🐨

【ChatGPT】Rによるサンプルデータセットの作成

2023/03/22に公開

はじめに

ChatGPTというすごいおもちゃがあるらしいので遊んでます。直近だと適当なデータセットをつくるためのRプログラムをChatGPTに作ってもらえないか試してみたので、その備忘録としてまとめました。ChatGPT4.0を使いました。

ラフな用途としてはブログやプレゼン資料に適当なデータを使いたいときなどがありそうです。もう少しきちんと業務で利用するということであれば、解析用のプログラムを回すためのダミーデータ作成にも応用できるかもしれません。

本題

とりあえず以下のようなプロンプトを投げてみました。

以下が出力されたプログラムです。プログラム以外の出力は省略しています。

出力されたプログラム
# Load required libraries
library(dplyr)

# Set the seed for reproducibility
set.seed(42)

# Number of patients
n <- 100

# Generate a sample dataset
diabetic_patients <- data.frame(
  id = 1:n,
  sex = factor(sample(c("M", "F"), n, replace = TRUE, prob = c(0.5, 0.5))),
  age = sample(40:80, n, replace = TRUE),
  treatment = sample(c(0, 1), n, replace = TRUE, prob = c(0.5, 0.5)),
  dBP = rnorm(n, mean = 80, sd = 10),
  sBP = rnorm(n, mean = 130, sd = 10),
  pre_hba1c = rnorm(n, mean = 8, sd = 1)
) %>%
  mutate(
    # Apply the 2% reduction in hba1c for treated patients
    post_hba1c = ifelse(treatment == 1, pre_hba1c * 0.98, pre_hba1c)
  )

# Print the first few rows of the dataset
head(diabetic_patients)

post_hba1cにばらつきがない状態なのが気になったので修正してもらえるように次のプロンプトを投げました。

出力されたプログラム
# Load required libraries
library(dplyr)

# Set the seed for reproducibility
set.seed(42)

# Number of patients
n <- 100

# Generate a sample dataset
diabetic_patients <- data.frame(
  id = 1:n,
  sex = factor(sample(c("M", "F"), n, replace = TRUE, prob = c(0.5, 0.5))),
  age = sample(40:80, n, replace = TRUE),
  treatment = sample(c(0, 1), n, replace = TRUE, prob = c(0.5, 0.5)),
  dBP = rnorm(n, mean = 80, sd = 10),
  sBP = rnorm(n, mean = 130, sd = 10),
  pre_hba1c = rnorm(n, mean = 8, sd = 1)
) %>%
  mutate(
    # Apply the 2% reduction in hba1c for treated patients, including an error term
    post_hba1c = ifelse(treatment == 1, pre_hba1c * 0.98 + rnorm(n, mean = 0, sd = 0.5), pre_hba1c)
  )

# Print the first few rows of the dataset
head(diabetic_patients)

"post_hba1c = ifelse(treatment == 1, pre_hba1c * 0.98 + rnorm(n, mean = 0, sd = 0.5), pre_hba1c)" をみれば誤差が足されているのが確認できました。

次にぼくの英語が問題あったと思うのですが、治療効果の2%が想定とは異なっていました。シンプルに引き算して欲しかったのでそのことを伝えました。

出力されたプログラム
# Load required libraries
library(dplyr)

# Set the seed for reproducibility
set.seed(42)

# Number of patients
n <- 100

# Generate a sample dataset
diabetic_patients <- data.frame(
  id = 1:n,
  sex = factor(sample(c("M", "F"), n, replace = TRUE, prob = c(0.5, 0.5))),
  age = sample(40:80, n, replace = TRUE),
  treatment = sample(c(0, 1), n, replace = TRUE, prob = c(0.5, 0.5)),
  dBP = rnorm(n, mean = 80, sd = 10),
  sBP = rnorm(n, mean = 130, sd = 10),
  pre_hba1c = rnorm(n, mean = 8, sd = 1)
) %>%
  mutate(
    # Apply the treatment effect by subtracting 2 from hba1c for treated patients, including an error term
    post_hba1c = ifelse(treatment == 1, pre_hba1c - 2 + rnorm(n, mean = 0, sd = 0.5), pre_hba1c)
  )

# Print the first few rows of the dataset
head(diabetic_patients)

ここで、treatmentが0のときにpost_hba1cがpre_hba1cと等しいことに気が付いたので修正してもらいました。

出力されたプログラム
# Load required libraries
library(dplyr)

