티스토리 뷰

반응형

plyr 패키지  



 plyr 패키지는 데이터 분할, 적용, 조합 세 단계로 데이터를 처리하는 함수를 제공해줍니다.

배열(a), 데이터 프레임(d), 리스트(l)에 적용 가능


> install.packages("plyr")

> library(plyr)



1adply() 함수  그룹 연산


 adply() 함수는 apply()함수와 동일하지만 apply()는 벡터로 리턴, adply()는 데이터 프레임으로 리턴이 가능합니다.

 apply(데이터 셋, 적용방향, 적용(그룹)함수) 
          # 적용방향 = 1:같은 행별, 2:같은 열별, c(1,2): 원소별


plyr :: adply( .데이터,    # 행렬, 배열, 데이터 프레임

                  .margins,    # 적용방향 = 1: 같은 행렬, 2: 같은 열별, c(1,2): 원소별 

                  .fun = NULL )   # 적용 함수


> library(googleVis)

> Fruits       # googleVis 패키지와 함께 들어있는 데이터 셋

    Fruit Year Location Sales Expenses Profit       Date

1  Apples 2008     West    98       78     20 2008-12-31

2  Apples 2009     West   111       79     32 2009-12-31

...

8 Oranges 2010     East    98       91      7 2010-12-31

9 Bananas 2010     East    81       71     10 2010-12-31

> apply(Fruits[,4:6],2,sum)   # apply() 함수는 벡터형태로 출력(그룹함수를 적용하기 좋음)

   Sales Expenses   Profit 

     845      710      135 

> adply(Fruits[,4:6],2,sum)   # adply() 함수는 데이터 프레임 형태로 출력

        X1  V1

1    Sales 845

2 Expenses 710

3   Profit 135


> subway <- read.csv("subway2.csv", stringsAsFactors = F, skip = 1)

> str(subway)

> head(subway)

       전체 구분 X05.06 X06.07 X07.08 X08.09 X09.10 X10.11 X11.12 X12.13 X13.14 X14.15 X15.16 ...

1 서울역(1) 승차  17465  18434  50313  93398  78705  86342  93585  97707 102608 101710  93849 ...

2           하차   7829  48553 110250 233852 121983  79628  75577  70984  80388  80263  79592 ...

3  시 청(1) 승차   2993   4473   7633  10404  13328  16953  25467  27265  36393  41128  48352 ...

4           하차   4142  19730  67995 175458  83777  48363  47519  42646  45465  42882  38720 ...

5     종 각 승차   7371   7836  14545  24578  23691  32290  47470  57187  76131  78721  87480 ...

6           하차   4861  29757  93579 245221 153933  88680  83402  78253  84694  80095  71320 ...

> toNum <- function(x) {      # ,(콤마) 제거 사용자 지정 함수

+   as.numeric(str_replace_all(x, ',', ''))

+ }

> library(stringr)

> subway[,-c(1,2)] <- sapply(subway[,-c(1,2)],toNum)   # sapply()에 함수를 적용

> apply(subway[,-c(1,2)],2,sum)    # vector 형태로 출력

  X05.06   X06.07   X07.08    ...  X22.23   X23.24   X24.01 

 1338165  3953180 10184565  ...  8782129  4997008  1204504

 > adply(subway[,-c(1,2)],2,sum)    # data frame 형태로 출력

       X1       V1

1  X05.06  1338165

2  X06.07  3953180

3  X07.08 10184565

...

18 X22.23  8782129

19 X23.24  4997008

20 X24.01  1204504




2ddply() 함수 중요 @@@ : 그룹 연산 (다양한 옵션) => 그룹 연산에서 많이 사용


 데이터 프레임을 input으로 데이터 프레임을 ouput 해주는 함수입니다.
분할, 적용, 조합을 수행하여 그룹별 연산을 사용하기 위한 용도이고, tapply(), agrregate() 함수와 유사합니다. 


tapply(vector, index, function)  # 벡터만 가능


aggregate(x,

              by,       # group by 컬럼, list로 전달, 여러 컬럼 전달 가능 

              FUN)    # 함수

aggregate(formula,   # 연산 대상 ~ group by 컬럼

               data,       # 위를 포함한 전체 데이터 셋

               FUN)  


ddply(data,     # 전체 데이터 셋

      .(),            # group by 컬럼

      ddply-func,      # ddply 내부 함수 (transform, mutate, summarise, subset...)

      fun)          # 그룹함수(컬럼이름과 함께 전달)


ddply 내부 함수 

