Plyr package (데이터 조작)


plyr는 reshape2와 마찬가지로 Hadley Wickham에 의해서 개발 되었다.
2011년에 해당 논문이 아래와 같이 출간되었다.

The split-apply-combine strategy for data analysis(2011, Journal of Statistical Software, Vol 40).

데이터들을 쪼개고, 일부부늘 취하며, 어떤 특정 함수를 특정 부분에 적용하고
그리고 결과들을 조합하는 향상된 기능을 제공하는 패키지이다.

그 밖에도
loop의 재배치를 제공한다.

로드법

install.packages("plyr")
library(plyr)

apply 종류가 많다. 하지만 데이터 프레임을 위한것은 없다.
이때 plyr package에 있는 ddply를 이용한다.

함수 제공 형태

  • 배열(a)
  • 데이터 프레임(d)
  • 리스트(l)
  • _는 아무런 출력도 내보내지 않음을 의미함.
{adl}{adl_}ply
입력 데이터 타입출력 데이터 타입

유용한 함수: adply()ddply()mdply()
유용한 유틸리티 함수: transform()mutate()summarise()subset()

Adply()

Adply()는 배열(a)를 받아 데이터 프레임(d)을 반환하는 함수이다. 
입력이 반드시 배열일 필요는 없고 숫자 색인으로 접근 가능 하기만 하면된다.
따라서 데이터 프레임도 입력으로 사용이 가능하다.

apply()의 단점인 문자열 데이터가 섞여 있다면 데이터가 모두 문자열로 반환된다는 점을 개선한 것이다.

