이 프로젝트에서는 연속형 변수에 대한 그룹별 요약 통계(Summary Statistics)를 생성하고, 이를 인구통계 요약표 형식에 맞춰 전치하는 방법을 배웁니다.
목표
- ADSL SAS (xpt) 데이터셋 읽기
- 유효성 분석 대상군(Efficacy Population) 서브셋 추출
- 그룹화 변수별 요약 통계 산출
- 표 작성을 위한 데이터 전치(Transpose)
이 문서 사용법
지침에 따라 코드 청크를 수정하고 실행하며 출력을 확인해 보세요.
미니 프로젝트 시작
- 먼저 필요한 패키지인
tidyverse와 rio를 로드합니다.
Warning: package 'ggplot2' was built under R version 4.4.3
Warning: package 'tibble' was built under R version 4.4.3
Warning: package 'purrr' was built under R version 4.4.2
Warning: package 'lubridate' was built under R version 4.4.2
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.2 ✔ tibble 3.3.0
✔ lubridate 1.9.4 ✔ tidyr 1.3.1
✔ purrr 1.0.4
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
- 데이터를 읽어오고 유효성 분석 대상군을 필터링합니다. 성별 레이블도 함께 재코딩합니다.
adsl <- import(file = "https://github.com/phuse-org/phuse-scripts/raw/master/data/adam/cdisc/adsl.xpt")
adsl_eff <- adsl %>%
filter( EFFFL == "Y" ) %>%
mutate(SEX = recode(SEX, "M" = "Male", "F" = "Female"))
- 치료군 및 성별별 연령(AGE) 평균 산출.
summarize() 함수를 사용하여 요약 통계를 계산합니다. 이는 SAS의 PROC MEANS와 유사합니다.
질문: 3개의 치료군과 2개의 성별이 있을 때, TRT01AN, TRT01A, SEX로 그룹화하면 결과 데이터는 몇 행이 될까요?
adsl_eff %>%
group_by( TRT01AN, TRT01A, SEX ) %>%
summarize(mean = mean(AGE), .groups = 'drop')
# A tibble: 6 × 4
TRT01AN TRT01A SEX mean
<dbl> <chr> <chr> <dbl>
1 0 Placebo Female 76.1
2 0 Placebo Male 73.4
3 54 Xanomeline Low Dose Female 76.4
4 54 Xanomeline Low Dose Male 75.6
5 81 Xanomeline High Dose Female 74.3
6 81 Xanomeline High Dose Male 73.6
평균값의 소수점 자릿수를 정리하고 문자형으로 변환해 보겠습니다.
adsl_eff %>%
group_by( TRT01A, TRT01AN, SEX ) %>%
summarize(mean = mean(AGE) %>%
round(digits = 1) %>%
format(nsmall = 1),
.groups = 'drop')
# A tibble: 6 × 4
TRT01A TRT01AN SEX mean
<chr> <dbl> <chr> <chr>
1 Placebo 0 Female 76.1
2 Placebo 0 Male 73.4
3 Xanomeline High Dose 81 Female 74.3
4 Xanomeline High Dose 81 Male 73.6
5 Xanomeline Low Dose 54 Female 76.4
6 Xanomeline Low Dose 54 Male 75.6
- 다양한 요약 통계 산출.
표준편차(sd), 중앙값(median), 최솟값(min), 최대값(max), 빈도(n)를 함께 계산합니다.
age_stat <- adsl_eff %>%
group_by(TRT01AN, TRT01A, SEX) %>%
summarize(mean = mean(AGE) %>% round(digits = 1) %>% format(nsmall = 1),
sd = sd(AGE) %>% round(digits = 1) %>% format(nsmall = 1),
med = median(AGE) %>% format(nsmall = 0),
min = min(AGE) %>% format(nsmall = 0),
max = max(AGE) %>% format(nsmall = 0),
n = n(),
.groups = 'drop')
head(age_stat)
# A tibble: 6 × 9
TRT01AN TRT01A SEX mean sd med min max n
<dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <int>
1 0 Placebo Female 76.1 8.5 77.5 59 88 46
2 0 Placebo Male 73.4 8.1 74 52 85 33
3 54 Xanomeline Low Dose Female 76.4 7.6 78 56 87 47
4 54 Xanomeline Low Dose Male 75.6 8.7 77.5 51 88 34
5 81 Xanomeline High Dose Female 74.3 7.5 76 56 88 35
6 81 Xanomeline High Dose Male 73.6 8.3 75 56 86 39
- 범위(Range) 형식 만들기.
min과 max를 결합하여 “(min, max)” 형태의 문자열을 만듭니다.
age_stat2 <- age_stat %>%
mutate(range_minmax = paste0("(", min, ", ", max, ")"))
head(age_stat2)
# A tibble: 6 × 10
TRT01AN TRT01A SEX mean sd med min max n range_minmax
<dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <int> <chr>
1 0 Placebo Fema… 76.1 8.5 77.5 59 88 46 (59, 88)
2 0 Placebo Male 73.4 8.1 74 52 85 33 (52, 85)
3 54 Xanomeline Low… Fema… 76.4 7.6 78 56 87 47 (56, 87)
4 54 Xanomeline Low… Male 75.6 8.7 77.5 51 88 34 (51, 88)
5 81 Xanomeline Hig… Fema… 74.3 7.5 76 56 88 35 (56, 88)
6 81 Xanomeline Hig… Male 73.6 8.3 75 56 86 39 (56, 86)
- 데이터 전치 - Long Format으로 변환.
각 통계량이 열로 나열된 현재 구조를, 통계량 이름(category)과 값(values)이 행으로 나열되는 긴 형식(Long Format)으로 바꿉니다. pivot_longer()를 사용합니다.
SAS 사용자를 위한 팁: select()는 SAS의 KEEP 문과 유사합니다.
desc_stat_long <- age_stat2 %>%
select(TRT01A, SEX, n, mean, med, sd, range_minmax) %>%
mutate(across(where(is.numeric), as.character)) %>%
pivot_longer(-c(TRT01A, SEX), names_to = "category", values_to = "values")
head(desc_stat_long)
# A tibble: 6 × 4
TRT01A SEX category values
<chr> <chr> <chr> <chr>
1 Placebo Female n 46
2 Placebo Female mean 76.1
3 Placebo Female med 77.5
4 Placebo Female sd 8.5
5 Placebo Female range_minmax (59, 88)
6 Placebo Male n 33
- 데이터 전치 - Wide Format으로 변환.
표 형식에 맞춰 치료군과 성별을 열로 배치합니다. pivot_wider()를 사용합니다.
desc_stat_long %>%
pivot_wider(names_from = c(TRT01A, SEX), values_from = values)
# A tibble: 5 × 7
category Placebo_Female Placebo_Male `Xanomeline Low Dose_Female`
<chr> <chr> <chr> <chr>
1 n 46 33 47
2 mean 76.1 73.4 76.4
3 med 77.5 74 78
4 sd 8.5 8.1 7.6
5 range_minmax (59, 88) (52, 85) (56, 87)
# ℹ 3 more variables: `Xanomeline Low Dose_Male` <chr>,
# `Xanomeline High Dose_Female` <chr>, `Xanomeline High Dose_Male` <chr>
- 최종 레이블 정리.
category의 변수명을 실제 표에 표시될 이름으로 변경합니다. case_when()을 활용합니다.
agestat_cat <- desc_stat_long %>%
pivot_wider(names_from = c(TRT01A, SEX), values_from = values) %>%
mutate(category = case_when(category == "n" ~ "N",
category == "med" ~ "Median",
category == "mean" ~ "Mean",
category == "sd" ~ "Std Dev",
category == "range_minmax" ~ "Range (min, max)"))
agestat_cat
# A tibble: 5 × 7
category Placebo_Female Placebo_Male `Xanomeline Low Dose_Female`
<chr> <chr> <chr> <chr>
1 N 46 33 47
2 Mean 76.1 73.4 76.4
3 Median 77.5 74 78
4 Std Dev 8.5 8.1 7.6
5 Range (min, max) (59, 88) (52, 85) (56, 87)
# ℹ 3 more variables: `Xanomeline Low Dose_Male` <chr>,
# `Xanomeline High Dose_Female` <chr>, `Xanomeline High Dose_Male` <chr>
챌린지 1: 체중(Weight) 및 신장(Height) 분석
위 과정을 반복하여 다른 연속형 변수에 대한 요약표를 만들어 보세요.
보너스 팁: 함수(Function) 작성
동일한 작업을 반복해야 한다면 함수를 작성하는 것이 좋습니다.
varSummary <- function(.data, variable) {
.data %>%
group_by(TRT01AN, TRT01A, SEX) %>%
summarize(
mean = mean({{variable}}) %>% round(digits = 1) %>% format(nsmall = 1),
sd = sd({{variable}}) %>% round(digits = 1) %>% format(nsmall = 1),
med = median({{variable}}) %>% format(nsmall = 0),
min = min({{variable}}) %>% format(nsmall = 0),
max = max({{variable}}) %>% format(nsmall = 0),
n = n(),
.groups = 'drop'
)
}
adsl_eff %>%
varSummary(AGE)
# A tibble: 6 × 9
TRT01AN TRT01A SEX mean sd med min max n
<dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <int>
1 0 Placebo Female 76.1 8.5 77.5 59 88 46
2 0 Placebo Male 73.4 8.1 74 52 85 33
3 54 Xanomeline Low Dose Female 76.4 7.6 78 56 87 47
4 54 Xanomeline Low Dose Male 75.6 8.7 77.5 51 88 34
5 81 Xanomeline High Dose Female 74.3 7.5 76 56 88 35
6 81 Xanomeline High Dose Male 73.6 8.3 75 56 86 39
참고: 함수 내부에서 데이터셋의 변수를 참조할 때는 { } (Embrace 연산자)를 사용해야 R이 해당 변수를 인식할 수 있습니다.