transform() : 원본 데이터 + ddply의 연산 결과를 컬럼 이름 지정과 함께 출력 

# mutate() : transform과 유사하지만 순차적 연산처리를 할 경우 사용

summarise() : 그룹 연산 결과를 그룹 수에 맞게 요약 정보 제공 

subset() : 그룹별 연산 결과를 사용하여 특정 조건을 만족하는 데이터만 출력 



# transform()  :  원본 데이터 + ddply의 연산 결과를 컬럼 이름 지정과 함께 출력 

> Fruits

    Fruit Year Location Sales Expenses Profit       Date

1  Apples 2008     West    98       78     20 2008-12-31

2  Apples 2009     West   111       79     32 2009-12-31

...

8 Oranges 2010     East    98       91      7 2010-12-31

9 Bananas 2010     East    81       71     10 2010-12-31

> ddply(Fruits, .(Year), transform, average = mean(Sales))   # 년도별 Sales 평균

    Fruit Year Location Sales Expenses Profit       Date  average

1  Apples 2008     West    98       78     20 2008-12-31 93.00000

2 Oranges 2008     East    96       81     15 2008-12-31 93.00000

...

8 Oranges 2010     East    98       91      7 2010-12-31 89.33333

9 Bananas 2010     East    81       71     10 2010-12-31 89.33333

> ddply(Fruits, .(Fruit), transform, average = mean(Sales))   # 과일 종류별  Sales 평균

    Fruit Year Location Sales Expenses Profit       Date  average

1  Apples 2008     West    98       78     20 2008-12-31 99.33333

2  Apples 2009     West   111       79     32 2009-12-31 99.33333

...

8 Oranges 2009     East    93       80     13 2009-12-31 95.66667

9 Oranges 2010     East    98       91      7 2010-12-31 95.66667


# mutate()  : transform과 유사하지만 순차적 연산처리를 할 경우 사용

> ddply(Fruits, .(Year), mutate, average = mean(Sales), avg_per = average/100)

                                                  # 인자의 결과(average)를 다음 인자(avg_per)에 순차적으로 사용

    Fruit Year Location Sales Expenses Profit       Date  average   avg_per

1  Apples 2008     West    98       78     20 2008-12-31 93.00000 0.9300000

2 Oranges 2008     East    96       81     15 2008-12-31 93.00000 0.9300000

...

8 Oranges 2010     East    98       91      7 2010-12-31 89.33333 0.8933333

9 Bananas 2010     East    81       71     10 2010-12-31 89.33333 0.8933333



# student 데이터를 사용하여 각 학년별 키와 몸무게의 평균 구하기 

> ddply(std, .(GRADE), transform, avg_height = mean(HEIGHT), avg_weight = mean(WEIGHT)) 

   STUDNO   NAME         ID GRADE        JUMIN            BIRTHDAY          TEL HEIGHT WEIGHT DEPTNO1

1    9711 이윤나 prettygirl     1 7.808192e+12 1978/08/19 00:00:00 055)278-3649    162     48     101

2    9712 안은수   silverwt     1 7.801052e+12 1978/01/05 00:00:00  02)381-5440    175     63     201

...

19   9414 김재수   gunmandu     4 7.512251e+12 1975/12/25 00:00:00 02)6255-9875    177     83     201

20   9415 박동호    pincle1     4 7.503032e+12 1975/03/03 00:00:00 031)740-6388    182     70     202

   DEPTNO2 PROFNO avg_height avg_weight     # 그룹 연산 결과를 전체 데이터셋에 각 행마다 추가

1       NA     NA      170.4       62.4

2       NA     NA      170.4       62.4

...

19      NA   4001      175.8       68.2

20      NA   4003      175.8       68.2

> ddply(std, .(GRADE), mutate, avg_height = mean(HEIGHT), avg_height2 = avg_height / 100)

   STUDNO   NAME         ID GRADE        JUMIN            BIRTHDAY          TEL HEIGHT WEIGHT DEPTNO1

1    9711 이윤나 prettygirl     1 7.808192e+12 1978/08/19 00:00:00 055)278-3649    162     48     101

2    9712 안은수   silverwt     1 7.801052e+12 1978/01/05 00:00:00  02)381-5440    175     63     201

...

19   9414 김재수   gunmandu     4 7.512251e+12 1975/12/25 00:00:00 02)6255-9875    177     83     201

20   9415 박동호    pincle1     4 7.503032e+12 1975/03/03 00:00:00 031)740-6388    182     70     202

   DEPTNO2 PROFNO avg_height avg_height2   # 순차적 연산처리 

