본문 바로가기
R

21. 데이터마트 - 2

by #Glacier 2018. 11. 21.
반응형

안녕하세요. 오늘은 어제에 이어서 데이터마트 두 번째 파트를 알아보겠습니다.

오늘 해볼 내용 중 첫 번째인 sqldf package 부터 시작할게요.


저는 R프로그램을 껐다가 켰으니 다시 reshape 패키지를 설치해야됩니다. 이어하시는분은 안설치하셔도되요 reshape 패키지만.,

<sqldf 패키지에 대한 설명>

-sql에 익숙하고, programming에 능숙하지 않은 사용자, SAS에서 proc sql로 작업을 하던 사용자를 위한 패키지라고 합니다.

-표준 sql에서 사용되는 문장이 모두 가능하다. 단 데이터 이름에 "."과 같은 특수문자가 들어간 경우 "로 묶어주면 table처럼 간단히 처리 가능.

-nested query등 다양한 내용 처리 가능


install.packages("reshape")

library(reshape)

install.packages("sqldf")

library(sqldf)

data(french_fries, package="reshape")

head(french_fries)


   time treatment subject rep potato buttery grassy rancid painty
61    1         1       3           1    2.9     0.0       0.0    0.0    5.5
25    1         1       3          2   14.0     0.0       0.0    1.1    0.0
62    1         1      10          1   11.0     6.4       0.0    0.0    0.0
26    1         1      10          2    9.9     5.9      2.9    2.2    0.0
63    1         1      15          1    1.2     0.1        0.0    1.1    5.1
27    1         1      15          2    8.8     3.0       3.6    1.5    2.3
 

# french_fries data :  2004년 lowa State University에서 시행한 3가지 오일이 프렌치 후라이의 맛에 미치는 영향을 조사한 data

# 일단 요렇구나 한번 봅니다. 그리고 treatement(오일3가지)를 테이블로 구성합니다.


table(french_fries$treatment)


 1   2   3 
232 232 232


sqldf("select * from french_fries limit 6")

#요렇게 치면.. head()함수와 똑같겠죠. 헤드함수가 디폴트값이 6개행을 보여주니까요~

#혹시 SQL의 기본적인 구문을 모르시는 분들을 위해서 SELECT * FROM은 결과를 표시해주는 함수입니다.


Loading required package: tcltk
  time treatment subject rep potato buttery grassy rancid painty
1    1         1       3          1    2.9      0.0        0.0    0.0    5.5
2    1         1       3         2   14.0      0.0        0.0    1.1    0.0
3    1         1      10         1   11.0      6.4        0.0    0.0    0.0
4    1         1      10         2    9.9      5.9        2.9    2.2    0.0
5    1         1      15         1    1.2      0.1         0.0    1.1    5.1
6    1         1      15         2    8.8      3.0        3.6    1.5    2.3


# 조건문 Where

sqldf("select count(*) from french_fries where treatment=1")

#이렇게 치면 트리트먼트가 1인 프렌치후라이 데이터의 숫자를 (*)모두 세어라 가 되겠죠.

#위에서 봤듯이 232가 나올겁니다.

  count(*)
1      232


names(french_fries)[2]<-"oil.type"

head(french_fries)


   time oil.type subject rep potato buttery grassy rancid painty
61    1        1       3   1    2.9     0.0    0.0    0.0    5.5
25    1        1       3   2   14.0     0.0    0.0    1.1    0.0
62    1        1      10   1   11.0     6.4    0.0    0.0    0.0
26    1        1      10   2    9.9     5.9    2.9    2.2    0.0
63    1        1      15   1    1.2     0.1    0.0    1.1    5.1
27    1        1      15   2    8.8     3.0    3.6    1.5    2.3


#요렇게 treatment열 변수명을 oil.type으로 바꿨습니다.

#하지만 SELECT*FROM 구문을 사용하면 "."이 "_"로 변환됩니다. period(.)은 사용이 불가합니다.

#이제 Where문을 사용하고자 oil.type이 1인 행을 찾아 세어라~라고 하면 오류가납니다. 못찾습니다.

#위에서 말씀드렸듯이 .은 안됩니다. 그래서 이름을 .에서 _로 바꿔주고 다시 치면 정상적으로 실행됩니다.

#책에서는 자동적으로 변환되어 나타난다고 적혀있지만 실제론 그렇게 되지 않았습니다(참고)


