R/개념 공부

[R] data.table package (wrangling)

연정양 2023. 1. 16.

R의 data.table로

wrangling을 연습하고 101 exercises를 했다. 

 

data.table은 용량이 큰 데이터를 다루는데 최적화되어 있다. 

chain[

           ][

          ]이 된다는 게 특징이다. (3.5GB 데이터를 불러오는 데 10초 정도 걸리는 듯)

시원시원하게 나오니까 재미는 있는데 조금 헷갈려서 손에 붙기까지 연습을 해야할 것 같다. 

 

사용해보기

1) install/import packages

install.packages("data.table")
library(data.table)

 

2) read in data using fread()

* data는 pisa.csv를 사용했으며 아래 링크에서 다운로드 가능하다.

 

4 Wrangling big data | Exploring, Visualizing, and Modeling Big Data with R

This book presents the materials for our NCME workshop on big data analysis in R.

okanbulut.github.io

pisa <- fread("pisa2015.csv", na.strings = "")

fread로 csv파일을 읽을 수 있다. 

 

3) see the class the object / how big it is

class(pisa)
#data.table data.frame

print(object.size(pisa), unit = "GB")
##3.5GB

pisa 데이터의 class를 확인했고, 3.5GB라는 걸 알 수 있다. 

 

4) 데이터 추출 및 csv 파일로 저장 (region6, random6)

region6 <- subset(pisa, CNT %in% c("United States", "Canada", "Mexico",
                                   "B-S-J-G (China)", "Japan", "Korea",
                                   "Germany", "Italy", "France", "Brazil",
                                   "Colombia", "Uruguay", "Australia",
                                   "New Zealand", "Jordan", "Israel", "Lebanon"))

#새로운 파일 만들기
fwrite(region6, file = "region6.csv")

random6 <- subset(pisa, CNT %in% c("Mexico", "Uruguay", "Japan",
                                   "Germany", "New Zealand", "Lebanon"))

fwrite(random6, file = "random6.csv")

파일로 저장은 fwrite ! fread, fwrite이니 외우기에는 쉽다

 

5) Using the i in data.table

data.table의 기본 문법은

df[i, j, by] 이다.

출처 : https://tinyurl.com/yyepwjpt

그리고 기존 R에서처럼 pisa$CNTRYID <- 이렇게 열을 지정하지 않아도 된다.

pisa[CNTRYID ~] 이런식으로 쓰는 게 가능하다. (아래 코드 참고)

pisa[CNTRYID == "Mexico" & ST063Q01NA == "Checked"]

pisa
pisa[10:25]

 

나라가 mexico이고 st~코드에 "checked"라고 답한 사람들의 데이터.

chain 을 활용하는 것도 가능하다. 

pisa[CNTRYID == "Mexico" & ST063Q01NA == "Checked"
     ][17:20]

head(pisa$CNTRYID)
pisa[order(CNTRYID, decreasing = TRUE)
     ][,
       head(CNTRYID)]

head도 쓸 수 있다.

아래 코드의 결과는 

> pisa[order(CNTRYID, decreasing = TRUE)
+      ][,
+        head(CNTRYID)]
[1] "Vietnam" "Vietnam" "Vietnam" "Vietnam" "Vietnam" "Vietnam"

나라명으로 내림차순 한 후에, (chain) head를 이용해서 맨 앞 6개 나라명 출력

 

**연습 문제

1. Subset all the Female students (ST004D01T) in Germany

pisa[CNTRYID == "Germany" & ST004D01T == "Female"]

2. How many female students are there in Germany?

pisa[CNTRYID == "Germany" & ST004D01T == "Female"
     ][, 
       table(CNTRYID)]
##3197명

 

5) Using the n in data.table

pisa[, list(CNTRYID)]

pisa[, .(CNTRYID)]
> pisa[, list(CNTRYID)]
                                       CNTRYID
     1:                                Albania
     2:                                Albania
     3:                                Albania
     4:                                Albania
     5:                                Albania
    ---                                       
