dplyr, 데이터프레임 손쉽게 다루기
{dplyr}패키지는 정말 완소 패키지입니다. 데이터프레임의 슬라이싱이나 select 함수 등이 좋은 결과를 보여주지만 직관적이지 않고 복잡합니다. {plyr}이 대안일 수 있습니다만 느립니다. 속 터지지요. C++를 기반으로 작성된 {dplyr}은 상당히 괜찮은 data handling 기능을 제공합니다. 반드시 알아야 하겠습니다.
설치를 하기 위해
> install.packages("dplyr")
이제 패키지를 부릅니다.
> library(dplyr)
이번 포스트는 hflights 데이터를 사용하겠습니다.
> library(hflights)
> dim(hflights)
[1] 227496 21
21개의 변수에 22만개의 행 데이터가 있습니다.
다루기 편하도록 data.frame객체를 {dplyr}의 tbl_df 객체로 변환하겠습니다.
> hflights_df <- tbl_df(hflights)
> hflights_df
Source: local data frame [227,496 x 21]
....
tbl_df 객체는 출력에서 이점이 있습니다. 22만개를 다 보여주는 대신 각종 요약 정보와 데이터의 일부를 간편하게 출력합니다. 직접 해 보세요.
행 데이터 중 일부를 추출하는 전통적인 방법은
> df[condition,]
이렇게 하여 condition의 TRUE, FALSE 벡터를 이용하는 것입니다. 편리하지만 참 이해하기 어려운 표현이기도 합니다.
{dplyr}의 filter()함수와 chaining 연산자(%>%)를 이용해서 간단하게 처리합니다.
> hflights_df %>% filter(Month==1,DayofMonth==1)
Source: local data frame [552 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW 224
2 2011 1 1 6 728 840 AA 460 N520AA 72 41 5 8 IAH DFW 224
3 2011 1 1 6 1631 1736 AA 1121 N4WVAA 65 37 -9 1 IAH DFW 224
4 2011 1 1 6 1756 2112 AA 1294 N3DGAA 136 113 -3 1 IAH MIA 964
위의 예는 hflights_df를 chaining으로 걸어 filter()함수로 데이터를 넘겨주고 있습니다.
이를 받아 filter는 두 개의 조건을 &(혹은 ,)로 엮어 해당되는 행 데이터를 뽑습니다.
예에서 조건은 Month == 1 & DayofMonth == 1입니다.
조건은 or(즉 |)도 가능하고 not(!=)도 가능합니다.
> hflights_df %>% filter(Month == 1 | Month == 2)
Source: local data frame [36,038 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW 224
2 2011 1 2 7 1401 1501 AA 428 N557AA 60 45 -9 1 IAH DFW 224
3 2011 1 3 1 1352 1502 AA 428 N541AA 70 48 -8 -8 IAH DFW 224
Chaining 연산자를 쓰지 않으면
> filter.result <- filter(hflights_df, Month==1 | Month==2)
혹은 바로 결과를 보고 싶다면
(> filter.result <- filter(hflights_df, Month==1 | Month==2))
> hflights_df %>% arrange(DayofMonth)
Source: local data frame [227,496 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW 224
2 2011 1 1 6 728 840 AA 460 N520AA 72 41 5 8 IAH DFW 224
3 2011 1 1 6 1631 1736 AA 1121 N4WVAA 65 37 -9 1 IAH DFW 224
4 2011 1 1 6 1756 2112 AA 1294 N3DGAA 136 113 -3 1 IAH MIA 964
기본은 내림차순이지만 desc()함수로 오름차순 정리도 할 수 있습니다.
> hflights_df %>% arrange(desc(DayofMonth))
Source: local data frame [227,496 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 31 1 1441 1553 AA 428 N505AA 72 39 43 41 IAH DFW 224
2 2011 1 31 1 718 816 AA 460 N493AA 58 40 -19 -2 IAH DFW 224
3 2011 1 31 1 1954 2105 AA 533 N477AA 71 38 -15 -11 IAH DFW 224
4 2011 1 31 1 1656 1758 AA 1121 N455AA 62 41 13 26 IAH DFW 224
만약 여러 값들이 주어지면 먼저 주어진 것부터 정렬합니다.
arrange(Year,DayofMonth) 이면 Year로 정렬된 결과에 대해 DayofMonth가 적용됩니다.
> hflights_df %>% select(Year,Month,DayOfWeek)
Source: local data frame [227,496 x 3]
Year Month DayOfWeek
5424 2011 1 6
5425 2011 1 7
5426 2011 1 1
5427 2011 1 2
5428 2011 1 3
5429 2011 1 4
어떤 값에서 어떤 값까지 포함된 것들을 다 뽑으려면 : 연산자를 씁니다.
> hflights_df %>% select(Year:DayOfWeek)
Source: local data frame [227,496 x 4]
Year Month DayofMonth DayOfWeek
5424 2011 1 1 6
5425 2011 1 2 7
5426 2011 1 3 1
5427 2011 1 4 2
5428 2011 1 5 3
제외하려면 - 연산자를 씁니다. 아래에서 Year부터 DayOfWeek까지가 제외됩니다.
> hflights_df %>% select(-Year:DayOfWeek)
Source: local data frame [227,496 x 3]
Month DayofMonth DayOfWeek
5424 1 1 6
5425 1 2 7
5426 1 3 1
5427 1 4 2
5428 1 5 3
5429 1 6 4
데이터프레임의 어떤 데이터를 바탕으로 새로운 데이터를 만드려면 두 단계를 거칩니다.
1) 계산
2) cbind()
{dplyr}은 이것을 한 단계로 줄이고 속도를 높입니다. 함수 mutate()를 써서 해결합니다. 출력 결과물 중 ArrDelay, DepDelay, gain만 필요하다고 가정해서 두번의 chaining을 해봅시다. 이처럼 {dplyr}은 연속으로 chaining할 수 있습니다.
> hflights_df %>% mutate(gain=ArrDelay-DepDelay) %>% select(ArrDelay,DepDelay,gain)
Source: local data frame [227,496 x 3]
ArrDelay DepDelay gain
1 -10 0 -10
2 -9 1 -10
3 -8 -8 0
4 3 3 0
5 -3 5 -8
6 -7 -1 -6
그룹 지정을 위해 group_by() 객체를 만듭니다.
> planes <- group_by(hflights_df,TailNum)
> planes
Source: local data frame [227,496 x 21]
Groups: TailNum
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest
5424 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW
5425 2011 1 2 7 1401 1501 AA 428 N557AA 60 45 -9 1 IAH DFW
위 결과를 보면 Groups라는 항목이 새로 추가된 것을 확인합니다.
각 그룹에 대한 요약값 출력을 수행하기 위해 summarise()함수를 사용합시다.
> delay <- summarise(planes,
+ count = n(),
+ dist = mean(Distance, na.rm = TRUE),
+ delay = mean(ArrDelay, na.rm = TRUE))
> delay
Source: local data frame [3,320 x 4]
TailNum count dist delay
1 795 938.7157 NaN
2 N0EGMQ 40 1095.2500 1.918919
3 N10156 317 801.7192 8.199357
4 N10575 94 631.5319 18.148936
5 N11106 308 774.9805 10.101639
6 N11107 345 768.1130 8.052786
7 N11109 331 772.4532 10.280000
물론 chaining으로 이를 표현하면
delay <- planes %>% summarise(count=n(), ... ) 이렇게 쓸 수 있겠지요.
함수 n()은 그룹내 데이터의 개수를 구하는 C++ 함수입니다.
> destinations <- group_by(hflights_df, Dest)
> summarise(destinations,
+ planes = n_distinct(TailNum),
+ flights = n()
+ )
Source: local data frame [116 x 3]
Dest planes flights
1 ABQ 716 2812
2 AEX 215 724
3 AGS 1 1
4 AMA 158 1297
n_distinct()는 unique value의 개수를 구합니다.
복수의 기준을 적용하여 그룹을 하는 이유는 주로 롤업(roll-up) 계산을 위해서입니다.
> daily <- group_by(hflights_df, Year, Month, DayofMonth)
> (per_day <- summarise(daily, flights = n()))
Source: local data frame [365 x 4]
Groups: Year, Month
Year Month DayofMonth flights
1 2011 1 1 552
2 2011 1 2 678
3 2011 1 3 702
4 2011 1 4 583
5 2011 1 5 590
> (per_month <- summarise(per_day, flights = sum(flights)))
Source: local data frame [12 x 3]
Groups: Year
Year Month flights
1 2011 1 18910
2 2011 2 17128
3 2011 3 19470
4 2011 4 18593
5 2011 5 19172
> (per_year <- summarise(per_month, flights = sum(flights)))
Source: local data frame [1 x 2]
Year flights
1 2011 227496
설치를 하기 위해
> install.packages("dplyr")
이제 패키지를 부릅니다.
> library(dplyr)
이번 포스트는 hflights 데이터를 사용하겠습니다.
> library(hflights)
> dim(hflights)
[1] 227496 21
21개의 변수에 22만개의 행 데이터가 있습니다.
다루기 편하도록 data.frame객체를 {dplyr}의 tbl_df 객체로 변환하겠습니다.
> hflights_df <- tbl_df(hflights)
> hflights_df
Source: local data frame [227,496 x 21]
....
tbl_df 객체는 출력에서 이점이 있습니다. 22만개를 다 보여주는 대신 각종 요약 정보와 데이터의 일부를 간편하게 출력합니다. 직접 해 보세요.
데이터의 일부를 추출
행 데이터 중 일부를 추출하는 전통적인 방법은
> df[condition,]
이렇게 하여 condition의 TRUE, FALSE 벡터를 이용하는 것입니다. 편리하지만 참 이해하기 어려운 표현이기도 합니다.
{dplyr}의 filter()함수와 chaining 연산자(%>%)를 이용해서 간단하게 처리합니다.
> hflights_df %>% filter(Month==1,DayofMonth==1)
Source: local data frame [552 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW 224
2 2011 1 1 6 728 840 AA 460 N520AA 72 41 5 8 IAH DFW 224
3 2011 1 1 6 1631 1736 AA 1121 N4WVAA 65 37 -9 1 IAH DFW 224
4 2011 1 1 6 1756 2112 AA 1294 N3DGAA 136 113 -3 1 IAH MIA 964
위의 예는 hflights_df를 chaining으로 걸어 filter()함수로 데이터를 넘겨주고 있습니다.
이를 받아 filter는 두 개의 조건을 &(혹은 ,)로 엮어 해당되는 행 데이터를 뽑습니다.
예에서 조건은 Month == 1 & DayofMonth == 1입니다.
조건은 or(즉 |)도 가능하고 not(!=)도 가능합니다.
> hflights_df %>% filter(Month == 1 | Month == 2)
Source: local data frame [36,038 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW 224
2 2011 1 2 7 1401 1501 AA 428 N557AA 60 45 -9 1 IAH DFW 224
3 2011 1 3 1 1352 1502 AA 428 N541AA 70 48 -8 -8 IAH DFW 224
Chaining 연산자를 쓰지 않으면
> filter.result <- filter(hflights_df, Month==1 | Month==2)
혹은 바로 결과를 보고 싶다면
(> filter.result <- filter(hflights_df, Month==1 | Month==2))
정렬
데이터를 R의 기본 함수만으로 정렬(ordering)하려면 꽤나 번거롭습니다. {dplyr}은 arrange()로 간편하게 데이터프레임을 정렬합니다.> hflights_df %>% arrange(DayofMonth)
Source: local data frame [227,496 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW 224
2 2011 1 1 6 728 840 AA 460 N520AA 72 41 5 8 IAH DFW 224
3 2011 1 1 6 1631 1736 AA 1121 N4WVAA 65 37 -9 1 IAH DFW 224
4 2011 1 1 6 1756 2112 AA 1294 N3DGAA 136 113 -3 1 IAH MIA 964
기본은 내림차순이지만 desc()함수로 오름차순 정리도 할 수 있습니다.
> hflights_df %>% arrange(desc(DayofMonth))
Source: local data frame [227,496 x 21]
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest Distance
1 2011 1 31 1 1441 1553 AA 428 N505AA 72 39 43 41 IAH DFW 224
2 2011 1 31 1 718 816 AA 460 N493AA 58 40 -19 -2 IAH DFW 224
3 2011 1 31 1 1954 2105 AA 533 N477AA 71 38 -15 -11 IAH DFW 224
4 2011 1 31 1 1656 1758 AA 1121 N455AA 62 41 13 26 IAH DFW 224
만약 여러 값들이 주어지면 먼저 주어진 것부터 정렬합니다.
arrange(Year,DayofMonth) 이면 Year로 정렬된 결과에 대해 DayofMonth가 적용됩니다.
부분 데이터프레임 추출
데이터에서 부분값을 선택하는 함수는 select()입니다.> hflights_df %>% select(Year,Month,DayOfWeek)
Source: local data frame [227,496 x 3]
Year Month DayOfWeek
5424 2011 1 6
5425 2011 1 7
5426 2011 1 1
5427 2011 1 2
5428 2011 1 3
5429 2011 1 4
어떤 값에서 어떤 값까지 포함된 것들을 다 뽑으려면 : 연산자를 씁니다.
> hflights_df %>% select(Year:DayOfWeek)
Source: local data frame [227,496 x 4]
Year Month DayofMonth DayOfWeek
5424 2011 1 1 6
5425 2011 1 2 7
5426 2011 1 3 1
5427 2011 1 4 2
5428 2011 1 5 3
제외하려면 - 연산자를 씁니다. 아래에서 Year부터 DayOfWeek까지가 제외됩니다.
> hflights_df %>% select(-Year:DayOfWeek)
Source: local data frame [227,496 x 3]
Month DayofMonth DayOfWeek
5424 1 1 6
5425 1 2 7
5426 1 3 1
5427 1 4 2
5428 1 5 3
5429 1 6 4
새로운 데이터 추가
데이터프레임의 어떤 데이터를 바탕으로 새로운 데이터를 만드려면 두 단계를 거칩니다.
1) 계산
2) cbind()
{dplyr}은 이것을 한 단계로 줄이고 속도를 높입니다. 함수 mutate()를 써서 해결합니다. 출력 결과물 중 ArrDelay, DepDelay, gain만 필요하다고 가정해서 두번의 chaining을 해봅시다. 이처럼 {dplyr}은 연속으로 chaining할 수 있습니다.
> hflights_df %>% mutate(gain=ArrDelay-DepDelay) %>% select(ArrDelay,DepDelay,gain)
Source: local data frame [227,496 x 3]
ArrDelay DepDelay gain
1 -10 0 -10
2 -9 1 -10
3 -8 -8 0
4 3 3 0
5 -3 5 -8
6 -7 -1 -6
그룹연산
{dplyr}의 가치를 크게 높이는 기능은 바로 그룹 연산입니다. group_by()로 tbl_df 객체에 그룹 인덱싱을 합니다. 전통적인 R 교과서를 보면 split과 do.call 함수로 비슷한 일을 합니다만 전혀 도움이 안됩니다. 데이터가 작을 때나 쓸 수 있지 조금만 사이즈가 커도 컴퓨터가 뻗기 쉽습니다. {plyr}도 비슷한 기능을 제공합니다만 {dplyr}과는 비교도 안될 정도로 번거롭습니다.그룹 지정을 위해 group_by() 객체를 만듭니다.
> planes <- group_by(hflights_df,TailNum)
> planes
Source: local data frame [227,496 x 21]
Groups: TailNum
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin Dest
5424 2011 1 1 6 1400 1500 AA 428 N576AA 60 40 -10 0 IAH DFW
5425 2011 1 2 7 1401 1501 AA 428 N557AA 60 45 -9 1 IAH DFW
위 결과를 보면 Groups라는 항목이 새로 추가된 것을 확인합니다.
각 그룹에 대한 요약값 출력을 수행하기 위해 summarise()함수를 사용합시다.
> delay <- summarise(planes,
+ count = n(),
+ dist = mean(Distance, na.rm = TRUE),
+ delay = mean(ArrDelay, na.rm = TRUE))
> delay
Source: local data frame [3,320 x 4]
TailNum count dist delay
1 795 938.7157 NaN
2 N0EGMQ 40 1095.2500 1.918919
3 N10156 317 801.7192 8.199357
4 N10575 94 631.5319 18.148936
5 N11106 308 774.9805 10.101639
6 N11107 345 768.1130 8.052786
7 N11109 331 772.4532 10.280000
물론 chaining으로 이를 표현하면
delay <- planes %>% summarise(count=n(), ... ) 이렇게 쓸 수 있겠지요.
함수 n()은 그룹내 데이터의 개수를 구하는 C++ 함수입니다.
> destinations <- group_by(hflights_df, Dest)
> summarise(destinations,
+ planes = n_distinct(TailNum),
+ flights = n()
+ )
Source: local data frame [116 x 3]
Dest planes flights
1 ABQ 716 2812
2 AEX 215 724
3 AGS 1 1
4 AMA 158 1297
n_distinct()는 unique value의 개수를 구합니다.
복수의 기준을 적용하여 그룹을 하는 이유는 주로 롤업(roll-up) 계산을 위해서입니다.
> daily <- group_by(hflights_df, Year, Month, DayofMonth)
> (per_day <- summarise(daily, flights = n()))
Source: local data frame [365 x 4]
Groups: Year, Month
Year Month DayofMonth flights
1 2011 1 1 552
2 2011 1 2 678
3 2011 1 3 702
4 2011 1 4 583
5 2011 1 5 590
> (per_month <- summarise(per_day, flights = sum(flights)))
Source: local data frame [12 x 3]
Groups: Year
Year Month flights
1 2011 1 18910
2 2011 2 17128
3 2011 3 19470
4 2011 4 18593
5 2011 5 19172
> (per_year <- summarise(per_month, flights = sum(flights)))
Source: local data frame [1 x 2]
Year flights
1 2011 227496
교수님 항상 좋은 강의 및 자료 감사드립니다!
답글삭제포스팅 해 두신 자료들 유용하게 보고 있습니다. 특히 {dplyr}은 익혀두니 정말 유용하네요 ㅎㅎ
앞으로 올라올 자료들도 기대하고 있겠습니다!!
강충한씨. 유용하다니 다행입니다.
삭제감사합니다
답글삭제