1       NA     NA      170.4       1.704

2       NA     NA      170.4       1.704

...

19      NA   4001      175.8       1.758

20      NA   4003      175.8       1.758

> ddply(std, .(GRADE), summarise, avg_height = mean(HEIGHT), avg_weight = mean(WEIGHT))

  GRADE avg_height avg_weight     # 그룹별 연산 

1     1      170.4       62.4

2     2      175.6       67.4

3     3      166.6       51.4

4     4      175.8       68.2



Q.

# 1. 학년별 최대 키 (3가지 방법)

# tapply()함수 사용

> tapply(std$HEIGHT, std$GRADE, max)  # 벡터로 리턴

  1   2   3   4 

179 184 177 182 

# aggregate()함수 사용

> aggregate(HEIGHT ~ GRADE, std, max)  # 데이터 프레임으로 리턴

  GRADE HEIGHT

1     1    179

2     2    184

3     3    177

4     4    182

# ddply()함수 사용

> max_height <- ddply(std, .(GRADE), summarise, max_height = max(HEIGHT))

> max_height

  GRADE max_height

1     1        179

2     2        184

3     3        177

4     4        182


##################################################################


# 2. 학년별 최대 키를 갖는 사람의 이름, 학년, 키

# sol 1) merger() 함수 사용 

> merge(std, max_height, by.x = c('GRADE','HEIGHT'),     # merge는 동등비교만 가능  

+       by.y = c('GRADE', 'max_height'))[,c("NAME","GRADE","HEIGHT")]

    NAME GRADE HEIGHT

1 김주현     1    179

2 노정호     2    184

3 오나라     3    177

4 박동호     4    182

# sol 2) ddply() 함수 사용 

> ddply(std, .(GRADE), subset, HEIGHT == max(HEIGHT),)[,c("NAME","GRADE","HEIGHT")]

                             # 원본 데이터 컬럼 == 연산 결과 (조건이니까 '==' 로 써줘야함)

    NAME GRADE HEIGHT

1 김주현     1    179

2 노정호     2    184

3 오나라     3    177

4 박동호     4    182


##################################################################


# 3. 학년별 평균키보다 큰 학생의 정보 출력 

> ddply(std, .(GRADE), subset, HEIGHT > mean(HEIGHT),)[,c("NAME","GRADE","HEIGHT")]

     NAME GRADE HEIGHT               # ddply() 함수는 merge() 함수와 다르게 대소비교 가능

1  안은수     1    175

2  인영민     1    173

3  김주현     1    179

4  일지매     2    182

5  노정호     2    184

6  오나라     3    177

7  임세현     3    171

8  이진욱     4    180

9  김재수     4    177

10 박동호     4    182



Deep.

# 1. 2013년_프로야구선수_성적.csv 파일을 불러와서 다음을 수행

> ball <- read.csv("2013년_프로야구선수_성적.csv", stringsAsFactors = F)

> head(ball)

  순위 선수명 포지션   팀 경기 타수 득점 안타 X2루타 X3루타 홈런 타점 도루 볼넷 삼진 병살  타율  장타율 출루율 연봉

1    1 김태균  1루수 한화  101  345   41  110     24      0   10   52    0   73   67   14 0.319   0.475  0.444 15.0

2    2 박병호  1루수 넥센  128  450   91  143     17      0   37  117   10   92   96    7 0.318  0.602  0.437  5.0

3    3   최정  3루수   SK  120  434   75  137     18      0   28   83   24   64  109   10 0.316   0.551  0.429  7.0


# 1) 경기수가 120 경기 이상인 선수만 출력하기

ball[ball$경기>=120,]


# 2) 경기수가 120 경기 이상이면서 득점도 80 점 이상인 선수만 출력하기

ball[ball$경기 >= 120 & ball$득점 >= 80,]


# 3) 팀별 출루율의 평균 출력

> tapply(ball$출루율, ball$팀, mean)

   KIA     LG     SK   넥센   롯데   삼성   한화 

0.3940 0.3990 0.4115 0.4370 0.4210 0.4135 0.4440 

> aggregate(출루율 ~ 팀, ball, mean)

    팀 출루율

1  KIA 0.3940

2   LG 0.3990

3   SK 0.4115

4 넥센 0.4370

5 롯데 0.4210

6 삼성 0.4135

7 한화 0.4440

> library(plyr)

> ddply(ball, .(팀), summarise, 평균_출루율 = mean(출루율))   # aggreate()함수와 동일 + 컬럼명 설정 가능 

    팀 평균_출루율