sqldf("select count(*) from french_fries where oil.type=1")
names(french_fries)[2]<-"oil_type"
sqldf("select count(*) from french_fries where oil_type=1")


 count(*)
1      232


#이런 식으로 SQL문을 사용할 수 있습니다. 이를 이용하면 R문법을 잘 몰라도, 본인이 지정한 변수를 쉽게 만들 수 있기 때문에

#분석도구마다 이러한 SQL기능을 지원하는 기능이 존재합니다. 처리 속도는 대용량 데이터가 아닌 이상 큰 차이가 없어서 30분이상 소요되는 작업이

#아니라면 sqldf를 사용하는 것이 용이하다고 합니다.


#그다음 알아볼 패키지는 plyr패키지 인데요~

#plyr패키지는 데이터를 분리하고 처리한 다음 다시 결합하는 등 가장 필수적인 데이터 처리기능을 제공합니다.

#apply함수와 multi-core를 사용하는 함수를 이용하면, 매우 간단히 for loop를 사용하지 않고 빠르게, 

 때로는 매우 빠르게 처리하고 multi core를 활용해서 처리시간을 더욱더 단축가능합니다.


#plyr는 apply function에 기반하여 입력 및 출력변수 처리를 동일한 형식으로 모든 데이터 형식을 지원합니다.

#예를 들어, 이러한 방식으로 데이터를 투입->출력이 가능합니다.

 구분

data.frame 

list 

array 

data.frame 

 ddply

ldply 

 adply

 list

 dlply

llply

 alply

 array

 daply

 laply

 aaply


#즉 data.frame으로 투입한 것을 data.frame혹은 list, array형태로 결합하여 출력도 가능하며 반대로도 가능하다는 겁니다~

 이제 해볼까요


install.packages("plyr")

library(plyr)

data(baseball)
head(baseball)


           id      year stint team  lg   g   ab   r   h X2b X3b hr rbi sb cs bb so ibb
4   ansonca01 1871     1  RC1         25 120 29 39  11   3     0   16  6  2  2   1  NA
44  forceda01 1871     1  WS3        32 162 45 45  9   4     0  29  8  0  4  0  NA
68  mathebo01 1871     1  FW1         19  89 15 24   3   1     0  10   2   1  2  0  NA
99  startjo01 1871     1  NY2         33 161 35 58   5   1      1  34  4  2  3  0  NA
102 suttoez01 1871     1  CL1          29 128 35 45   3   7     3  23  3  1  1  0  NA
106 whitede01 1871     1  CL1          29 146 40 47   6   5      1  21  2  2  4  1  NA
    hbp sh sf gidp
4    NA NA NA   NA
44   NA NA NA   NA
68   NA NA NA   NA
99   NA NA NA   NA
102  NA NA NA   NA
106  NA NA NA   NA


#요런식으로 데이터가 나옵니다. baseball data는 1871년부터 2007년까지 15시즌 이상 참가한 1,228명의 미국 프로야구 타자 기록 data

# 100개의 row에 대해 연도별 row수 계산


bb_subset<-baseball[,c(1,2,5,13)]

head(bb_subset)


                id year lg rbi
4   ansonca01 1871     16
44  forceda01 1871     29
68  mathebo01 1871     10
99  startjo01 1871     34
102 suttoez01 1871     23
106 whitede01 1871     21


## ddply(데이터셋, 변수, function)

ddply(bb_subset[1:100,], ~year, nrow)

  year V1
1 1871  7
2 1872 13
3 1873 13
4 1874 15
5 1875 17
6 1876 15
7 1877 17

8 1878  3


ddply(bb_subset[1:100,], .(year), nrow)
  year V1
1 1871  7
2 1872 13
3 1873 13
4 1874 15
5 1875 17
6 1876 15
7 1877 17
8 1878  3


ddply(bb_subset[1:100,], "year", nrow)
  year V1
1 1871  7
2 1872 13
3 1873 13
4 1874 15
5 1875 17
6 1876 15
7 1877 17
8 1878  3


#이렇게 3가지 모두 다 동일한 결과가 나옵니다.


ddply(bb_subset, .(lg), c("nrow", "ncol"))
  lg  nrow ncol
1       65    4
2 AA   171    4
3 AL 10007    4
4 FL    37    4
5 NL 11378    4
6 PL    32    4
7 UA     9    4

