Chapter 7 Tables for public health 2
7.1 데이터 준비
데이터 표를 만드는 실습은 6차 근로환경조사 자료를 통해 실습할 것입니다.. 자료는 안전보건공단, 근로환경조사 원시자료 사이트 (http://kosha.or.kr/kosha/data/primitiveData.do) 에서 신청할 수 있습니다..
rm(list=ls())
if(!require("tidyverse")) install.packages("tidyverse")
if(!require("htmlTable")) install.packages("htmlTable")
if(!require("haven")) install.packages("haven")
if(!require("broom")) install.packages("broom")
데이터를 불러오겠습니다. 안전보건공단 홈페이에서 자료를 다운 받는게 원칙입니다. 다만 실습을 빠르게 진행하기 위해서, dspubs.org 페이지에 있는 파일을 이용하겠습니다.
dspubs.org open_data
<- "https://dspubs.org/webapps/forum/open_data/kwcs6th.sav"
url download.file(url, "data/kwcs6th.sav")
<- read_sav("data/kwcs6th.sav") kwcs
7.2 분석 주제 선정
우선 수면 장애를 중심으로 연구를 하기로 했습니다. 이때 장시간 근무가 수면장애를 일으킬 수 있다는 가정을 했습니다. 기존 연구에서 유사한 내용이 있었기 때문입니다. 그 이유를 생각해보니, 오래 일하면 어떤 방식으로든 수면시간 자체가 줄어들 것으로 보였기 때문입니다. 우선 sleep disturbance, long working hours per week 이 정해졌습니다. 이후 연구방법론의 혼란변수 선정 방법이나, 연구자의 Domain knowledge에 따른 선정, 새로운 가설 개발 (originality) 위한 변수 선정등을 고려할 수 있습니다. 이러한 내용은 각각의 연구방법론 수업에서 학습하시기를 바랍니다.
여러 토론을 하다보니, 일을 마치고 집에 돌아온 후 해야할 일이 많은 경우 수면장애가 발생할 것 같은 느낌이 들었습니다. 이 것을 확인해 보고자 합니다.
즉, 장시간근로와 일과 삶의 균형에 따른 수면장애 관련성을 연구해 보고 싶습니다.
이제 data manipulation, long wide 변환을 통해 실습을 해보겠습니다.
7.2.1 근로환경조사와 recode (선택사항)
번외로 분석을 빠르게 진행하기 위해 recode
에 대한 복습을 해 보겠습니다. recode
는 아주 단순한 변경에 사용되는데요, 근로환경조사는 이미 변수를 1, 2, 3, 4, 5 의 순서를 Likert 척도로 사용하고 있습니다.
근로환경조사 Likert 척도
근로환경조사 | Likert 척도 |
---|---|
얼마나 자주 그렇습니까(freq)? | “4.Always”, “3.Often”, “2.Sometimes”, “1.Rarely”, “0.Never” |
얼마나 자주 그렇습니까(time)? | “5.All of the time”, “4.Most of the time”, “3.More than half of the time”, “2.less than half of the time”, “1.Some of the time”, “0.At no time” |
얼마나 적당 합니까? | “3.Very well”, “3.Well”, “2.Not very well”, “0.Not at all well” |
이것을 이용하면 매우 쉽게 정리할 수 있습니다.
- wwa4: 집안일 때문에 집중하기 어렵다가
- 1: 항상그렇다,
- 2: 대부분그렇다.
- 3: 가끔 그렇다
- 4: 별로 그렇지 않다.
- 5: 전혀 그렇지 않다 로 되어 있습니다.
recode
아래의 함수 결과를 살펴보면, 숫자의 경우 순서에 따라 문자를 어사인하는 것을 볼 수 있습니다. 데이터가 정형화되어 정리되어 있는 경우, 그리고 숫자인경우, case_when 이나 ifelse보다 더 쉬운 방법입니다.
= c(1, 1, 1, 3, 3, 3, 2, 2, 2, 4, 4, 4)
vars = recode(vars, `1`= "a", `2`= "b", `3`= "c", `4`= "d")
r1 r1
## [1] "a" "a" "a" "c" "c" "c" "b" "b" "b" "d" "d" "d"
= recode(vars, "a", "b", "c", "d")
r2 == r2 r1
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
문자일 때는 어떨까요? 문자는 순서를 특정화 해주지 않았으므로 어렵습니다. 근로환경조사는 대부분 문자로 저장되어 있습니다.
= as.character(vars)
vars_char = recode(vars_char, "a", "b", "c", "d")
r3 = recode(as.numeric(vars_char), "a", "b", "c", "d") r3_n
이를 as.numeric을 통해 숫자로 변형시켜준 후 시행하면 잘 작동합니다.
= as.character(vars)
vars_char = recode(as.numeric(vars_char), "a", "b", "c", "d") r3_n
이제 kwcs
에서 wwa1부터 wwa5까지를 가져와 역순으로 Likert 척도를 구해보겠습니다.
= kwcs %>% select(TSEX, contains("wwa"))
wwas %>% head() wwas
## # A tibble: 6 × 6
## TSEX wwa1 wwa2 wwa3 wwa4 wwa5
## <dbl+lbl> <dbl+lbl> <dbl+lbl> <dbl+lbl> <dbl+l> <dbl+l>
## 1 2 [여성] 4 [별로 그렇지 않다] 5 [전혀 그렇지 않다] 5 [전혀 … 5 [전… 5 [전…
## 2 2 [여성] 5 [전혀 그렇지 않다] 4 [별로 그렇지 않다] 5 [전혀 … 5 [전… 5 [전…
## 3 2 [여성] 4 [별로 그렇지 않다] 3 [가끔 그렇다] 3 [가끔 … 4 [별… 4 [별…
## 4 1 [남성] 4 [별로 그렇지 않다] 4 [별로 그렇지 않다] 4 [별로 … 5 [전… 5 [전…
## 5 1 [남성] 3 [가끔 그렇다] 4 [별로 그렇지 않다] 4 [별로 … 4 [별… 4 [별…
## 6 2 [여성] 4 [별로 그렇지 않다] 4 [별로 그렇지 않다] 4 [별로 … 4 [별… 4 [별…
Quizz1: wwa1 변수에서 1의 값을 갖는 것은 남녀 별로 각각 몇명일까요? (script 안에 count 를 이용해서 작성해 보세요)
%>%
wwas group_by(TSEX) %>%
[ script ]
이제 recode를 이용해 변환해 보겠습니다.
- wwa 관련 변수를
- 1: 항상그렇다 → “4.Always”
- 2: 대부분그렇다 → “3.Often”
- 3: 가끔 그렇다 → “2.Sometimes”
- 4: 별로 그렇지 않다 → “1.Rarely”
- 5: 전혀 그렇지 않다 →“0.Never”
로 변경해 보겠습니다.
첫번째는 case_when으로 두번째는 recode로 변경했습니다. 누가 더 쉬운가요?
= wwas %>%
test mutate(wwa1gp1 = case_when(
==1 ~ "4.Always",
wwa1 ==2 ~ "3.Often",
wwa1 ==3 ~ "2.Sometimes",
wwa1 ==4 ~ "1.Rarely",
wwa1 ==5 ~ "0.Never"
wwa1 %>%
)) mutate(wwa1gp2 = recode(as.numeric(wwa1),
"4.Always","3.Often","2.Sometimes", "1.Rarely","0.Never"
)) %>%
test mutate(diff = wwa1gp1 == wwa1gp2) %>%
pull(diff) %>% table(.)
## .
## TRUE
## 49268
코드가 길어지는 것은 누군가와 소통하는데 장벽이 될수 있습니다. 반복적인 것은 함수를 만들어 요약할 수 있습니다.
= function(x){
Likerts recode(as.numeric(x),
"4.Always","3.Often","2.Sometimes", "1.Rarely","0.Never"
)
}
%>%
wwas mutate(wwa1gp1 = recode(as.numeric(wwa1),
"4.Always","3.Often","2.Sometimes", "1.Rarely","0.Never"
%>%
)) mutate(wwa1gp2 = Likerts(wwa1)) %>%
mutate(diff = wwa1gp1 == wwa1gp2) %>%
pull(diff) %>% table(.)
## .
## TRUE
## 49268
7.2.2 근로환경조사 기본 변수 생성
data manipulation에서 실습한 내용을 통해 변수를 실습을 위한 변수를 생성해 보겠습니다.
# data manip function
= function(x){dplyr::recode(as.numeric(x),
Likert5f "4.Always","3.Often","2.Sometimes", "1.Rarely","0.Never" )}
# data step start ----------
= kwcs %>%
dat1 filter(AGE <70) %>%
filter(AGE >18) %>%
# sleep --------
filter(!is.na(sleep1)&!is.na(sleep2)&!is.na(sleep3)) %>%
filter(sleep1 %in% c(1:5),
%in% c(1:5),
sleep2 %in% c(1:5)) %>%
sleep3 mutate(sleep1in = 5-sleep1,
sleep2in = 5-sleep2,
sleep3in = 5-sleep3
%>%
) mutate(sleepgp = case_when(
+ sleep2in+ sleep3in >=6 ~ "1.sleep disturbance",
sleep1in TRUE ~ "0.non distrubance"
%>%
)) # work live balances -------------
filter(!is.na(wbalance), !is.na(wwa1), !is.na(wwa2), !is.na(wwa3), !is.na(wwa4), !is.na(wwa5)) %>%
filter(!is.na(wbalance)) %>%
mutate(wbalancegp = case_when(
%in% c(1, 2) ~ "0.balance",
wbalance TRUE ~ "1.non balance"
%>%
)) mutate(wwa1gp=Likert5f(wwa1), wwa2gp=Likert5f(wwa2), wwa3gp=Likert5f(wwa3),
wwa4gp=Likert5f(wwa4), wwa5gp=Likert5f(wwa5),
%>%
) # job and sex, agegp ----------
filter(!is.na(job1))%>%
filter(job1 %in% c(1, 2, 3)) %>%
mutate(sexgp = case_when(
==1 ~ "Men",
TSEX TRUE ~ "Women"
%>%
)) mutate(agegp = case_when(AGE <25 ~ "<25", AGE <30 ~ "<30", AGE <35 ~ "<35",
<40 ~ "<40", AGE <45 ~ "<45", AGE <50 ~ "<50",AGE <55 ~ "<55", AGE <60 ~ "<60",
AGE TRUE ~ "\u226560" # 나머지는 모두 >65 (\u2265는 크거나 같다는 symbol)
%>%
)) filter(!is.na(edu)) %>% filter(edu %in% c(1:7)) %>%
mutate(edugp = case_when(
%in% c(1:3) ~ "2.middle school or below",
edu %in% c(4 ) ~ "1.high school",
edu %in% c(5:7) ~ "0.university or more"
edu %>%
)) mutate(njob=case_when(
%in% c(2, 3) ~ "1.njob",
job1 TRUE ~ "0.one-job")) %>%
# pains back -----------
mutate(backpain= case_when(
==1 ~ "pain",
heal_prob1TRUE ~ "no-pain")) %>%
# emp_type,working hours, shiftwork, work life balance -------
filter(!is.na(emp_type)) %>%
filter(emp_type %in% c(1:4)) %>%
mutate(empgp = case_when(
==1 ~ "2.own-account worker",
emp_type ==2 ~ "1.employer/self-employer",
emp_type ==3 ~ "0.paid-worker",
emp_type ==4 ~ "3.unpaind family work"
emp_type %>%
)) filter(!is.na(wtime_week)) %>%
mutate(whgp=case_when(
< 35 ~ "<35",
wtime_week < 40 ~ "<40",
wtime_week < 52 ~ "<52",
wtime_week < 60 ~ "<60",
wtime_week TRUE ~ "\u226560",
%>%
)) filter(!is.na(wtime_length5)) %>%
filter(wtime_length5 %in% c(1, 2)) %>%
mutate(shiftWork = case_when(
==1 ~ "1.shift work",
wtime_length5 TRUE ~ "0.non shift work"
%>%
)) filter(!is.na(wtime_resilience)) %>%
mutate(shortReturn = case_when(
==1 ~ "1.short return",
wtime_resilience TRUE ~ "0.non short return"
%>%
)) filter(!is.na(satisfaction)) %>%
filter(satisfaction %in% c(1:4)) %>%
mutate(satisInv = 5-satisfaction) %>%
mutate(shiftShort=case_when(
== "1.shift work" & shortReturn == "1.short return" ~ "3.shift work with short return",
shiftWork == "1.shift work" & shortReturn != "1.short return" ~ "2.shift work",
shiftWork != "1.shift work" & shortReturn == "1.short return" ~ "1.day work with short return",
shiftWork != "1.shift work" & shortReturn != "1.short return" ~ "0.day work",
shiftWork ))
7.3 근로환경조사 Table 1 만들기
지금까지 작업을 통해 분석한 변수를 선정합니다. 이때 정리할 부분은 무엇으로 구분할지, 관심변수는 무엇인지 이중 명목변수와 연속변수는 무엇인지를 구분하는 것입니다.
## Variables selection
= c("sleepgp")
stratas = c(
catVars # interesting
#"wbalancegp",
"wwa1gp", "wwa2gp","wwa3gp","wwa4gp","wwa5gp",
# confounder
#"whgp",
"shortReturn",#"shiftWork" , #"njob",
# demograhpics
"sexgp", #"agegp",
"edugp", "empgp" #, "backpain"
)= c("AGE","satisfaction") conVars
7.3.1 변수 값 요약하기
아래 코드가 뜻하는 것은 무엇일까요? 하나하나 살펴보아야 합니다. Table을 만들때 long file 형태로 만든 것입니다.
= dat1 %>%
catTab select(stratas, all_of(catVars)) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values")%>%
group_by( variables, values) %>%
count(!!sym(stratas)) %>%
mutate(prob = n/sum(n),
smry= sprintf("%.0f (%.1f%%)", n, prob*100)
%>%
) select(-n, -prob) %>%
ungroup() %>%
pivot_wider(names_from = stratas, values_from =smry)
아래 코드가 뜻하는 것은 무엇일까요? 하나하나 살펴보아야 합니다. Table을 만들때 long file 형태로 만든 것입니다.
=
conTab %>%
dat1 select(stratas, all_of(conVars)) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values")%>%
group_by( !!sym(stratas), variables) %>%
summarise(avg = mean(values, na.rm =TRUE),
std = sd(values, na.rm =TRUE)
%>%
) mutate(smry = sprintf("%.1f\u00b1%.1f", avg, std)) %>%
select(stratas, variables, smry)%>%
ungroup() %>%
pivot_wider(names_from = stratas, values_from =smry) %>%
mutate(values ="")
명목변수 요약 표 catTab
과 연속편수 요약표 conTab
을 합쳐 보겠습니다. rbind는 종으로 합친다는 뜻입니다.
= rbind(catTab, conTab) tabDat
7.3.2 P value 구하기.
이제 P value를 구해보겠습니다. 명목변수는 카이검정, 연속변수는 T검정을 해보겠습니다.
Chisq-Test
Cross Table을 만든 다음, chisq.test() 명령을 통해 수행합니다.
= data.frame(A = c(1000, 2000),
tabB = c(100, 300))
tab
## A B
## 1 1000 100
## 2 2000 300
chisq.test(tab)
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tab
## X-squared = 10.821, df = 1, p-value = 0.001003
T.Test
두 연속변수로 구성된 Data를 만들고 t.test() 명령을 통해 수행합니다.
= data.frame(A=rnorm(100),
tab B=rnorm(100)+0.3)
t.test(tab)
##
## One Sample t-test
##
## data: tab
## t = 1.843, df = 199, p-value = 0.06682
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## -0.009154466 0.270814872
## sample estimates:
## mean of x
## 0.1308302
이것을 이용해서 카이검정과 T검정을 수행해보겠습니다.
가장 정확하면서 쉬운 방식은 반복하는 것입니다. 우리가 이미 변수 값을 long file을 통해 정리하는 것을 실습하였기 때문에, 이 방식도 long file을 이용하겠습니다.
이때 중요한 개념임 map
, nest
, tidy
가 나옵니다.
map, nest, tidy
각 백터 값에 대해서 함수를 실행한다.
1:5 %>%
map(function(x){x^2})
## [[1]]
## [1] 1
##
## [[2]]
## [1] 4
##
## [[3]]
## [1] 9
##
## [[4]]
## [1] 16
##
## [[5]]
## [1] 25
tibble(a=1:5, b=6:10) %>%
map(sum)
## $a
## [1] 15
##
## $b
## [1] 40
이번에는 좀 복잡한 것을 해보겠습니다 아래와 같이 두 집단에 대해서 size와 power를 각 20명에게 측정했다고 가정합시다. 그리고 size와 power를 동시에 측정하고 측정 순서대로 데이터를 정리한 것입니다. 이후 G1과 G2의 Size와 Power에 대해 T.test를 수행하겠습니다.
= tibble(
test Variables= rep(c("Size","Power"), each=20),
G1= c(rnorm(20), rnorm(20)),
G2= c(rnorm(20)-0.3, rnorm(20)+0.3),
)
일반적 방식은 아래와 같습니다. 이것을 반복하면 되는 것입니다.
%>% filter(Variables=="Size") %>%
test select(-Variables) %>%
t.test(.)
##
## One Sample t-test
##
## data: .
## t = -1.1466, df = 39, p-value = 0.2585
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## -0.4121175 0.1139225
## sample estimates:
## mean of x
## -0.1490975
t.test(test[test$Variables=="Size", ]$G1,
$Variables=="Size", ]$G2) test[test
##
## Welch Two Sample t-test
##
## data: test[test$Variables == "Size", ]$G1 and test[test$Variables == "Size", ]$G2
## t = 0.3964, df = 37.23, p-value = 0.6941
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.4284027 0.6368525
## sample estimates:
## mean of x mean of y
## -0.09698507 -0.20120997
이에 이것을 반복 수행하기 위해, data를 slice 하여 하나의 list로 만드는과정을 하겠습니다. nest의 과정입니다. 이후 각 데이터에 map을 이용해서 반복 수행을 하겠습니다. 그리고 그 값을 정리하여 unnest하는 과정이 필요합니다. 필요한 값인 p. value만 남겨 정리합니다.
= test %>%
test1 nest(dat = -Variables) %>%
mutate(fit=map(dat, ~t.test(.x)),
tidied=map(fit, tidy))
%>% unnest(tidied) %>%
test1 select(Variables, p.value)
## # A tibble: 2 × 2
## Variables p.value
## <chr> <dbl>
## 1 Size 0.259
## 2 Power 0.0989
지금까지 사용한 것을 가지고, 명목변수에서는 Chisq-Test, 연속변수에서 t.test 를 수행하여 정리하겠습니다.
명목변수, chisq.test
=
catPvalue %>%
dat1 select(stratas, catVars) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values")%>%
group_by(variables, values) %>%
count(!!sym(stratas)) %>%
pivot_wider(names_from = stratas, values_from =n) %>%
ungroup() %>%
select(-values) %>%
nest(dat = -variables) %>%
mutate(
fit = map(dat,
~chisq.test(.x)),
tidied = map(fit, tidy)
%>%
) unnest(tidied) %>%
select(variables, p.value) %>%
mutate(p.value = ifelse(p.value <0.001, "<0.001", sprintf("%.3f", p.value)))
연속변수, t.test
=dat1 %>%
conPvaluemutate(stratas = !!sym(stratas)) %>%
select(stratas, conVars) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values") %>%
nest(dat = -variables) %>%
mutate(
fit =map(dat, ~t.test(.$values ~ .$stratas)),
tidied=map(fit, tidy)
%>%
) unnest(tidied) %>%
select(variables, p.value) %>%
mutate(p.value = ifelse(p.value <0.001, "<0.001", sprintf("%.3f", p.value)))
P.valeu 합치기
= rbind(catPvalue, conPvalue) tabPvalue
표가 어떤 순서대로 표현될지에 대한 순서를 정합니다.
= tibble("variables"=c(catVars, conVars)) %>%
varOrder mutate(order = row_number())
varOrder
## # A tibble: 11 × 2
## variables order
## <chr> <int>
## 1 wwa1gp 1
## 2 wwa2gp 2
## 3 wwa3gp 3
## 4 wwa4gp 4
## 5 wwa5gp 5
## 6 shortReturn 6
## 7 sexgp 7
## 8 edugp 8
## 9 empgp 9
## 10 AGE 10
## 11 satisfaction 11
7.4 Table 1 정리하기
이제 변수값 요약과, p.value를 합치고, 순서에 맞게 정리하겠습니다.
= tabDat %>%
tab1 left_join(tabPvalue, by=c("variables")) %>%
left_join(varOrder, by = c("variables")) %>%
arrange(order, values) %>%
group_by(variables) %>%
mutate(ranks = row_number()) %>%
mutate(p.value = ifelse(ranks==min(ranks), p.value, "")) %>%
mutate(variables = ifelse(ranks==min(ranks), variables, "")) %>%
ungroup() %>%
select(-order, -ranks)%>%
mutate(values = str_replace(values, "[:digit:]\\.", ""))
이것을 htmlTable로 나타내면 다음과 같습니다.
%>% htmlTable() tab1
variables | values | 0.non distrubance | 1.sleep disturbance | p.value | |
---|---|---|---|---|---|
1 | wwa1gp | Never | 12222 (94.7%) | 684 (5.3%) | <0.001 |
2 | Rarely | 12316 (94.5%) | 714 (5.5%) | ||
3 | Sometimes | 9112 (90.3%) | 981 (9.7%) | ||
4 | Often | 3456 (82.8%) | 717 (17.2%) | ||
5 | Always | 634 (70.0%) | 272 (30.0%) | ||
6 | wwa2gp | Never | 12432 (95.4%) | 597 (4.6%) | <0.001 |
7 | Rarely | 13682 (94.1%) | 863 (5.9%) | ||
8 | Sometimes | 8882 (89.2%) | 1072 (10.8%) | ||
9 | Often | 2460 (79.4%) | 638 (20.6%) | ||
10 | Always | 284 (58.9%) | 198 (41.1%) | ||
11 | wwa3gp | Never | 13472 (95.2%) | 682 (4.8%) | <0.001 |
12 | Rarely | 13938 (93.1%) | 1040 (6.9%) | ||
13 | Sometimes | 7749 (89.9%) | 868 (10.1%) | ||
14 | Often | 2314 (79.5%) | 597 (20.5%) | ||
15 | Always | 267 (59.6%) | 181 (40.4%) | ||
16 | wwa4gp | Never | 18708 (94.1%) | 1169 (5.9%) | <0.001 |
17 | Rarely | 14799 (91.6%) | 1362 (8.4%) | ||
18 | Sometimes | 3348 (85.0%) | 592 (15.0%) | ||
19 | Often | 805 (80.7%) | 193 (19.3%) | ||
20 | Always | 80 (60.6%) | 52 (39.4%) | ||
21 | wwa5gp | Never | 19061 (93.9%) | 1245 (6.1%) | <0.001 |
22 | Rarely | 14770 (91.6%) | 1349 (8.4%) | ||
23 | Sometimes | 3180 (85.3%) | 550 (14.7%) | ||
24 | Often | 682 (79.8%) | 173 (20.2%) | ||
25 | Always | 47 (48.0%) | 51 (52.0%) | ||
26 | shortReturn | non short return | 36183 (92.5%) | 2927 (7.5%) | <0.001 |
27 | short return | 1557 (77.9%) | 441 (22.1%) | ||
28 | sexgp | Men | 17892 (93.1%) | 1327 (6.9%) | <0.001 |
29 | Women | 19848 (90.7%) | 2041 (9.3%) | ||
30 | edugp | university or more | 19597 (92.9%) | 1502 (7.1%) | <0.001 |
31 | high school | 14943 (91.9%) | 1318 (8.1%) | ||
32 | middle school or below | 3200 (85.4%) | 548 (14.6%) | ||
33 | empgp | paid-worker | 25786 (92.4%) | 2122 (7.6%) | <0.001 |
34 | employer/self-employer | 2539 (91.7%) | 229 (8.3%) | ||
35 | own-account worker | 8359 (90.5%) | 880 (9.5%) | ||
36 | unpaind family work | 1056 (88.5%) | 137 (11.5%) | ||
37 | AGE | 46.8±12.4 | 49.7±11.9 | <0.001 | |
38 | satisfaction | 2.1±0.5 | 2.4±0.6 | <0.001 |
7.4.1 htmlTable visulaization
테이블이 너무 길기 때문에, wwa2, wwa3, wwa4, wwa5, 는 제외하고 표를 만들겠습니다.
= tab1 %>% slice(-c(6:25))
tab2 %>%
tab2 `rownames<-`(NULL) %>%
htmlTable(rnames = FALSE)
variables | values | 0.non distrubance | 1.sleep disturbance | p.value |
---|---|---|---|---|
wwa1gp | Never | 12222 (94.7%) | 684 (5.3%) | <0.001 |
Rarely | 12316 (94.5%) | 714 (5.5%) | ||
Sometimes | 9112 (90.3%) | 981 (9.7%) | ||
Often | 3456 (82.8%) | 717 (17.2%) | ||
Always | 634 (70.0%) | 272 (30.0%) | ||
shortReturn | non short return | 36183 (92.5%) | 2927 (7.5%) | <0.001 |
short return | 1557 (77.9%) | 441 (22.1%) | ||
sexgp | Men | 17892 (93.1%) | 1327 (6.9%) | <0.001 |
Women | 19848 (90.7%) | 2041 (9.3%) | ||
edugp | university or more | 19597 (92.9%) | 1502 (7.1%) | <0.001 |
high school | 14943 (91.9%) | 1318 (8.1%) | ||
middle school or below | 3200 (85.4%) | 548 (14.6%) | ||
empgp | paid-worker | 25786 (92.4%) | 2122 (7.6%) | <0.001 |
employer/self-employer | 2539 (91.7%) | 229 (8.3%) | ||
own-account worker | 8359 (90.5%) | 880 (9.5%) | ||
unpaind family work | 1056 (88.5%) | 137 (11.5%) | ||
AGE | 46.8±12.4 | 49.7±11.9 | <0.001 | |
satisfaction | 2.1±0.5 | 2.4±0.6 | <0.001 |
변수 이름을 변경하요 보기 좋게 변환시키고, cgroup을 이용하여 colum 부분을 조정합니다. Caption과 Footer를 작성하여 마무리 합니다.
%>%
tab2 setNames(c("", "", "None", "Disturbance", "P value")) %>%
htmlTable(
cgroup = c("", "Sleep disturbance", ""),
n.cgroup = c(2, 2, 1),
tfoot = "P value calculated by Chisq-Test and T-Test",
rnames = FALSE,
caption = "Basic Characteristics according to Sleep disturbance"
)
Basic Characteristics according to Sleep disturbance | ||||||
Sleep disturbance | ||||||
---|---|---|---|---|---|---|
None | Disturbance | P value | ||||
wwa1gp | Never | 12222 (94.7%) | 684 (5.3%) | <0.001 | ||
Rarely | 12316 (94.5%) | 714 (5.5%) | ||||
Sometimes | 9112 (90.3%) | 981 (9.7%) | ||||
Often | 3456 (82.8%) | 717 (17.2%) | ||||
Always | 634 (70.0%) | 272 (30.0%) | ||||
shortReturn | non short return | 36183 (92.5%) | 2927 (7.5%) | <0.001 | ||
short return | 1557 (77.9%) | 441 (22.1%) | ||||
sexgp | Men | 17892 (93.1%) | 1327 (6.9%) | <0.001 | ||
Women | 19848 (90.7%) | 2041 (9.3%) | ||||
edugp | university or more | 19597 (92.9%) | 1502 (7.1%) | <0.001 | ||
high school | 14943 (91.9%) | 1318 (8.1%) | ||||
middle school or below | 3200 (85.4%) | 548 (14.6%) | ||||
empgp | paid-worker | 25786 (92.4%) | 2122 (7.6%) | <0.001 | ||
employer/self-employer | 2539 (91.7%) | 229 (8.3%) | ||||
own-account worker | 8359 (90.5%) | 880 (9.5%) | ||||
unpaind family work | 1056 (88.5%) | 137 (11.5%) | ||||
AGE | 46.8±12.4 | 49.7±11.9 | <0.001 | |||
satisfaction | 2.1±0.5 | 2.4±0.6 | <0.001 | |||
P value calculated by Chisq-Test and T-Test |
7.5 함수만들기
지금가지 했던 일련의 과정을 함수로 정리하겠습니다.
= function(dat1, stratas, catVars, conVars){
kwcsTabf = tibble("variables"=c(catVars, conVars)) %>%
varOrder mutate(order = row_number())
= dat1 %>%
catTab select(stratas, all_of(catVars)) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values")%>%
group_by( variables, values) %>%
count(!!sym(stratas)) %>%
mutate(prob = n/sum(n),
smry= sprintf("%.0f (%.1f%%)", n, prob*100)
%>%
) select(-n, -prob) %>%
ungroup() %>%
pivot_wider(names_from = stratas, values_from =smry)
=
conTab %>%
dat1 select(stratas, all_of(conVars)) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values")%>%
group_by( !!sym(stratas), variables) %>%
summarise(avg = mean(values, na.rm =TRUE),
std = sd(values, na.rm =TRUE)
%>%
) mutate(smry = sprintf("%.1f\u00b1%.1f", avg, std)) %>%
select(stratas, variables, smry)%>%
ungroup() %>%
pivot_wider(names_from = stratas, values_from =smry) %>%
mutate(values ="")
= rbind(catTab, conTab)
tabDat
=
catPvalue %>%
dat1 select(stratas, catVars) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values")%>%
group_by(variables, values) %>%
count(!!sym(stratas)) %>%
pivot_wider(names_from = stratas, values_from =n) %>%
ungroup() %>%
select(-values) %>%
nest(dat = -variables) %>%
mutate(
fit = map(dat,
~chisq.test(.x)),
tidied = map(fit, tidy)
%>%
) unnest(tidied) %>%
select(variables, p.value) %>%
mutate(p.value = ifelse(p.value <0.001, "<0.001", sprintf("%.3f", p.value)))
=dat1 %>%
conPvaluemutate(stratas = !!sym(stratas)) %>%
select(stratas, conVars) %>%
pivot_longer(-c(stratas), names_to = "variables", values_to ="values") %>%
nest(dat = -variables) %>%
mutate(
fit =map(dat, ~t.test(.$values ~ .$stratas)),
tidied=map(fit, tidy)
%>%
) unnest(tidied) %>%
select(variables, p.value) %>%
mutate(p.value = ifelse(p.value <0.001, "<0.001", sprintf("%.3f", p.value)))
= rbind(catPvalue, conPvalue)
tabPvalue
= tabDat %>%
tab1 left_join(tabPvalue, by=c("variables")) %>%
left_join(varOrder, by = c("variables")) %>%
arrange(order, values) %>%
group_by(variables) %>%
mutate(ranks = row_number()) %>%
mutate(p.value = ifelse(ranks==min(ranks), p.value, "")) %>%
mutate(variables = ifelse(ranks==min(ranks), variables, "")) %>%
ungroup() %>%
select(-order, -ranks)%>%
mutate(values = str_replace(values, "[:digit:]\\.", ""))
return(tab1)
}
층화변수, 명목변수, 연속변수를 구성하여 함수를 실행해 보겠습니다.
## Variables selection
= c("sleepgp")
stratas = c(
catVars # interesting
#"wbalancegp",
"wwa1gp", "wwa2gp","wwa3gp","wwa4gp","wwa5gp",
# confounder
#"whgp",
"shortReturn","shiftWork" , "njob",
# demograhpics
"sexgp", "agegp",
"edugp", "empgp" #, backpain"
)= c("AGE","satisfaction")
conVars
= kwcsTabf(dat1=dat1, stratas = stratas, catVars = catVars, conVars = conVars)
tab1 %>%
tab1 setNames(c("", "", "None", "Disturbance", "P value")) %>%
htmlTable(
cgroup = c("", "Sleep disturbance", ""),
n.cgroup = c(2, 2, 1),
tfoot = "P value calculated by Chisq-Test and T-Test",
rnames = FALSE,
caption = "Basic Characteristics according to Sleep disturbance"
)
Basic Characteristics according to Sleep disturbance | ||||||
Sleep disturbance | ||||||
---|---|---|---|---|---|---|
None | Disturbance | P value | ||||
wwa1gp | Never | 12222 (94.7%) | 684 (5.3%) | <0.001 | ||
Rarely | 12316 (94.5%) | 714 (5.5%) | ||||
Sometimes | 9112 (90.3%) | 981 (9.7%) | ||||
Often | 3456 (82.8%) | 717 (17.2%) | ||||
Always | 634 (70.0%) | 272 (30.0%) | ||||
wwa2gp | Never | 12432 (95.4%) | 597 (4.6%) | <0.001 | ||
Rarely | 13682 (94.1%) | 863 (5.9%) | ||||
Sometimes | 8882 (89.2%) | 1072 (10.8%) | ||||
Often | 2460 (79.4%) | 638 (20.6%) | ||||
Always | 284 (58.9%) | 198 (41.1%) | ||||
wwa3gp | Never | 13472 (95.2%) | 682 (4.8%) | <0.001 | ||
Rarely | 13938 (93.1%) | 1040 (6.9%) | ||||
Sometimes | 7749 (89.9%) | 868 (10.1%) | ||||
Often | 2314 (79.5%) | 597 (20.5%) | ||||
Always | 267 (59.6%) | 181 (40.4%) | ||||
wwa4gp | Never | 18708 (94.1%) | 1169 (5.9%) | <0.001 | ||
Rarely | 14799 (91.6%) | 1362 (8.4%) | ||||
Sometimes | 3348 (85.0%) | 592 (15.0%) | ||||
Often | 805 (80.7%) | 193 (19.3%) | ||||
Always | 80 (60.6%) | 52 (39.4%) | ||||
wwa5gp | Never | 19061 (93.9%) | 1245 (6.1%) | <0.001 | ||
Rarely | 14770 (91.6%) | 1349 (8.4%) | ||||
Sometimes | 3180 (85.3%) | 550 (14.7%) | ||||
Often | 682 (79.8%) | 173 (20.2%) | ||||
Always | 47 (48.0%) | 51 (52.0%) | ||||
shortReturn | non short return | 36183 (92.5%) | 2927 (7.5%) | <0.001 | ||
short return | 1557 (77.9%) | 441 (22.1%) | ||||
shiftWork | non shift work | 35056 (91.9%) | 3073 (8.1%) | <0.001 | ||
shift work | 2684 (90.1%) | 295 (9.9%) | ||||
njob | one-job | 37471 (91.9%) | 3317 (8.1%) | <0.001 | ||
njob | 269 (84.1%) | 51 (15.9%) | ||||
sexgp | Men | 17892 (93.1%) | 1327 (6.9%) | <0.001 | ||
Women | 19848 (90.7%) | 2041 (9.3%) | ||||
agegp | <25 | 1359 (96.6%) | 48 (3.4%) | <0.001 | ||
<30 | 2697 (94.3%) | 163 (5.7%) | ||||
<35 | 3308 (93.6%) | 225 (6.4%) | ||||
<40 | 3995 (92.3%) | 334 (7.7%) | ||||
<45 | 4414 (92.2%) | 372 (7.8%) | ||||
<50 | 4934 (92.7%) | 388 (7.3%) | ||||
<55 | 5300 (91.9%) | 465 (8.1%) | ||||
<60 | 5099 (90.0%) | 566 (10.0%) | ||||
≥60 | 6634 (89.2%) | 807 (10.8%) | ||||
edugp | university or more | 19597 (92.9%) | 1502 (7.1%) | <0.001 | ||
high school | 14943 (91.9%) | 1318 (8.1%) | ||||
middle school or below | 3200 (85.4%) | 548 (14.6%) | ||||
empgp | paid-worker | 25786 (92.4%) | 2122 (7.6%) | <0.001 | ||
employer/self-employer | 2539 (91.7%) | 229 (8.3%) | ||||
own-account worker | 8359 (90.5%) | 880 (9.5%) | ||||
unpaind family work | 1056 (88.5%) | 137 (11.5%) | ||||
AGE | 46.8±12.4 | 49.7±11.9 | <0.001 | |||
satisfaction | 2.1±0.5 | 2.4±0.6 | <0.001 | |||
P value calculated by Chisq-Test and T-Test |
7.6 Quiz
7.6.1 Quiz1
Quiz.1 아래의 표와 같은 결과가 나타나도록, sleepgp 대신 요통을 중심으로 표를 만들어 보세요. R script를 업로드 해주세요.
Basic Characteristics according to Back Pain | ||||||
Back PAin | ||||||
---|---|---|---|---|---|---|
No | Pain | P value | ||||
wwa4gp | Never | 14966 (75.3%) | 4911 (24.7%) | <0.001 | ||
Rarely | 11430 (70.7%) | 4731 (29.3%) | ||||
Sometimes | 2435 (61.8%) | 1505 (38.2%) | ||||
Often | 565 (56.6%) | 433 (43.4%) | ||||
Always | 70 (53.0%) | 62 (47.0%) | ||||
wwa5gp | Never | 15248 (75.1%) | 5058 (24.9%) | <0.001 | ||
Rarely | 11436 (70.9%) | 4683 (29.1%) | ||||
Sometimes | 2246 (60.2%) | 1484 (39.8%) | ||||
Often | 489 (57.2%) | 366 (42.8%) | ||||
Always | 47 (48.0%) | 51 (52.0%) | ||||
shortReturn | non short return | 28389 (72.6%) | 10721 (27.4%) | <0.001 | ||
short return | 1077 (53.9%) | 921 (46.1%) | ||||
shiftWork | non shift work | 27320 (71.7%) | 10809 (28.3%) | 0.668 | ||
shift work | 2146 (72.0%) | 833 (28.0%) | ||||
sexgp | Men | 14348 (74.7%) | 4871 (25.3%) | <0.001 | ||
Women | 15118 (69.1%) | 6771 (30.9%) | ||||
edugp | university or more | 16953 (80.3%) | 4146 (19.7%) | <0.001 | ||
high school | 10835 (66.6%) | 5426 (33.4%) | ||||
middle school or below | 1678 (44.8%) | 2070 (55.2%) | ||||
empgp | paid-worker | 20969 (75.1%) | 6939 (24.9%) | <0.001 | ||
employer/self-employer | 1961 (70.8%) | 807 (29.2%) | ||||
own-account worker | 5927 (64.2%) | 3312 (35.8%) | ||||
unpaind family work | 609 (51.0%) | 584 (49.0%) | ||||
AGE | 45.2±12.3 | 51.5±11.4 | <0.001 | |||
P value calculated by Chisq-Test and T-Test |