안녕하세요. 오늘은 어제에 이어서 데이터마트 두 번째 파트를 알아보겠습니다.
오늘 해볼 내용 중 첫 번째인 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 |