# Set the seed for reproducibility
set.seed(42)

# Number of patients
n <- 100

# Generate a sample dataset
diabetic_patients <- data.frame(
  id = 1:n,
  sex = factor(sample(c("M", "F"), n, replace = TRUE, prob = c(0.5, 0.5))),
  age = sample(40:80, n, replace = TRUE),
  treatment = sample(c(0, 1), n, replace = TRUE, prob = c(0.5, 0.5)),
  dBP = rnorm(n, mean = 80, sd = 10),
  sBP = rnorm(n, mean = 130, sd = 10),
  pre_hba1c = rnorm(n, mean = 8, sd = 1)
) %>%
  mutate(
    # Apply the treatment effect and include the error term for all patients
    post_hba1c = ifelse(treatment == 1, pre_hba1c - 2, pre_hba1c) + rnorm(n, mean = 0, sd = 0.5)
  )

# Print the first few rows of the dataset
head(diabetic_patients)

Rで走らせてみました。それっぽいデータセットはできています。血圧やHbA1cの値も標準正規分布から乱数を発生させるのではなくて、変数名を考慮した値になっているように見えます。

> head(diabetic_patients)
  id sex age treatment      dBP       sBP pre_hba1c post_hba1c
1  1   M  57         1 94.40523 123.30736  7.768392   5.331510
2  2   M  63         0 74.40528 137.04518  8.093684   7.678444
3  3   F  57         0 75.37981 121.72372  6.704910   6.637252
4  4   M  44         1 67.43199  96.50676  7.151215   5.247620
5  5   M  79         0 98.31371 133.42541  5.709944   5.257317
6  6   M  79         1 67.65394 110.68902  9.282856   7.124959

他の変数名だとどんな風になるのか気になったので以下のプロンプトを投げました。

出力されたプログラム
# Load required libraries
library(dplyr)

# Set the random seed for reproducibility
set.seed(42)

# Number of samples
n <- 100

# Generate sample data
id <- seq(1, n)
age <- sample(18:65, n, replace = TRUE)
sex <- rep("male", n)
height <- rnorm(n, mean = 175, sd = 6)
weight <- rnorm(n, mean = 75, sd = 12)
BMI <- weight / (height/100)^2
TG <- rnorm(n, mean = 100, sd = 25)
LDL <- rnorm(n, mean = 130, sd = 20)
HDL <- rnorm(n, mean = 60, sd = 10)
UA <- rnorm(n, mean = 5, sd = 1)
WBC <- rnorm(n, mean = 7000, sd = 1000)
RBC <- rnorm(n, mean = 5.5, sd = 0.4)
Hb <- rnorm(n, mean = 15, sd = 1)

# Create data frame
healthy_males <- data.frame(id, age, sex, height, weight, BMI, TG, LDL, HDL, UA, WBC, RBC, Hb)

# Print the first few rows of the dataset
head(healthy_males)

BMIは身長と体重から算出してくれるようです。ただ変数名によっては微妙なものもあるようです。

次に生存時間解析につかうようなデータセットを作るために以下のプロンプトを投げました。生存時間というよりはイベント有無のデータセットにおまけ程度の一様分布に従う連続変数を1つ加えたものです。

出力されたプログラム
library(dplyr)

set.seed(123) # Set a seed for reproducibility
n_patients <- 200

# Create a data frame with the required columns
dataset <- data.frame(
  id = 1:n_patients,
  sex = sample(c("M", "F"), n_patients, replace = TRUE),
  age = sample(20:80, n_patients, replace = TRUE),
  stage = sample(1:4, n_patients, replace = TRUE),
  treatment = sample(0:1, n_patients, replace = TRUE)
)

# Calculate the response based on stage and treatment
dataset <- dataset %>%
  mutate(response = case_when(
    treatment == 0 & stage == 1 ~ rbinom(1, 1, 0.8),
    treatment == 1 & stage == 1 ~ rbinom(1, 1, 0.7),
    treatment == 0 & stage == 2 ~ rbinom(1, 1, 0.6),
    treatment == 1 & stage == 2 ~ rbinom(1, 1, 0.5),
    treatment == 0 & (stage == 3 | stage == 4) ~ rbinom(1, 1, 0.4),
    treatment == 1 & (stage == 3 | stage == 4) ~ rbinom(1, 1, 0.3)
  ))