adply(
.data, # 행렬, 배열, 또는 데이터 프레임
# 함수를 적용할 방향. 1(행 방향), 2(열 방향) 또는 c(1,2) 행과 열의 모든 방향을 지정 한다.
.margins,
.fun=NULL # .margin 방향으로 잘려진 데이터에 적용할 함수

반환 값은 데이터 프레임이다.

apply와 유사하지만 반환 값이 데이터 프레임이라는 차이가 있다.

예제

#적용 전
 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
adply(iris, 1 , function(row){ row$Sepal.Length >= 5.0 & row$Species == "setosa"})

    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species    V1
1            5.1         3.5          1.4         0.2     setosa  TRUE
2            4.9         3.0          1.4         0.2     setosa FALSE
3            4.7         3.2          1.3         0.2     setosa FALSE

예제: 컬럼에 이름 부여

adply(iris, 1 , function(row)
{ 
    data.frame( sepal_ge_5_setosa = c(row$Sepal.Length >= 5.0 & row$Species == "setosa"))
}
)

    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species sepal_ge_5_setosa
1            5.1         3.5          1.4         0.2     setosa              TRUE
2            4.9         3.0          1.4         0.2     setosa             FALSE

Ddply()

ddply()는 데이터 프레임(d)을 입력으로 받아 데이터 프레임(d)을 내보내는 함수 이다.

ddply(
.data,
.variables, #데이터를 그룹 지을 변수명
.fun=NULL
)

반환 값은 데이터 프레임이다.

adply()와 ddply()의 가장 큰 차이점이라면 adply()는 행 또는 컬럼 단위로 함수를 적용하는 반면
ddply()는 .variables에 나열한 컬럼에 따라 데이터를 나눈 뒤 함수를 적용한다는 점이다.

아래와 같이.()안의 컬럼으로 데이터를 묶은 다음에 function안에 있는 함수를 적용 하게 된다.
데이터 프레임의 컬럼의 이름은 sepal.width.mean이며, 각 Species에 대해서 묶고 그것들의 Sepal.Width의 평균을 구하는 코드이다.

ddply(iris, .(Species), function(sub){
    data.frame(sepal.width.mean = mean(sub$Sepal.Width))
})
     Species sepal.width.mean
1     setosa            3.428
2 versicolor            2.770
3  virginica            2.974

추가 조건을 기입한 예제는 아래와 같다.

ddply(iris, .(Species, Sepal.Length > 5.0), function(sub){
    data.frame(sepal.width.mean = mean(sub$Sepal.Width))
})

     Species Sepal.Length > 5 sepal.width.mean
1     setosa            FALSE         3.203571
2     setosa             TRUE         3.713636
3 versicolor            FALSE         2.233333
4 versicolor             TRUE         2.804255
5  virginica            FALSE         2.500000
6  virginica             TRUE         2.983673

Mdply()

m{adl_}ply(), 즉 maply()mdply()mlply()m_ply()함수는 데이터 프레임 또는 
배열을 인자로 받아 각 컬럼을 주어진 함수에 적용하고 그 실행 결과들을 조합한다.
여기서는 이들 중 mdply()에 대해서 살펴본다.

plyr::mdply(
.data, # 인자로 사용할 행렬 또는 데이터 프레임
.fun, # 호출할 함수
)
# 반환 값은 데이터 프레임이다.

Transform, Mutate, Summarise, Subset

데이터 프레임을 반환 한다.

base::transform( 
.data # 변환할 객체
...   # 태그=값 형태의 인자들
)

데이터 프레임 _data에 ...에 지정한 연산을 수행한 뒤 그 결과를 지정한 새로운 컬럼을 추가한 데이터 프레임을 반환한다.

데이터 프레임에 새로운 컬럼을 추가하거나 기존 컬럼을 수정 한다.

plyr::mutate(
.data, # 변환할 데이터 프레임
... # 새로운 컬럼 정의. 컬럼명 = 값 형식
)

변환이 이루어진다는 점은 transform()과 같지만 컬럼명=값 형태로 지정된 연산이 여러 개 있을 때 앞서의 연산 결과를 뒤에 나오는 연산에서 참조할 수 있다는 차이가 있다.

plyr:summarise: 데이터 프레임을 요약 한다.

plyr::summarise(
.data, # 요약할 데이터 프레임
... # 변수=값 형태의 인자들
)

...에 지정된 그룹마다의 요약을 수행한 뒤 그 결과를 저장한 새로운 컬럼이 추가된 데이터 프레임을 반환한다.

subset은 이전 POST 참조

Transform()

transform은 연산 결과를 데이터 프레임의 새로운 컬럼에 저장하는 함수이다.

이를 사용해 baseball 데이터에 각 행이 선수의 몇 년차 통계인지를 뜻하는 cyear 컬럼을 추가해보자.
다음 코드는 데이터를 선수id로 분할하여 그룹 지은 뒤, 각 그룹에세 year의 최솟값과 현재 행의 year값의 차이를 cyear에 저장 한다.

> head(ddply(baseball, .(id), transform, cyear = year - min(year) + 1))

         id year stint team lg   g  ab   r   h X2b X3b hr rbi sb cs bb so ibb hbp sh sf gidp cyear
1 aaronha01 1954     1  ML1 NL 122 468  58 131  27   6 13  69  2  2 28 39  NA   3  6  4   13     1
2 aaronha01 1955     1  ML1 NL 153 602 105 189  37   9 27 106  3  1 49 61   5   3  7  4   20     2
3 aaronha01 1956     1  ML1 NL 153 609 106 200  34  14 26  92  2  4 37 54   6   2  5  7   21     3
4 aaronha01 1957     1  ML1 NL 151 615 118 198  27   6 44 132  1  1 57 58  15   0  0  3   13     4
5 aaronha01 1958     1  ML1 NL 153 601 109 196  34   4 30  95  4  1 59 49  16   1  0  3   21     5
6 aaronha01 1959     1  ML1 NL 154 629 116 223  46   7 39 123  8  0 51 54  17   4  0  9   19     6

Mutate()

base::transform()을 개선한 plyr::mutate() 함수가 있다. 이 함수는 여러 컬럼을 데이터 프레임에 추가할 때 바로 앞서 추가한 컬럼을 뒤에 추가하는 컬럼에서 참조할 수 있어 편리하다. 예를 들어, 아래 코드에서 muate()를 이용해 transform() 예에서처럼 cyear를 계산한 뒤log(cyear)를 log_cyear컬럼으로 추가 한다. 
만약 mutate()가 아닌 transform()을 사용하면 이 경우 에러가 발생 한다.

> head( ddply(baseball, .(id), mutate, cyear=year - min(year)+1, log_cyear = log(cyear)))
> 
         id year stint team lg   g  ab   r   h X2b X3b hr rbi sb cs bb so ibb hbp sh sf gidp cyear log_cyear
1 aaronha01 1954     1  ML1 NL 122 468  58 131  27   6 13  69  2  2 28 39  NA   3  6  4   13     1 0.0000000
2 aaronha01 1955     1  ML1 NL 153 602 105 189  37   9 27 106  3  1 49 61   5   3  7  4   20     2 0.6931472
3 aaronha01 1956     1  ML1 NL 153 609 106 200  34  14 26  92  2  4 37 54   6   2  5  7   21     3 1.0986123
4 aaronha01 1957     1  ML1 NL 151 615 118 198  27   6 44 132  1  1 57 58  15   0  0  3   13     4 1.3862944
5 aaronha01 1958     1  ML1 NL 153 601 109 196  34   4 30  95  4  1 59 49  16   1  0  3   21     5 1.6094379
6 aaronha01 1959     1  ML1 NL 154 629 116 223  46   7 39 123  8  0 51 54  17   4  0  9   19     6 1.7917595

Summarise()

transform이 인자로 주어진 계산 결과를 새로운 컬럼에 추가한 데이터 프레임을 반환하는 반면,
summarise()는 계산 결과만을 담은 새로운 데이터 프레임을 반환 한다.

baseball 데이터에서 각 선수의 최초 데이터가 몇 년도인지를 조사해보자.
아래 예에서는 데이터를 id마다 그룹지은 뒤 각 그룹마다 year의 최솟값을 계산한 minyear 컬럼을 생성 했다.
연산 시 사용할 함수로 summarise()를 지정했으므로 그룹을 짓는 변수인 id와 각 그룹의 요약 값 minyear만 저장된 데이터 프레임이 반환됐다.

> head (ddply(baseball, .(id), summarise, minyear=min(year)))
         id minyear

1 aaronha01    1954
2 abernte02    1955
3 adairje01    1958
4 adamsba01    1906
5 adamsbo03    1946
6 adcocjo01    1950

만약 여러 요약 값을 구하고 싶다면 요약 값 계산을 계속 나열한다.

> head (ddply(baseball, .(id), summarise, minyear=min(year), maxyear=max(year)))
         id minyear maxyear

1 aaronha01    1954    1976
2 abernte02    1955    1972
3 adairje01    1958    1970
4 adamsba01    1906    1926
5 adamsbo03    1946    1959
6 adcocjo01    1950    1966


'Data Science > R Basic' 카테고리의 다른 글

Apply 함수 (데이터 조작)  (1) 2015.10.03
R의 문자열 처리 및 비교  (0) 2015.10.03
Plyr package (데이터 조작)  (0) 2015.10.01
Reshape2 pacakge (데이터 조작)  (0) 2015.10.01
R 자주 사용하는 팁 및 한글 주석 깨짐 해결  (2) 2015.07.30
R의 철학  (0) 2015.04.17

+ Recent posts