1  KIA      0.3940

2   LG      0.3990

3   SK      0.4115

4 넥센      0.4370

5 롯데      0.4210

6 삼성      0.4135

7 한화      0.4440


# 4) 각 선수의 선수명, 포지션, 팀과 해당 팀의 평균 출루율 데이터 조회하기

> ddply(ball, .(팀), transform, 평균_출루율 = mean(출루율))[,c("선수명","포지션","팀","평균_출루율")]

   선수명 포지션   팀 평균_출루율

1  나지완 좌익수  KIA      0.3940

2  정성훈  3루수   LG      0.3990

3  박용택 중견수   LG      0.3990

4    최정  3루수   SK      0.4115

5  박정권  1루수   SK      0.4115

6  박병호  1루수 넥센      0.4370

7  손아섭 우익수 롯데      0.4210

8  박석민  3루수 삼성      0.4135

9  배영섭 중견수 삼성      0.4135

10 김태균  1루수 한화      0.4440


###########################################################


# 2. emp2.csv 파일을 불러와서 다음을 수행

> emp2<- read.csv("emp2.csv", stringsAsFactors = F)

> head(emp2)

     EMPNO   NAME        BIRTHDAY DEPTNO EMP_TYPE          TEL      HOBBY       PAY POSITION   PEMPNO

1 19900101 나사장 1964-01-25 0:00      1   정규직 054)223-0001   음악감상 100000000 대표이사       NA

2 19960101 전부장 1973-03-22 0:00   1000   정규직 02)6255-8000       독서  72000000     부장 19900101

3 19970201 최일도 1975-04-15 0:00   1000   정규직 02)6255-8005       운동  50000000     과장 19960101

...

> str(emp2)


# PAY 컬럼에 '-'를 제외한 후 숫자 타입으로 변경

### 1.ifelse구문으로 전체 컬럼 수정

> emp2$PAY

 [1] "100000000" "72000000"  "50000000"  ... "22000000"  "20000000"  "20000000"  "-"        

> ifelse(emp2$PAY == '-', NA, as.numeric(emp2$PAY)) 

                                        # 값이 커서 지수 형식으로 출력, 치환 대상이 데이터의 일부라면 ifelse()를 사용한 치환은 성능상 비추 

 [1] 1.0e+08 7.2e+07 5.0e+07 6.0e+07 5.6e+07 7.5e+07 ...   NA

### 2. 수정 대상만 선택해서 NA 치환 후 숫자 변경 

> emp2[emp2$PAY=='-','PAY'] <- NA  # 치환 대상이 일부라면, 색인을 통해 조건에 만족하는 데이터만 치환

> as.numeric(emp2$PAY)

 [1] 1.0e+08 7.2e+07 5.0e+07 6.0e+07 5.6e+07 ... 2.2e+07 2.0e+07 2.0e+07      NA

### 3. PAY 컬럼의 '-' 값을 read.csv로 불러올 때 NA 처리

       (데이터가 방대해질 수록 불필요한 작업은 성능에 마이너스이므로 데이터를 불러올 때 NA로 처리하는 것이 좋음)

> emp2 <- read.csv("emp2.csv", stringsAsFactors = F, na.strings = '-')    # c('-',' ') 벡터로 na.strings에 여러 값 설정 가능 


# 1) 현재 직급이 없는 직원은 사원으로 치환

> library(stringr)

> emp2$POSITION

 [1] "대표이사" "부장"     "과장"     "차장"    ...    "-"        "-"        "-"        "-"        "-"        "-"           

> emp2[is.na(emp2$POSITION), 'POSITION'] <- '사원'    # 색인을 통한 데이터 치환

   # str_replace_all(emp2$POSITION,'-','사원')  # 데이터를 na.strings 옵션 없이 불러올 경우, str_replace_all()함수를 사용한 방법도 ifelse()함수를 사용한 치환보다 성능이 좋긴 하지만. emp2$POSITION 벡터 전체를 가지고 함수가 동작하므로, 색인을 통한 데이터 치환보다는 좋지 않습니다. 

   # 또한, NA는 문자열이 아닌데, str_replace_all() 함수에서 'NA'로 작성 시 문법에 맞지 않으므로 문자열 치환에서 NA는 치환 불가 


# 2) 직급별 평균연봉을 출력(tapply, aggregate, ddaply)

> emp2[is.na(emp2$PAY), 'PAY'] <- 0