​#lg변수에 대해서 nrow와 ncol 함수 적용. (여기서 또 보실것은 투입도 data.frame, 결과출력도 data.frame)

#summarise function은 기준 변수와 결과 값만을 표시합니다.

#여기서 rbi는 runs batted in 으로 타점을 의미합니다.

rbi_s<-ddply(bb_subset, "year", summarise, mean_rbi = mean(rbi, na.rm=TRUE))
head(rbi_s)
  year mean_rbi
1 1871 22.28571
2 1872 20.53846
3 1873 30.92308
4 1874 29.00000
5 1875 31.58824
6 1876 30.13333

# 즉 결과값은 연도별로 타점평균을 나타낸 것이죠~

# transform 옵션은 기준 데이터 마지막 column에 결과 값을 추가합니다. 동일 그룹에 속하는 row에 모두 같은 값을 표시합니다.


rbi_t<-ddply(bb_subset, "year", transform,  mean_rbi=mean(rbi, na.rm=TRUE))

head(rbi_t)
              id year lg rbi mean_rbi
1 ansonca01 1871     16 22.28571
2 forceda01 1871     29 22.28571
3 mathebo01 1871     10 22.28571
4 startjo01 1871     34 22.28571
5 suttoez01 1871     23 22.28571
6 whitede01 1871     21 22.28571


# 보시다시피 원래 있던 row 끝에 mean_rbi가 생겼죠.


# 서적에서는 plyr의 가장 큰 장점은 parallel처리가 가능하다는 점이지만 해당 문법에 익숙하지 않으면 데이터를 잘못 처리할 수도 있으니

 권장하지는 않는다고 하네요~


#그 다음 알아볼 것은 Data Table입니다.


-Data table은 Data Frame과 유사하지만 빠른 grouping, 빠른 ordering과 짧은 문장이 지원되어 data frame보다 좋다.

-특히 64bit 환경에서 RAM의 공간이 충분할 때 효율적이다.

-Windows 32bit RAM 8GB 이고 분석하는 데이터가 20GB 1개라면, 당연히 한 번에 로딩하려고 하면 RAM 8GB이기 때문에 읽어들여서 불필요한

 데이터를 제외하고 데이터 마트를 만드는 작업을 할 수 없을 뿐더러 sampling 자체를 할 수 없다. 무엇보다 32bit환경에서는 메모리를 4GB미만만 사용할 수 있다.

 메모리 주소 할당을 4GB까지만 할 수 있기 때문이다. 이러한 환경에서 20GB를 처리하려면 데이터 읽는 속도도 문제가 되므로 대안을 찾아야  한다.


-이를 위해서는 데이터를 한 번에 2GB씩 읽어들이기 위해 fread()함수를 이용해 몇 줄을 읽어 들일지를 지정해서 처리하면, 한 번에 읽어 들이는 속도도 매우

  빨라지고, 하나의 큰 파일을 쪼개어 읽을 수 있다. 결국 한 개를 읽어 들여서 rdata file로 저장하고, 메모리에서 지운 뒤 다음 파일을 읽어들이는 방식으로

  모두 읽어 들인다. 그 다음에 불필요한 내용을 지우고, 이를 모두 rbind()함수를 이용해 merge하면 된다. fread가 워낙 빠르게 처리되고 파일을 나누기 때문에

  RAM 부족으로 disk swappling이나 오류가 나는 일도 없다. 만약 한 번에 20GB를 이러한 환경에서 읽으려 한다면 memory allocation error가 표시되고,

  나누어서 read.csv를 한다해도 속도가 10분의 1 이하로 저하된다.

(거의 저자분은 데이터분석가이기 이전에 컴잘알..)

ex ) system.time(DT1 <- fread("2008.csv", nrows=1000000, skip=0))


# Data table사례


install.packages("data.table")

library(data.table)


2014년 월드컵 결과를 data frame으로 생성(수작업)


Final4<-data.table(team=c("GER","ARG","NED", "BRA", "GER", "BRA", "ARG"),
        stage=c(rep("F",2), rep("34",2), rep("QF", 4)),
        res=rep(c(1,0),4),
        score=c("1","0","0","3","7","1","0(4)", "0(2)"))

Final4


 Final4
   team stage res score