519330: Argentina (Ciudad Aut처noma de Buenos)
519331: Argentina (Ciudad Aut처noma de Buenos)
519332: Argentina (Ciudad Aut처noma de Buenos)
519333: Argentina (Ciudad Aut처noma de Buenos)

두 개 코드 결과는 같다. 

 

6) 원하는 정보를 알고자 할 때 

#JAPAN과 MEXICO학생 중 체육을 수강한 수를 알고 싶을 때
pisa[CNTRYID %in% c("Mexico", "Japan"),
     table(ST063Q01NA)]
#checked 4283 not checked 9762

#"i get very tense when i study for a test"라고 답한 수
pisa[CNTRYID %in% c("Mexico", "Japan"),
     table(ST119Q04NA)]

pisa[CNTRYID %in% c("Mexico", "Japan"),
     .(tense = factor(ST118Q04NA, levels = c("Strongly disagree", "Disagree", "Agree", "Strongly agree")))
     ][,
       table(tense)
     ]

table을 chain으로 사용하면 간단히 확인이 가능하다. 

> pisa[CNTRYID %in% c("Mexico", "Japan"),
+      .(tense = factor(ST118Q04NA, levels = c("Strongly disagree", "Disagree", "Agree", "Strongly agree")))
+      ][,
+        table(tense)
+      ]
tense
Strongly disagree          Disagree             Agree 
             2904              5313              4074 
   Strongly agree 
             1760

 

7) 요약 통계 & plot

pisa[CNTRYID %in% c("Mexico", "Japan"),
     .(xbar = mean(SCIEEFF, na.rm = T),
       sigma = sd(SCIEEFF, na.rm = T),
       minimum = min(SCIEEFF, na.rm = T),
       med = median(SCIEEFF, na.rm = T),
       maximum = max(SCIEEFF, na.rm = T))]
###       xbar    sigma minimum     med maximum
###1: -0.08693672 1.216052 -3.7565 -0.0541  3.2775

sd, mean, minimum, median 등 요약 통계량을 확인할 수 있다. (위 코드에서는 mexico와 japan을 묶어서 연산했다.)

pisa[CNTRYID %in% c("Mexico", "Japan"),
     .(plot(y = SCIEEFF, x = JOYSCIE,
           col = rgb(red = 0, green = 0, blue = 0, alpha = 0.3)),
     xbar.joyscie = mean(JOYSCIE, na.rm = T))]

8) eat.dinner(ST078Q01NA) 변수 변환

#After leaving school did you : Eat dinner
table(pisa$ST078Q01NA)

#created a new variable(:= 가 새 변수를 만들어줌)
pisa[,
     "eat.dinner" := sapply(ST078Q01NA,
                            function(x) {
                              if (is.na(x)) NA
                              else if (x == "No") 0L
                              else if (x == "Yes") 1L
                            })
     ][,
       table(eat.dinner)]

방과후에 저녁 먹는다고 답한 사람을 TABLE로 확인하고, 

기존 변수를 식별하기 쉬운 eat.dinner 변수를 추가하여 값도 0, 1로 변환해줬다. 

> table(pisa$ST078Q01NA)

    No    Yes 
 23617 373131
eat.dinner
     0      1 
 23617 373131

NO -> 0 , Yes - > 1 로 변환됐다. 

이외에 답변이 Yes, no인 다른 변수들에 대해서도 변환을 진행한다. 

 

9) 변수 변환

bin.to.num <- function(x){
  if (is.na(x)) NA
  else if (x == "Yes") 1L
  else if (x == "No") 0L
}

#전부 0, 1 로 변환해서 알아볼 수 있는 변수로 변환함 (yes/no나오는 답을)