# Generate right-censored survival times with a uniform distribution
max_survival_time <- 5
dataset <- dataset %>%
  mutate(survival_time = runif(n_patients, 0, max_survival_time),
         censored = as.numeric(survival_time < max_survival_time))

Rで回して確認すると、こんな感じのデータセットが得られました。

  id sex age stage treatment response survival_time censored
1  1   M  49     3         1        0     4.4206680        1
2  2   M  49     2         0        0     3.8764861        1
3  3   M  71     1         1        0     0.6960182        1
4  4   F  44     4         0        1     1.4750464        1
5  5   M  35     2         0        0     0.6304139        1
6  6   F  43     2         1        0     2.9495081        1

最後に経時データを作成するようなプロンプトを投げました。

出力されたプログラム
# 1. Load the required libraries
library(dplyr)
library(MASS)

# 2. Define the parameters of the dataset
n <- 100       # number of participants per group
correlation <- 0.20  # correlation between time points
mean_diff <- 5  # difference in outcomes between treatment and control group
time_points <- 6  # number of time points (0 to 5)

# 3. Create a function to generate correlated outcomes
generate_outcomes <- function(n, mean_diff, correlation, time_points) {
  # Create the covariance matrix
  cov_matrix <- matrix(correlation, nrow = time_points, ncol = time_points) + diag(1 - correlation, time_points)
  
  # Generate correlated outcomes for the treatment and control groups
  outcomes_treatment <- mvrnorm(n, mu = rep(0, time_points), Sigma = cov_matrix)
  outcomes_control <- mvrnorm(n, mu = rep(mean_diff, time_points), Sigma = cov_matrix)
  
  return(list(treatment = outcomes_treatment, control = outcomes_control))
}

# 4. Create the dataset with the specified variables
set.seed(42)  # for reproducibility

# Generate demographic and treatment variables
id <- 1:(2 * n)
age <- round(runif(2 * n, min = 18, max = 80))
sex <- factor(sample(c("Male", "Female"), 2 * n, replace = TRUE))
treatment <- c(rep(0, n), rep(1, n))

# Generate correlated outcomes
outcomes <- generate_outcomes(n, mean_diff, correlation, time_points)

# Combine demographic, treatment, and outcome variables into a dataset
dataset <- data.frame(
  id = id,
  age = age,
  sex = sex,
  treatment = treatment,
  outcome_v0 = c(outcomes$control[, 1], outcomes$treatment[, 1]),
  outcome_v1 = c(outcomes$control[, 2], outcomes$treatment[, 2]),
  outcome_v2 = c(outcomes$control[, 3], outcomes$treatment[, 3]),
  outcome_v3 = c(outcomes$control[, 4], outcomes$treatment[, 4]),
  outcome_v4 = c(outcomes$control[, 5], outcomes$treatment[, 5]),
  outcome_v5 = c(outcomes$control[, 6], outcomes$treatment[, 6])
)

# View the dataset
head(dataset)

Rで確認してみます。

  id age    sex treatment outcome_v0 outcome_v1 outcome_v2 outcome_v3 outcome_v4 outcome_v5
1  1  75 Female         0   3.634322   4.047843   3.897044   3.983116   6.644344   5.407231
2  2  76 Female         0   4.043801   4.965315   4.807050   3.877034   5.243098   4.551941
3  3  36   Male         0   5.764075   4.354416   4.880022   4.112225   5.459096   4.677139
4  4  69 Female         0   5.531849   4.948421   5.346693   4.908342   5.344275   4.618980
5  5  58   Male         0   5.677514   4.746786   6.265931   6.018956   4.591125   7.430575
6  6  50   Male         0   5.089544   6.078941   6.303781   5.840876   4.934528   2.822520

outcome_v0は背景因子として両群で差がついてほしくなかったのですが恐らくこれだと差がついているので修正は必要そうです。

途中のcov_matrixはこんな感じになっていました。

まとめ

しっかりと内容を確認していませんが、パッとみた感じはたたき台としては使えそうな感触でした。英語もかなり雑に投げてますが(間違いが多いと思います)、それでもある程度は意図をくみ取ってくれました。これからも時間をみつけてChatGPTで遊んでみようと思います。


サポートして頂けるとモチベーションに繋がりますのでぜひ宜しくお願いします。データ解析や臨床研究でのご相談があれば、お気軽にTwiiterもしくはメールにてご連絡下さい。

作成者:Masahiro Kondo
作成日:2023/3/22
連絡先:m.kondo1042(at)gmail.com

Discussion