1:  GER     F     1     1
2:  ARG     F    0     0
3:  NED    34   1     0
4:  BRA    34   0     3
5:  GER    QF   1     7
6:  BRA    QF   0     1
7:  ARG    QF   1  0(4)
8:  NED    QF   0  0(2)


#축구좀 보신분이면 알겠죠? F=Final 34=3,4위전 QF=Quarter Final, 0(3) =승부차기


#이제 wine data를 불러와서 data table로 변경합니다.

install.packages("HDclassif")
library(HDclassif)
data(wine, package="HDclassif")

head(wine)

  class    V1   V2   V3   V4  V5   V6   V7   V8   V9  V10  V11  V12  V13
1     1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
2     1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
3     1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
4     1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
5     1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93  735
6     1 14.20 1.76 2.45 15.2 112 3.27 3.39 0.34 1.97 6.75 1.05 2.85 1450


dt_wine<-data.table(wine)

head(dt_wine)


   class    V1   V2   V3   V4  V5   V6   V7   V8   V9  V10  V11  V12  V13
1:     1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
2:     1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
3:     1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
4:     1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
5:     1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93  735
6:     1 14.20 1.76 2.45 15.2 112 3.27 3.39 0.34 1.97 6.75 1.05 2.85 1450


#이제 둘 간의 차이를 살펴보기 위해 tables()기능을 이용하여 크기, key, 용량을 비교합니다.

     NAME    NROW NCOL MB COLS                                             KEY
[1,] dt_wine  178       14  1    class,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13    
[2,] Final4     8         4  1     team,stage,res,score                                
Total: 2MB


#sapply()함수는simple apply로서 적용한 함수 값을 벡터나 행렬로 반환합니다.

sapply(dt_wine, class)

   class        V1        V2        V3        V4        V5        V6        V7 
"integer" "numeric" "numeric" "numeric" "numeric" "integer" "numeric" "numeric" 
       V8        V9       V10       V11       V12       V13 
"numeric" "numeric" "numeric" "numeric" "numeric" "integer"


sapply(Final4, class)
       team       stage         res       score 
"character" "character"   "numeric" "character"


#표면적으로는 둘 간의 차이를 알 수 없으나, data table에 key를 지정하여 차이를 확인

setkey(Final4, team)
Final4
   team stage res score
1:  ARG     F   0     0
2:  ARG    QF   1  0(4)
3:  BRA    34   0     3
4:  BRA    QF   0     1
5:  GER     F   1     1
6:  GER    QF   1     7
7:  NED    34   1     0
8:  NED    QF   0  0(2)


#data frame에서와는 다르게 표시되는 순서가 x에 의해 ordering 되어 있음. tables()에서 key가 x로 설정되어 있다.


-data frame은 하나하나 모든 자료를 비교하여 찾는 vector search방식으로 매우 비효율적이다.

 R은 이러한 방식으로 개발되어 왔다. data table에서 동일한 작업을 수행하면 약 100배 빠른데 이는 binary search를 하기 때문이다.

 1,440분(1일) 소요될 일이 15분 이내에 완료 된다면 매우 큰 차이다. 그러나 data table을 data frame처럼 사용하면 비슷해진다.

 즉, 무조건 data table을 사용한다고 빨라지는 것은 아니다



++ 기타 옵션

"GER"가 들어간 모든 데이터를 표시하고 싶은 경우와 첫 번째 결과, 마지막 결과, 모든 결과를 표시하는 option


Final4["GER",]
   team stage res score
1:  GER     F   1     1
2:  GER    QF   1     7

> Final4["GER", mult="last"]
   team stage res score
1:  GER    QF   1     7

> Final4["GER", mult="first"]
   team stage res score
1:  GER     F   1     1


> Final4["GER"]
   team stage res score
1:  GER     F   1     1
2:  GER    QF   1     7
 



#오늘은 데이터마트 - 2 번째 내용인 sqldf, plyr, data table에 대해서 알아봤는데요~

 다음 시간에는 데이터 가공에 대해서 알아보겠습니다~~


반응형

'R' 카테고리의 다른 글

23. Missing Data, 이상치  (0) 2018.11.21
22. 데이터 가공  (2) 2018.11.21
20. 데이터 마트 - 1  (2) 2018.11.21
19. 주성분 분석(Principal Component Analysis, PCA)  (5) 2018.11.21
18. 다차원척도법 (Multidimensional Scaling, MDS)  (4) 2018.11.21