pisa[, `:=` 
     (female = ifelse(ST004D01T == "Female", 1, 0),
       sex = ST004D01T,
       
       # At my house we have ...
       desk = sapply(ST011Q01TA, bin.to.num),
       own.room = sapply(ST011Q02TA, bin.to.num),
       quiet.study = sapply(ST011Q03TA, bin.to.num),
       computer = sapply(ST011Q04TA, bin.to.num),
       software = sapply(ST011Q05TA, bin.to.num),
       internet = sapply(ST011Q06TA, bin.to.num),
       lit = sapply(ST011Q07TA, bin.to.num),
       poetry = sapply(ST011Q08TA, bin.to.num),
       art = sapply(ST011Q09TA, bin.to.num),
       book.sch = sapply(ST011Q10TA, bin.to.num),
       tech.book = sapply(ST011Q11TA, bin.to.num),
       dict = sapply(ST011Q12TA, bin.to.num),
       art.book = sapply(ST011Q16NA, bin.to.num))]

yes를 1, no를 0으로 변환하는 사용자 정의 함수를 만들어 적용했다. 

 

** 연습 문제 

  1. The computer and software variables that were created above ask a student whether they had a computer in their home that they can use for school work (computer) and whether they had educational software in their home (software). Find the proportion of students in the Germany and Uruguay that have a computer in their home or have educational software.
pisa[CNTRYID %in% c("Germany", "Uruguay"),
     .(computer = mean(computer, na.rm = TRUE),
       software = mean(software, na.rm = TRUE)),
     by = .(country = CNTRYID)]

 

10) using 'by' in data.tabel (groupby)

#집에 자신의 방이 있는 각 국가의 학생 비율
pisa[,
     .(mean(own.room, na.rm = TRUE)),
     by = .(CNTRYID)
     ][1:6,
     ]

#캐나다와 아이슬란드에서, 성별에 따라 시집을 가지고 있는 비율과
#과학에 즐거움을 느끼는 비율 비교
pisa[CNTRYID %in% c("Canada", "Iceland"),
     .(poetry = mean(poetry, na.rm = TRUE),
     enjoy = mean(JOYSCIE, na.rm = TRUE)),
     by = .(country = CNTRYID, sex = sex)]
   country    sex    poetry      enjoy
1:  Canada Female 0.3632105 0.29635781
2:  Canada   Male 0.3123878 0.40950018
3: Iceland Female 0.7280806 0.03583745
4: Iceland   Male 0.7011494 0.30316273

 

11) sorting

#내림차순(국가별)
pisa[,
     .(poetry = mean(poetry, na.rm = TRUE)),
     by = .(country = CNTRYID)
     ][order(poetry, decreasing = TRUE)
       ][1:6
         ]
              country    poetry
1:             Kosovo 0.8352507
2: Russian Federation 0.8045568
3:            Romania 0.8019434
4:            Georgia 0.7495615
5:    B-S-J-G (China) 0.7442052
6:            Estonia 0.7422718

국가별 시집을 갖고 있는 비율을 구하여 결과를 내림차순했다. 

 

12) fit a regression model

get.params <- function(cntry){
  mod <- lm(SCIEEFF ~ JOYSCIE + sex, cntry)
  est.params <- list(int = coef(mod)[[1]], enjoy.slope = coef(mod)[[2]], sex.slope = coef(mod)[[3]])
  return(est.params)
}

g7.params <- pisa[CNTRYID %in% c("Canada", "France", "Germany", "Italy",
                                 "Japan", "United Kingdom", "United States"),
                  get.params(.SD), 
                  by = .(CNTRYID)]
g7.params
          CNTRYID          int enjoy.slope  sex.slope
1:         Canada  0.009803357   0.4370945 0.21489577
2:         France -0.208698984   0.4760903 0.17743126
3:        Germany -0.019150031   0.4316565 0.17971821
4:          Italy -0.030880063   0.3309990 0.18831666
5:          Japan -0.353806055   0.3914385 0.04912039
6: United Kingdom  0.009711647   0.5182592 0.18981965
7:  United States  0.096920721   0.3907848 0.15022008

과학 효능감에 따른 학생들의 과학 점수를 예측하기 위한 회귀모델을 만들었고, 성별과 효능감에 따른 결과를 g7 나라에 따라 출력했다. 다중 회귀 분석 모델도 학습시킬 수 있으며, 결과는 intercept(int) 와 slope로 출력된다.

 

**연습 문제

  1. Calculate the proportion of students who have art in their home (art) and the average age (AGE) of the students by gender.
pisa[,
     .(art = mean(art, na.rm = TRUE),
       age = mean(AGE, na.rm = TRUE)),
     by = .(sex = sex)]

13) melting data

#학생 아이디 -> ID, 재택변수 하위 설정
pisa$id <- 1:nrow(pisa)
athome <- subset(pisa, select = c(id, desk:art.book))

athome.l <- melt(athome, 
                 id.vars = "id",
                 measure.vars = c("desk", "own.room", "quiet.study", "lit",
                                  "poetry", "art", "book.sch", "tech.book",
                                  "dict", "art.book"))
athome.l
#형식 추측
athome.guess <- melt(athome)
athome.guess
#잘못함. id가 문자형 벡터로 설정되었다면 올바르게 추측했을 테지만
#변수의 이름을 추측하도록 허용해서는 안 됨.

#와이드 형식으로 돌아가기
athome.w <- dcast(athome.l,
                  id ~ variable)
athome.w

 

14) using sparklyr

#sparklyr 
library("sparklyr")
library("dplyr")

sc <- spark_connect(master = "local")
#데이터 하위 집합 설정
pisa_sub <- subset(pisa, CNTRYID %in% c("Canada", "France", "Germany",
                                        "Italy", "Japan", "United Kingdom",
                                        "United States"),
                   select = c("DISCLISCI", "TEACHSUP", "IBTEACH", "TDTEACH",
                              "ENVAWARE", "JOYSCIE", "INTBRSCI", "INSTSCIE",
                              "SCIEEFF", "EPIST", "SCIEACT", "BSMJ", "MISCED",
                              "FISCED", "OUTHOURS", "SMINS", "TMINS",
                              "BELONG", "ANXTEST", "MOTIVAT", "COOPERATE",
                              "PERFEED", "unfairteacher", "HEDRES", "HOMEPOS",
                              "ICTRES", "WEALTH", "ESCS", "math", "reading",
                              "CNTRYID", "sex"))

#데이터 복사
pisa_tbl <- copy_to(sc, pisa_sub, overwrite = TRUE)

#독일 데이터 중 여학생만 보기
pisa_tbl %>%
  filter(CNTRYID == "Germany" & sex == "Female")

#과학 수업의 평균 징계 분위기를 국가 및 성별로 계산,
#성별이 아닌 국가별로 순서 변경
pisa_tbl %>%
  group_by(CNTRYID, sex) %>%
  summarize(ave_disclip = mean(DISCLISCI, na.rm = TRUE)) %>%
  arrange(CNTRYID, sex)

#함수를 새용한 새 변수 추가(가정 교육 자원, 가정 소유물)
pisa_tbl %>%
  mutate(totl_home = HEDRES + HOMEPOS) %>%
  group_by(CNTRYID) %>%
  summarize(xbar = mean(totl_home, na.rm = TRUE))

 

참고 링크 

빠른 처리를 지원하는 r의 data.table패키지

data.table: Extension of `data.frame` (r-project.org)

 

101 R data.table Exercises - Machine Learning Plus

 

101 R data.table Exercises - Machine Learning Plus

The data.table package in R is super fast when it comes to handling data. It has a syntax that reduces keystrokes while making R code easier to read. These set of exercises are designed to help you to oil your data brain through solving data manipulation e

www.machinelearningplus.com

-> 연습 문제 

 

'R > 개념 공부' 카테고리의 다른 글

[R] R/R studio 설치하기  (0) 2022.11.09

댓글