dplyr는 R에서 데이터를 다루기 위해 필수적으로 익혀야 할 패키지입니다. 데이터를 구성하는 row와 colum 들을 자유롭게 접근하기 위한 다양한 함수들이 있습니다. 우선, R에서 데이터를 구성하는 타입은 기본적으로 data.frame입니다. matrix 형태로도 데이터를 다룰 수 있지만, dplyr를 적용하기 위해서는 data.frame 형태여야 합니다. data.frmae은 row와 column으로 구성 되어 있고, 각 column의 타입은 달라도 상관 없습니다.
1. data
먼저, 필요한 패키지를 불러오고, 사용할 데이터를 탐색합니다.
사용할 데이터는 MLDataR 패키지의 heartdisease입니다. MLDataR은 머신러닝용 데이터를 모아놓은 패키지입니다. 패키지 로드 후, dplyr의 glimpse() 함수를 적용하여 데이터의 row와 column 및 속성들을 대략적으로 파악합니다. 해당예제에서는 heartdisease데이터에서 10개의 행만 추출해서 사용해보도록 하겠습니다.
# 패키지 로드
library(dplyr)
library(MLDataR)
MLDataR::heartdisease
sample = heartdisease[c(726,732:740),]
glimpse(sample)
Show in New Window
Rows: 10
Columns: 10
$ Age <dbl> 55, 46, 56, 66, 56, 49, 54, 57, 65, 54
$ Sex <chr> "F", "M", "F", "F", "M", "M", "M", "M", "~
$ RestingBP <dbl> 180, 120, 200, 150, 130, 120, 122, 152, 1~
$ Cholesterol <dbl> 327, 249, 288, 226, 283, 188, 286, 274, 3~
$ FastingBS <dbl> 0, 0, 1, 0, 1, 0, 0, 0, 0, 0
$ RestingECG <chr> "ST", "LVH", "LVH", "Normal", "LVH", "Nor~
$ MaxHR <dbl> 117, 144, 133, 114, 103, 139, 116, 88, 15~
$ Angina <chr> "Y", "N", "Y", "N", "Y", "N", "Y", "Y", "~
$ HeartPeakReading <dbl> 3.4, 0.8, 4.0, 2.6, 1.6, 2.0, 3.2, 1.2, 0~
$ HeartDisease <dbl> 1, 1, 1, 0, 1, 1, 1, 1, 0, 0
2. pipe 연산자
데이터를 다루기에 앞서 pipe연산자에 대한 언급이 필요합니다. 파이프 연산자(pipe operator)는 "magrittr"이라는 패키지에 포함된 함수이지만, dplyr 로드시 magrittr에서 파이프 연산자를 불러오게 되어 magrittr를 로드 하지 않아도 사용 할 수 있습니다. pipe 연산자란 data.frame과 함수, 함수와 함수를 연결해주는 역할을 하며, "%>%"로 표시합니다. dplyr의 filter함수를 시작으로 pipe 연산자에 대한 내용도 알아보겠습니다.
3. select
select는 column을 선택하는 함수 입니다. 많은 상황에서 column의 이름을 알고 특정 column을 추출 하게 되지만, 상황에 따라 특정단어로 시작하거나, 끝나거나, 포함된 column을 추출해야 하는 경우도 있습니다. colnames()함수로 sample의 column 이름을 확인해보겠습니다.
colnames(sample)
[1] "Age" "Sex" "RestingBP"
[4] "Cholesterol" "FastingBS" "RestingECG"
[7] "MaxHR" "Angina" "HeartPeakReading"
[10] "HeartDisease"
"Age", "Sex", "RestingBP"를 추출해보겠습니다.
sample %>% select(Age, Sex, RestingBP)
# A tibble: 10 x 3
Age Sex RestingBP
<dbl> <chr> <dbl>
1 55 F 180
2 46 M 120
3 56 F 200
4 66 F 150
5 56 M 130
6 49 M 120
7 54 M 122
8 57 M 152
9 65 F 160
10 54 M 125
다음, column이름 중 특정단어로 시작하는 column을 추출 할 수 있습니다. "A"로 시작하는 column을 추출해보겠습니다.
sample %>% select(starts_with("A"))
# A tibble: 10 x 2
Age Angina
<dbl> <chr>
1 55 Y
2 46 N
3 56 Y
4 66 N
5 56 Y
6 49 N
7 54 Y
8 57 Y
9 65 N
10 54 N
또, column이름 중 특정단어로 끝나는 column을 추출 할 수 있습니다.
sample %>% select(ends_with("g"))
# A tibble: 10 x 2
RestingECG HeartPeakReading
<chr> <dbl>
1 ST 3.4
2 LVH 0.8
3 LVH 4
4 Normal 2.6
5 LVH 1.6
6 Normal 2
7 LVH 3.2
8 Normal 1.2
9 LVH 0.8
10 LVH 0.5
contains()함수를 사용하면 특정단어가 포함된 coulmn을 추출 할 수도 있습니다. 아래 예제는, "l"을 포함하는 column을 추출하는 코드 입니다.
sample %>% select(contains("l"))
# A tibble: 10 x 1
Cholesterol
<dbl>
1 327
2 249
3 288
4 226
5 283
6 188
7 286
8 274
9 360
10 273
matches()함수도 contains()함수와 마찬가지로 특정단어를 포함한 열을 추출할 수 있습니다. matches()함수와 contains()함수의 차이는, matches()함수는 복수의 조건을 입력 할 수 있습니다.
sample %>% select(matches("l")) # "l"이 포함된 column
# A tibble: 10 x 1
Cholesterol
<dbl>
1 327
2 249
3 288
4 226
5 283
6 188
7 286
8 274
9 360
10 273
sample %>% select(matches("l|p")) # "l" 또는 "p"가 포함된 column
# A tibble: 10 x 3
RestingBP Cholesterol HeartPeakReading
<dbl> <dbl> <dbl>
1 180 327 3.4
2 120 249 0.8
3 200 288 4
4 150 226 2.6
5 130 283 1.6
6 120 188 2
7 122 286 3.2
8 152 274 1.2
9 160 360 0.8
10 125 273 0.5
4. filter
filter는 column 조건에 맞는 row를 추출하는 함수입니다. heatrdisease에서 추출한 sample 데이터는 10개의 row와 10개의 column으로 되어 있습니다. 10개의 column중 RestingECG의 데이터값을 살펴보겠습니다. unique()함수는 column이 가진 값들 중 중복을 제외한 고유한 값을 보여줍니다.
unique(sample$RestingECG)
[1] "ST" "LVH" "Normal"
"Normal", "ST", "LVH"로 되어 있는 것을 확인 할 수 있습니다. 이 중, "LVH"값만 추출해보겠습니다.
# 1. pipe operator
sample %>% filter(RestingECG == "LVH")
# A tibble: 6 x 10
Age Sex RestingBP Cholesterol FastingBS RestingECG MaxHR
<dbl> <chr> <dbl> <dbl> <dbl> <chr> <dbl>
1 46 M 120 249 0 LVH 144
2 56 F 200 288 1 LVH 133
3 56 M 130 283 1 LVH 103
4 54 M 122 286 0 LVH 116
5 65 F 160 360 0 LVH 151
6 54 M 125 273 0 LVH 152
# i 3 more variables: Angina <chr>, HeartPeakReading <dbl>,
# HeartDisease <dbl>
# 2. basic
filter(sample, RestingECG == "LVH")
# A tibble: 6 x 10
Age Sex RestingBP Cholesterol FastingBS RestingECG MaxHR
<dbl> <chr> <dbl> <dbl> <dbl> <chr> <dbl>
1 46 M 120 249 0 LVH 144
2 56 F 200 288 1 LVH 133
3 56 M 130 283 1 LVH 103
4 54 M 122 286 0 LVH 116
5 65 F 160 360 0 LVH 151
6 54 M 125 273 0 LVH 152
# i 3 more variables: Angina <chr>, HeartPeakReading <dbl>,
# HeartDisease <dbl>
filter()를 사용하면 RestingECG 컬럼에서 "LVH"값을 가지는 row를 모두 추출 할 수 있습니다. 1번 방법은 파이프연산자를 사용한 코드 입니다. 파이프 연산자는 "앞 %>% 뒤"로 볼 때, 앞에 뒤의 명령어를 적용하라는 의미입니다. 파이프연산자를 사용하면 R에서 좀 더 깔끔하고 간결한 쉬운 코드를 작성 할 수 있습니다. 2번 방법은 파이프 연산자를 사용하지 않은 코드 입니다. filter() 함수안에 data.frame과 조건식을 입력하면 되는데, 함수를 여러개 사용하고, 조건식이 많아 질 수록 코드 해석이 어려울 수 있습니다.
summary()함수를 사용하면 column들의 데이터의 분포를 대략적으로 파악 할 수 있습니다. summary()를 통해 알 수 있는 값은 최소값(Min), 1st Qu(1사분위수), Median(중위수), Mean(평균값), 3rd Qu(3사분위수), Max(최대값)입니다.
summary(sample)
Age Sex RestingBP Cholesterol FastingBS RestingECG MaxHR Angina HeartPeakReading HeartDisease
Min. :46.00 Length:10 Min. :120.0 Min. :188.0 Min. :0.0 Length:10 Min. : 88.0 Length:10 Min. :0.50 Min. :0.00
1st Qu.:54.00 Class :character 1st Qu.:122.8 1st Qu.:255.0 1st Qu.:0.0 Class :character 1st Qu.:114.5 Class :character 1st Qu.:0.90 1st Qu.:0.25
Median :55.50 Mode :character Median :140.0 Median :278.5 Median :0.0 Mode :character Median :125.0 Mode :character Median :1.80 Median :1.00
Mean :55.80 Mean :145.9 Mean :275.4 Mean :0.2 Mean :125.7 Mean :2.01 Mean :0.70
3rd Qu.:56.75 3rd Qu.:158.0 3rd Qu.:287.5 3rd Qu.:0.0 3rd Qu.:142.8 3rd Qu.:3.05 3rd Qu.:1.00
Max. :66.00 Max. :200.0 Max. :360.0 Max. :1.0 Max. :152.0 Max. :4.00 Max. :1.00
Cholesterol의 최소값(Min)은 188, 최대값(Max)은 360인것을 알 수 있습니다. 그럼, RestingECG는 "LVH"이고, Cholesterol은 200 이상인 row를 추출해보겠습니다. filter() 안에 RestingECG와 Cholesterol의 조건을 넣어주면 됩니다.
sample %>% filter(RestingECG == "LVH", Cholesterol > 200)
# A tibble: 6 x 10
Age Sex RestingBP Cholesterol FastingBS RestingECG MaxHR Angina HeartPeakReading HeartDisease
<dbl> <chr> <dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl> <dbl>
1 46 M 120 249 0 LVH 144 N 0.8 1
2 56 F 200 288 1 LVH 133 Y 4 1
3 56 M 130 283 1 LVH 103 Y 1.6 1
4 54 M 122 286 0 LVH 116 Y 3.2 1
5 65 F 160 360 0 LVH 151 N 0.8 0
6 54 M 125 273 0 LVH 152 N 0.5 0
만약, RestingECG의 "LVH"와 "Normal" 두 개 이상의 값과 일치하는 row를 찾기 위해서는 "%in%"를 사용하면 됩니다. unique()함수로 확인 했을 때 "LVH", "Normal"값만 들어 있는 것을 알 수 있습니다.
result = sample %>% filter(RestingECG %in% c("LVH", "Normal"))
unique(result$RestingECG)
[1] "LVH" "Normal"
5. mutate
mutate() 함수는 새로운 column을 활용해 새로운 변수를 만들어 기존의 data.frame에 추가해주는 함수 입니다. mean_ch라는 column이름으로 Cholestrol의 평균을 계산해 data.frame에 추가해보겠습니다.
sample %>% mutate(mean_ch = mean(Cholesterol))
# A tibble: 10 x 11
Age Sex RestingBP Cholesterol FastingBS RestingECG MaxHR Angina HeartPeakReading HeartDisease mean_Ch
<dbl> <chr> <dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl> <dbl> <dbl>
1 55 F 180 327 0 ST 117 Y 3.4 1 275.
2 46 M 120 249 0 LVH 144 N 0.8 1 275.
3 56 F 200 288 1 LVH 133 Y 4 1 275.
4 66 F 150 226 0 Normal 114 N 2.6 0 275.
5 56 M 130 283 1 LVH 103 Y 1.6 1 275.
6 49 M 120 188 0 Normal 139 N 2 1 275.
7 54 M 122 286 0 LVH 116 Y 3.2 1 275.
8 57 M 152 274 0 Normal 88 Y 1.2 1 275.
9 65 F 160 360 0 LVH 151 N 0.8 0 275.
10 54 M 125 273 0 LVH 152 N 0.5 0 275.
다음, "Age"와 "Cholesterol"를 더해서 "age_ch" column을 만들어 보겠습니다.
sample %>% mutate(age_ch = Age + Cholesterol) %>% select(Age, Cholesterol, age_ch)
# A tibble: 10 x 3
Age Cholesterol age_ch
<dbl> <dbl> <dbl>
1 55 327 382
2 46 249 295
3 56 288 344
4 66 226 292
5 56 283 339
6 49 188 237
7 54 286 340
8 57 274 331
9 65 360 425
10 54 273 327
mutate()는 ifelse와 함께 많이 사용 됩니다. 특정조건을 만족 할 때 값을 변경해주는 함수 입니다.
"Angina" column에서 N 이면 0, Y이며 1로 값을 변경하고 그 값을 "Angina_n"으로 만들어 보겠습니다.
sample %>% mutate(Angina_n = ifelse(Angina == "N", 0 , 1)) %>% select(Angina, Angina_n)
# A tibble: 10 x 2
Angina Angina_n
<chr> <dbl>
1 Y 1
2 N 0
3 Y 1
4 N 0
5 Y 1
6 N 0
7 Y 1
8 Y 1
9 N 0
10 N 0
5. summarise
summarise()함수는 column들의 기본적인 계산을 할 수 있게 해주는 함수 입니다. summarise()함수로는 주로 평균, 표준편차, 합계, column간의 연산 등의 계산을 할 때 주로 사용 합니다. 그럼 예시로, mean_age라는 column이름으로 Age의 평균을 계산해보겠습니다.
sample %>% summarise(mean_age = mean(Age))
# A tibble: 1 x 1
mean_age
<dbl>
1 55.8
mutate()함수를 사용해서도 계산 할 수 있습니다. 하지만, 두 함수의 차이점은 mutate()는 계산한 결과를 기존의 data.frame에 붙여서 보여주고, summarise()는 계산결과만 단일값으로 보여줍니다.
다음, Age와 Cholesterol을 더해보겠습니다.
sample %>% summarise(sum_age_ch = Age + Cholesterol)
# A tibble: 10 x 1
sum_age_ch
<dbl>
1 382
2 295
3 344
4 292
5 339
6 237
7 340
8 331
9 425
10 327
Warning message:
Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
i Please use `reframe()` instead.
i When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
dplyr 버전 1.1.0이상에서는 행이 1개 이상 반환되는 결과에 대해서는 summarise() 대신 reframe()을 사용하라 되어 있습니다. reframe()은 하상 group화 되지않은 data.frame을 반환해주는 함수로 추후 다시 다루도록 하겠습니다.
sample %>% reframe(sum_age_ch = Age + Cholesterol)
# A tibble: 10 x 1
sum_age_ch
<dbl>
1 382
2 295
3 344
4 292
5 339
6 237
7 340
8 331
9 425
10 327
특히, summarise()는 group_by()함수와 함께 자주 사용 됩니다. group_by()는 column값들을 그룹을 지은 결과를 보여줍니다. "RestingECG"의 "LVH", "Normal", "ST" 별 Age의 평균값을 계산해 보겠습니다.
sample %>% group_by(RestingECG) %>% summarise(mean_age = mean(Age))
# A tibble: 3 x 2
RestingECG mean_age
<chr> <dbl>
1 LVH 55.2
2 Normal 57.3
3 ST 55
goroup_by()에 두 개 이상의 group이 들어가도 됩니다.
sample %>% group_by(RestingECG, Angina) %>% summarise(mean_age = mean(Age))
`summarise()` has grouped output by 'RestingECG'. You can override using the `.groups` argument.
# A tibble: 5 x 3
# Groups: RestingECG [3]
RestingECG Angina mean_age
<chr> <chr> <dbl>
1 LVH N 55
2 LVH Y 55.3
3 Normal N 57.5
4 Normal Y 57
5 ST Y 55
평균 외에도 다양한 함수를 적용 할 수 있습니다. 평균, 표준편차, 중앙값, 최대값, 최소값을 한 번에 계산해보겠습니다.
sample %>% group_by(RestingECG, Angina) %>% summarise(mean_age = mean(Age),
sd_age = sd(Age),
median_age = median(Age),
max_age = max(Age),
min_age = min(Age))
`summarise()` has grouped output by 'RestingECG'. You can override using the `.groups` argument.
# A tibble: 5 x 7
# Groups: RestingECG [3]
RestingECG Angina mean_age sd_age median_age max_age min_age
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 LVH N 55 9.54 54 65 46
2 LVH Y 55.3 1.15 56 56 54
3 Normal N 57.5 12.0 57.5 66 49
4 Normal Y 57 NA 57 57 57
5 ST Y 55 NA 55 55 55
NA는 RestingECG == "Normal"이면서 Angina == "Y"인 데이터가 1개 있어서 표준편차가 계산되지 않았습니다.
'R' 카테고리의 다른 글
[dplyr] arrange, distinct, slice로 데이터 추출 및 정리 (0) | 2024.03.05 |
---|---|
[preprocessing] 결측값(NA) 찾기 (colSums(is.na()), complete.cases(), filter(), filter_all(), select_if()) (1) | 2023.08.25 |
[caret] caret을 활용한 머신러닝 모델 구축 (1) | 2023.08.07 |
[tidymodels] tidymodels를 활용한 머신러닝 모델 구축하기 (0) | 2023.07.31 |