> tapply(emp2$PAY, emp2$POSITION, mean)  

     과장      대리  대표이사      부장      사원      차장 

 51500000  35000000 100000000  71666667  22600000  60000000 

    # tapply(emp2$PAY, emp2$POSITION, mean, na.rm = T) 

    # 이 방법도 있지만, mean() 함수에서 na.rm = TRUE 설정 시, NA인 row는 카운트를 하지 않으므로 상황에 맞게 사용하면 됩니다.

> aggregate(PAY ~ POSITION, emp2, mean)  # aggregate()함수는 자동으로 na를 0으로 생각하고 연산

  POSITION       PAY

1     과장  51500000

2     대리  35000000

3 대표이사 100000000

4     부장  71666667

5     사원  22600000

6     차장  60000000

> ddply(emp2, .(POSITION), summarise, mean_pay = mean(PAY))  

     # ddply(emp2, .(POSITION), summarise, mean_pay = mean(PAY, na.rm = T))   

  POSITION  mean_pay

1     과장  51500000

2     대리  35000000

3 대표이사 100000000

4     부장  71666667

5     사원  22600000

6     차장  60000000


# 3) 직급별 최대연봉자의 사원번호,이름,직급,연봉출력

ddply(emp2, .(POSITION), subset, PAY == max(PAY))[,c("EMPNO","NAME","POSITION","PAY")]


###########################################################


# 3. emp.csv 파일을 불러와서 다음을 수행

> emp<- read.csv("emp.csv", stringsAsFactors = F)

> head(emp)

  EMPNO  ENAME      JOB  MGR        HIREDATE  SAL COMM DEPTNO

1  7369  SMITH    CLERK 7902 1980-12-17 0:00  800   NA     20

2  7499  ALLEN SALESMAN 7698 1981-02-20 0:00 1600  300     30

3  7521   WARD SALESMAN 7698 1982-02-22 0:00 1250  500     30

...


# 1) 부서별 각 사원의 이름을 다음과 같은 형태로 출력

# DEPTNO                                     ENAME

# 1     10                       CLARK, KING, MILLER

# 2     20          SMITH, JONES, SCOTT, ADAMS, FORD

# 3     30 ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES


# 그룹 연산의 수행과정

# tapply(emp$ENAME, emp$DEPTNO, function)

# 1. 분리 : 그룹별 데이터의 분리(연산 컬럼만)  -> 연산 대상 = ENAME

# 2. 적용 : 분리된 연산 대상을 '각각' 함수에 적용

# 3. 결합 : 위의 연산 결과를 다시 결합하여 화면에 출력

> library(stringr)

> str_c(emp[emp$DEPTNO == 10, 'ENAME'], collapse = ',')   # 다음과 같이 출력 가능 

[1] "CLARK,KING,MILLER"


# 결합 함수의 주의점 !!!

> v1 <- c('a','b','c')

> str_c('a','b','c')    # 함수 내에 분리된 인자들을 연결

[1] "abc"

> str_c(v1)  # 여러개의 값이 들어있는 하나의 인자를 연결하기 때문에 옵션이 필요

[1] "a" "b" "c"


> str_c('a','b','c', sep = ',')  # 분리된 인자들을 연결

[1] "a,b,c"

> str_c(v1, collapse = ',')

[1] "a,b,c"


> paste('a','b','c', sep = ',')  # 문자 결합

[1] "a,b,c" 

> paste(v1, collapse = ',')    # 벡터 내 문자 결합

[1] "a,b,c"


> library(stringr)

> tapply(emp$ENAME, emp$DEPTNO, str_c, collapse = ',')

                     10                                     20                                                         30 

      "CLARK,KING,MILLER"         "SMITH,JONES,SCOTT,ADAMS,FORD"    "ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES" 

                                    

> aggregate(ENAME ~ DEPTNO, emp, str_c, collapse = ', ')  # collapse 옵션을 사용하지 않아도 ,(콤마)로 연결되어 출력 가능

  DEPTNO                                     ENAME

1     10                       CLARK, KING, MILLER

2     20          SMITH, JONES, SCOTT, ADAMS, FORD

3     30 ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES

> library(plyr)

> ddply(emp, .(DEPTNO), summarise, ENAME=str_c(ENAME, collapse = ', '))

  DEPTNO                                     ENAME

1     10                       CLARK, KING, MILLER

2     20          SMITH, JONES, SCOTT, ADAMS, FORD

3     30 ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES





참고: KIC 캠퍼스 머신러닝기반의 빅데이터분석 양성과정


반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday