이번에는 실제적인 데이타를 예로 들어 data cleaning, subsetting 및 변환을 살펴보고자 한다. L모 교수는 최근 환자들의 자료를 엑셀화일로 정리한 후 CSV화일로 변환하였다. 환자의 이름과 신상명세는 제외하였다. 전체 데이타에서 50명의 환자 데이타만 제시한 것이다.

data=read.csv("ECMO.csv")
head(data)
##   Sex Age Year Holiday Insertion.time ECMO.duration Death Height Weight
## 1   1  49 2009       1              1             8     1     NA     NA
## 2   1  77 2009       1             NA            24     0     NA     NA
## 3   0  67 2009       1              1            15     0     NA     NA
## 4   0  56 2010       1              0             5     0   1.65     68
## 5   0  67 2010       1              0             2     0   1.70     65
## 6   0  76 2010       1              0             5     0   1.64     68
##     BMI   Diagnosis Smoking CAD CVA PAD DM HBP Indication Mode CA OHCA
## 1    NA Myocarditis       2   1   1   1  1   1          0    0  1   NA
## 2    NA         ACS       2   1   1   1  1   0          0    0  1   NA
## 3    NA         ACS       0   0   1   1  0   0          0    0  0    1
## 4 29.76         ACS       2   1   1   1  1   0          0    0  0    1
## 5 26.37        ARDS       2   1   1   1  1   1          1    1  0    1
## 6 30.21         ACS       1   1   1   1  0   0          0    0  1   NA
##   CPR.duration CA.ECMO.Time EKG Weaning Vent Intu.day HD ICU.stay CRRT
## 1           NA           NA   2       0    0        8 30       11    0
## 2           NA           NA   2       0    0       27 31       31    1
## 3           37           37   0       0    0       17 17       17    0
## 4           25           25   0       1    0        5  5        5    0
## 5          210          210   2       1    0        3 43        3    1
## 6           NA           NA   2       0    0        9 12       12    1
##   CRRT.duration CAG PCI GCS Bleeding Tamponade Pulmo AKI Liver.failure MOF
## 1             8   1   1  15        1         1     1   0             1   1
## 2            NA   0   1   5        1         1     1   0             1   1
## 3            13   0   0   3        1         1     0   0             1   0
## 4             3   0   0   3        1         1     1   0             1   1
## 5            NA   1   1  12        1         1     1   0             1   1
## 6            NA   0   0   4        1         1     1   1             1   0
##   Sepsis Stroke Leg.ischemia   WBC  Hct PLT Sodium   K Lactate   PH HCO3
## 1      1      1            1 16400 43.0 248  143.2 3.9    10.6 7.20 15.9
## 2      1      1            1  5230 30.1 154  143.2 3.1      NA 7.49 22.0
## 3      1      1            1  9670 36.0  54  144.8 3.4      NA 7.26  9.0
## 4      1      1            1 10930 44.8 293  136.8 3.2      NA 7.18 13.4
## 5      0      1            1 17950 22.3  70  143.2 6.5      NA 7.14 10.9
## 6      1      1            1  6790 40.1 173  140.5 3.8      NA 7.29 14.9
##    BUN  Cr Glucose Albumin Total..bilirubin   CRP D.dimer CK.MB Troponin
## 1 20.1 2.3     184     4.7              1.1  0.31    2.29 30.95    3.050
## 2  6.3 1.0     153     4.2              0.5  1.03      NA  3.97    0.298
## 3 20.1 1.5      56     2.2              0.5 13.34    1.03  8.91    0.088
## 4 15.9 1.5     200     2.5              0.6  0.07      NA  3.47    0.020
## 5 48.9 2.5     488     1.6              0.3 23.27    0.44  4.38    0.036
## 6 15.8 0.9     178     3.8              1.1  0.29      NA 17.70    0.674
##   PRC FFP  PC Cryo Survive
## 1   5   3  72    0       1
## 2  22   7  61    0       0
## 3  35   9 136    0       0
## 4  10   0  18    0       0
## 5  24   5  42    0       0
## 6  14   0  46    0       0
str(data)
## 'data.frame':    50 obs. of  65 variables:
##  $ Sex             : int  1 1 0 0 0 0 0 0 1 0 ...
##  $ Age             : int  49 77 67 56 67 76 48 67 69 38 ...
##  $ Year            : int  2009 2009 2009 2010 2010 2010 2010 2010 2010 2010 ...
##  $ Holiday         : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ Insertion.time  : int  1 NA 1 0 0 0 1 1 0 0 ...
##  $ ECMO.duration   : int  8 24 15 5 2 5 1 14 6 1 ...
##  $ Death           : int  1 0 0 0 0 0 0 0 0 0 ...
##  $ Height          : num  NA NA NA 1.65 1.7 1.64 1.75 1.65 1.55 1.7 ...
##  $ Weight          : num  NA NA NA 68 65 68 75 60 53 65 ...
##  $ BMI             : num  NA NA NA 29.8 26.4 ...
##  $ Diagnosis       : Factor w/ 8 levels "ACS","ARDS","LA myxoma",..: 4 1 1 1 2 1 1 1 1 4 ...
##  $ Smoking         : int  2 2 0 2 2 1 0 2 2 0 ...
##  $ CAD             : int  1 1 0 1 1 1 1 1 1 1 ...
##  $ CVA             : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ PAD             : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ DM              : int  1 1 0 1 1 0 0 0 0 1 ...
##  $ HBP             : int  1 0 0 0 1 0 0 0 1 1 ...
##  $ Indication      : int  0 0 0 0 1 0 0 0 0 0 ...
##  $ Mode            : int  0 0 0 0 1 0 0 0 0 0 ...
##  $ CA              : int  1 1 0 0 0 1 0 1 0 1 ...
##  $ OHCA            : int  NA NA 1 1 1 NA 0 NA 0 NA ...
##  $ CPR.duration    : int  NA NA 37 25 210 NA 30 NA 20 NA ...
##  $ CA.ECMO.Time    : int  NA NA 37 25 210 NA 240 NA 540 NA ...
##  $ EKG             : int  2 2 0 0 2 2 2 2 2 2 ...
##  $ Weaning         : int  0 0 0 1 1 0 1 0 1 1 ...
##  $ Vent            : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Intu.day        : Factor w/ 23 levels "1","10","11",..: 21 12 7 18 13 22 9 8 19 1 ...
##  $ HD              : int  30 31 17 5 43 12 2 20 6 2 ...
##  $ ICU.stay        : int  11 31 17 5 3 12 2 20 6 2 ...
##  $ CRRT            : int  0 1 0 0 1 1 1 1 0 1 ...
##  $ CRRT.duration   : int  8 NA 13 3 NA NA NA NA 5 NA ...
##  $ CAG             : int  1 0 0 0 1 0 1 0 1 0 ...
##  $ PCI             : int  1 1 0 0 1 0 1 1 1 1 ...
##  $ GCS             : int  15 5 3 3 12 4 3 3 3 8 ...
##  $ Bleeding        : int  1 1 1 1 1 1 0 0 1 0 ...
##  $ Tamponade       : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ Pulmo           : int  1 1 0 1 1 1 1 1 1 1 ...
##  $ AKI             : int  0 0 0 0 0 1 1 1 0 1 ...
##  $ Liver.failure   : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ MOF             : int  1 1 0 1 1 0 0 0 1 1 ...
##  $ Sepsis          : int  1 1 1 1 0 1 1 0 1 1 ...
##  $ Stroke          : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ Leg.ischemia    : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ WBC             : int  16400 5230 9670 10930 17950 6790 20410 18230 21500 11910 ...
##  $ Hct             : num  43 30.1 36 44.8 22.3 40.1 32.1 26.5 30.2 41.7 ...
##  $ PLT             : int  248 154 54 293 70 173 203 334 235 308 ...
##  $ Sodium          : num  143 143 145 137 143 ...
##  $ K               : num  3.9 3.1 3.4 3.2 6.5 3.8 6.6 4.1 5.4 4.4 ...
##  $ Lactate         : num  10.6 NA NA NA NA NA 15.5 15.6 7.6 3.8 ...
##  $ PH              : num  7.2 7.49 7.26 7.18 7.14 ...
##  $ HCO3            : num  15.9 22 9 13.4 10.9 14.9 10.5 12.7 12.5 16.7 ...
##  $ BUN             : num  20.1 6.3 20.1 15.9 48.9 15.8 54.6 49.9 40.7 32 ...
##  $ Cr              : num  2.3 1 1.5 1.5 2.5 0.9 3.9 1.3 1.6 1.7 ...
##  $ Glucose         : int  184 153 56 200 488 178 256 230 208 131 ...
##  $ Albumin         : num  4.7 4.2 2.2 2.5 1.6 3.8 3 4.1 2.8 3.9 ...
##  $ Total..bilirubin: num  1.1 0.5 0.5 0.6 0.3 1.1 0.6 0.5 1 0.6 ...
##  $ CRP             : num  0.31 1.03 13.34 0.07 23.27 ...
##  $ D.dimer         : num  2.29 NA 1.03 NA 0.44 NA NA 4.97 NA NA ...
##  $ CK.MB           : num  30.95 3.97 8.91 3.47 4.38 ...
##  $ Troponin        : num  3.05 0.298 0.088 0.02 0.036 ...
##  $ PRC             : int  5 22 35 10 24 14 9 42 10 3 ...
##  $ FFP             : int  3 7 9 0 5 0 0 5 0 0 ...
##  $ PC              : int  72 61 136 18 42 46 0 170 54 0 ...
##  $ Cryo            : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Survive         : int  1 0 0 0 0 0 0 0 0 0 ...

데이타는 모두 50 예이며 65개의 변수로 되어있다. 이중 대부분의 변수는 Yes,No의 범주형 변수이나 Excel에서 0,1로 입력하여 모두 numeric 변수로 되어 있다. 성별은 여자는 1, 남자는 0으로 코딩했고 착오로 인해 Yes/No로 표현해야 하는 여러 변수는 No를 1로, Yes를 0으로 입력했다고 한다. 먼저 남여의 경우는 다음과 같이 바꾸었다.

data$Sex=ifelse(data$Sex==1,"Female","Male")

Yes/No가 아닌 데이타는 다음과 같이 ifelse를 이용해 바꾸었다.

data$Insertion.time=ifelse(data$Insertion.time==1,"Emergency","Elective")
data$Death=ifelse(data$Death==1,"Survivor","Non-survivor")
data$Indication=ifelse(data$Indication==1,"Respiratory","Cardiology")
data$Mode=ifelse(data$Mode==1,"VV","VA")
data$OHCA=ifelse(data$OHCA==1,"IHCA","OHCA")
data$EKG=ifelse(data$EKG==0,"Asystole",
                 ifelse(data$EKG==1,"PEA","ETC"))
data$Weaning=ifelse(data$Weaning==1,"Fail","Success")
head(data)
##      Sex Age Year Holiday Insertion.time ECMO.duration        Death Height
## 1 Female  49 2009       1      Emergency             8     Survivor     NA
## 2 Female  77 2009       1           <NA>            24 Non-survivor     NA
## 3   Male  67 2009       1      Emergency            15 Non-survivor     NA
## 4   Male  56 2010       1       Elective             5 Non-survivor   1.65
## 5   Male  67 2010       1       Elective             2 Non-survivor   1.70
## 6   Male  76 2010       1       Elective             5 Non-survivor   1.64
##   Weight   BMI   Diagnosis Smoking CAD CVA PAD DM HBP  Indication Mode CA
## 1     NA    NA Myocarditis       2   1   1   1  1   1  Cardiology   VA  1
## 2     NA    NA         ACS       2   1   1   1  1   0  Cardiology   VA  1
## 3     NA    NA         ACS       0   0   1   1  0   0  Cardiology   VA  0
## 4     68 29.76         ACS       2   1   1   1  1   0  Cardiology   VA  0
## 5     65 26.37        ARDS       2   1   1   1  1   1 Respiratory   VV  0
## 6     68 30.21         ACS       1   1   1   1  0   0  Cardiology   VA  1
##   OHCA CPR.duration CA.ECMO.Time      EKG Weaning Vent Intu.day HD
## 1 <NA>           NA           NA      ETC Success    0        8 30
## 2 <NA>           NA           NA      ETC Success    0       27 31
## 3 IHCA           37           37 Asystole Success    0       17 17
## 4 IHCA           25           25 Asystole    Fail    0        5  5
## 5 IHCA          210          210      ETC    Fail    0        3 43
## 6 <NA>           NA           NA      ETC Success    0        9 12
##   ICU.stay CRRT CRRT.duration CAG PCI GCS Bleeding Tamponade Pulmo AKI
## 1       11    0             8   1   1  15        1         1     1   0
## 2       31    1            NA   0   1   5        1         1     1   0
## 3       17    0            13   0   0   3        1         1     0   0
## 4        5    0             3   0   0   3        1         1     1   0
## 5        3    1            NA   1   1  12        1         1     1   0
## 6       12    1            NA   0   0   4        1         1     1   1
##   Liver.failure MOF Sepsis Stroke Leg.ischemia   WBC  Hct PLT Sodium   K
## 1             1   1      1      1            1 16400 43.0 248  143.2 3.9
## 2             1   1      1      1            1  5230 30.1 154  143.2 3.1
## 3             1   0      1      1            1  9670 36.0  54  144.8 3.4
## 4             1   1      1      1            1 10930 44.8 293  136.8 3.2
## 5             1   1      0      1            1 17950 22.3  70  143.2 6.5
## 6             1   0      1      1            1  6790 40.1 173  140.5 3.8
##   Lactate   PH HCO3  BUN  Cr Glucose Albumin Total..bilirubin   CRP
## 1    10.6 7.20 15.9 20.1 2.3     184     4.7              1.1  0.31
## 2      NA 7.49 22.0  6.3 1.0     153     4.2              0.5  1.03
## 3      NA 7.26  9.0 20.1 1.5      56     2.2              0.5 13.34
## 4      NA 7.18 13.4 15.9 1.5     200     2.5              0.6  0.07
## 5      NA 7.14 10.9 48.9 2.5     488     1.6              0.3 23.27
## 6      NA 7.29 14.9 15.8 0.9     178     3.8              1.1  0.29
##   D.dimer CK.MB Troponin PRC FFP  PC Cryo Survive
## 1    2.29 30.95    3.050   5   3  72    0       1
## 2      NA  3.97    0.298  22   7  61    0       0
## 3    1.03  8.91    0.088  35   9 136    0       0
## 4      NA  3.47    0.020  10   0  18    0       0
## 5    0.44  4.38    0.036  24   5  42    0       0
## 6      NA 17.70    0.674  14   0  46    0       0

남은 데이타 중 0/1로 코딩한 열은 모두 Yes/No로 바꾸고 싶다. 일일이 코딩하는 방법은 다음과 같다. 바꿔야 하는 자료중 일부를 제시하면 다음과 같다.

data$Holiday=ifelse(data$Holiday==1,"No","Yes")
data$Smoking=ifelse(data$Smoking==1,"No","Yes")
data$CAD=ifelse(data$CAD==1,"No","Yes")
data$CVA=ifelse(data$CVA==1,"No","Yes")
data$PAD=ifelse(data$PAD==1,"No","Yes")
data$DM=ifelse(data$DM==1,"No","Yes")
data$HBP=ifelse(data$HBP==1,"No","Yes")
data$CA=ifelse(data$CA==1,"No","Yes")
data$Vent=ifelse(data$Vent==1,"No","Yes")
data$CRRT=ifelse(data$CRRT==1,"No","Yes")
data$CAG=ifelse(data$CAG==1,"No","Yes")
data$PCI=ifelse(data$PCI==1,"No","Yes")
data$Bleeding=ifelse(data$Bleeding==1,"No","Yes")
data$Tamponade=ifelse(data$Tamponade==1,"No","Yes")
data$Pulmo=ifelse(data$Pulmo==1,"No","Yes")
data$AKI=ifelse(data$AKI==1,"No","Yes")
data$Liver.failure=ifelse(data$Liver.failure==1,"No","Yes")
data$MOF=ifelse(data$MOF==1,"No","Yes")
data$Sepsis=ifelse(data$Sepsis==1,"No","Yes")
data$Stroke=ifelse(data$Stroke==1,"No","Yes")
data$Leg.ischemia=ifelse(data$Leg.ischemia==1,"No","Yes")

물론 이정도는 감당할 수 있다. 21개 정도의 열은 일일이 위와 같이 코드를 복사해서 고칠 수 있다. 하지만 자료가 65개의 변수가 아닌 650개의 변수라면? 거의 불가능하거나 포기하고 싶어질 것이다.

여기서 잠깐 생각해보자. 지금 우리가 하고 싶은 일은 무엇인가? 첫째, 전체 자료 중에 0,1로 코딩되어있는 열을 찾아낸다. 둘째, 그 열에 포함되어 있는 자료에서 0을 “Yes”로 1을 “No”로 바꿔준다.

이 두가지 단계를 거치면 우리가 원하는 자료를 얻을수 있을 것이다. 이번 문제는 1단계 2단계 모두 functional programming이다. funtional이란 함수들 중에서 인수로써 함수를 받아들이고 output으로 벡터를 반환하는 함수로서 apply 류의 함수가 대표적이다. 힌트는 1,2단계 모두 lapply를 사용하여 한줄로 코딩할수 있다는 것이다.

통계분석에 드는 시간과 노력은 data cleaning에 70%, 분석에 30%라는 얘기가 있다. 이 문제를 해결할 수 있으면 데이타 cleaning에 자신을 가질수 있을 것이다.

모두들 응모하세요. 정답을 맞추신 보든 분께는 제가 출간예정인 책을 한권씩 선물로 드립니다. 제가 올린 글 중 Functional programming 부분을 잘 읽고 이해한다면 쉽게 풀수 있을 겁니다. 정답은 한가지가 아니라 여러가지가 있을수 있읍니다. 실제 코딩을 해보고 다른 사람의 코드와 비교해보는 것이 실력 향상의 지름길입니다.