요인형 자료형을 문자형 대신 사용하게 되면 두가지 장점이 있는데, 가장 큰 장점은 아마도 오탈자로 생기는 새로운 유형 생성을 억제시킬 수 있다. 즉, 월은 12개월 밖에 존재하지 않는다. 따라서, 오탈자로 인해 범주가 추가로 생성되는 것을 사전에 방지할 수 있다. 그리고, 요인형을 자료형을 갖추게 되면 정렬을 쉽게 할 수도 있다.
일반 문자형 벡터을 정렬하게 되면 알파벳순으로 정렬하는데 무의미하다.
[1] "Apr" "Dec" "Jan" "Mar"
levels
인자로 수준을 정의하게 되면 오탈자로 인한 엉뚱한 범주가 추가되는 것을 방지하는 것과 더불어 정렬하게 되면 사람에게 좀더 의미있게 다가온다.
month_levels <- c(
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
y1 <- factor(x1, levels = month_levels)
y1
[1] Dec Apr Jan Mar
Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
[1] Jan Mar Apr Dec
Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
x2
문자열 벡터에 Jam
범주가 들어가 있는데 이를 levels
를 통해 범주를 설정하게 되면 오류를 방지할 수 있다. 특히, parse_factor
명령어를 사용하면 어디가 잘못되었는지 확인이 쉽다.
[1] Dec Apr <NA> Mar
Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
levels
를 생략하게 되면 기본디폴트 설정으로 알파벳순으로 범주를 생성하여 수준을 정해버린다.
[1] Dec Apr Jan Mar
Levels: Apr Dec Jan Mar
수준(levels) 순서를 맞추려면 unique()
혹은 fct_inorder()
함수를 사용한다.
[1] Dec Apr Jan Mar
Levels: Dec Apr Jan Mar
[1] Dec Apr Jan Mar
Levels: Dec Apr Jan Mar
[1] "Dec" "Apr" "Jan" "Mar"
요인(factor, 팩터) 자료형을 다룬다는 것은 다음을 의미한다. 하지만, Base R
과 tidyverse
두가지 방식이 있어 두가지 구문에 대한 이해도 필요하다.
forcats::fct_recode
, dplyr::recode
fct_relevel()
if_else()
case_when()
Base R에서 먼저 요인(factor)에 대한 데이터 분석 작업은 levels()
함수로 범주를 확인하고 summary()
함수로 시작된다.
library(tidyverse)
# download.file("https://raw.githubusercontent.com/dsscollection/factor-mgmt/master/data/GSScleaned.csv", destfile = "data/GSScleaned.csv")
GSS <- read_csv("https://raw.githubusercontent.com/dsscollection/factor-mgmt/master/data/GSScleaned.csv") %>%
mutate_if(is.character, as.factor)
levels(GSS$LaborStatus)
[1] "Keeping house" "No answer" "Other"
[4] "Retired" "School" "Temp not working"
[7] "Unempl, laid off" "Working fulltime" "Working parttime"
Keeping house No answer Other Retired
263 2 76 460
School Temp not working Unempl, laid off Working fulltime
90 40 104 1230
Working parttime NA's
273 2
요인 수준을 다른 형태로 조정하고 싶은데 levels(GSS$LaborStatus)[1:5]
앞에서 5개 범주는 그대로 둔 채로 나머지만 바꾸고자 하는 경우 다음과 같이 코드를 작성한다. 하지만, 이렇게 작성하는 것은 소프트웨어가 부서지기 쉬운(fragile software)의 전형적인 예가 된다.
GSS$LaborStatus_backup <- GSS$LaborStatus
levels(GSS$LaborStatus) <- c(levels(GSS$LaborStatus)[1:5],
"Temporarily not working",
"Unemployed, laid off",
"Working full time",
"Working part time")
summary(GSS$LaborStatus)
Keeping house No answer Other
263 2 76
Retired School Temporarily not working
460 90 40
Unemployed, laid off Working full time Working part time
104 1230 273
NA's
2
또다른 방식으로 다소 코드가 길어지기는 하지만 강건한 방식으로 다음과 같이 코드를 작성할 수 있다. 순서가 아닌 범주가 맞는 경우만 라벨을 바꿔주는 것이라 강건하지만 데이터프레임(GSS
)이 여러번, 변수(LaborStatus
)도 중복되어 그다지 읽기 즐거운 코드는 아니다.
GSS$LaborStatus <- GSS$LaborStatus_backup
GSS$LaborStatus <- as.character(GSS$LaborStatus)
GSS$LaborStatus[GSS$LaborStatus == "Temp not working"] <-
"Temporarily not working"
GSS$LaborStatus[GSS$LaborStatus == "Unempl, laid off"] <-
"Unemployed, laid off"
GSS$LaborStatus[GSS$LaborStatus == "Working fulltime"] <-
"Working full time"
GSS$LaborStatus[GSS$LaborStatus == "Working parttime"] <-
"Working part time"
GSS$LaborStatus <- factor(GSS$LaborStatus)
summary(GSS$LaborStatus)
Keeping house No answer Other
263 2 76
Retired School Temporarily not working
460 90 40
Unemployed, laid off Working full time Working part time
104 1230 273
NA's
2
dplyr
팩키지 recode()
함수, 혹은 forcats
팩키지 fct_recode()
를 사용해서 범주명을 다른 명칭으로 바꿀 수 있는데 코드가 깔끔한다.
GSS <- GSS %>%
mutate(tidyLaborStatus =
fct_recode(LaborStatus,
`Temp not working` = "Temporarily not working",
`Unempl, laid off` = "Unemployed, laid off",
`Working fulltime` = "Working full time",
`Working parttime ` = "Working part time"))
GSS %>%
count(tidyLaborStatus, sort=TRUE)
# A tibble: 10 x 2
tidyLaborStatus n
<fct> <int>
1 Working fulltime 1230
2 Retired 460
3 "Working parttime " 273
4 Keeping house 263
5 Unempl, laid off 104
6 School 90
7 Other 76
8 Temp not working 40
9 No answer 2
10 <NA> 2
trimws()
함수 사용
범주가 동일하나 공백문자(whitespace)가 포함된 경우 수작업을 일일이 손대는 대신에 trimws()
함수를 사용하면 수월히 범주를 잘 정리할 수 있다.
[1] "male" "male " "male " "male "
[1] "male"
그 다음으로 요인 수준 범주 순서를 바꾸는 것이 많이 사용되는 기능이다. Base R에서는 알파벳 순으로 요인 수준 범주를 기본디폴트 설정되어 있다.
Above average Average Below average Don't know
483 1118 666 21
Far above average Far below average No answer NA's
65 179 6 2
상기 순서를 다음과 같이 바꾸어 보자. 즉 소득에 대해서 순위형 범주로 순서를 넣어 정렬시키고자 한다.
Far above average → Above average → Average → Below Average → Far below average → Don’t know → No answer → NA’s
factor()
함수 내부에 levels =
인자조정을 통해서 범주 순서를 재조정시킬 수 있다. 이와 같이 구문을 작성할 경우 Average
의 경우 공백 때문에, Below Average
는 대소문자로 인해 잘못 범주 구분이 되어 숫자가 맞지 않는다.
GSS$BaseOpinionOfIncome <- factor(as.character(GSS$BaseOpinionOfIncome),
levels = c("Far above average", "Above average", "Average ", "Below Average",
"Far below average", "Don't know", "No answer"))
summary(GSS$BaseOpinionOfIncome )
Far above average Above average Average Below Average
65 483 0 0
Far below average Don't know No answer NA's
179 21 6 1786
소득에 대해서 순위형 범주로 순서를 넣어 정렬시키고자 할 때 다음과 같이 엽기(?)적으로 코딩을 할 수 있다.
원데이터 범주 순서
Above average Average Below average Don't know
483 1118 666 21
Far above average Far below average No answer NA's
65 179 6 2
엽기(?)적 범주 순서
Far above average Above average Average Below average
483 1118 666 21
Far below average Don't know No answer NA's
65 179 6 2
원데이터 범주 순서
Above average Average Below average Don't know
483 1118 666 21
Far above average Far below average No answer NA's
65 179 6 2
tidyverse
로 깔끔한 범주 순서 정리
GSS <- GSS %>%
mutate(tidyOpinionOfIncome =
fct_relevel(OpinionOfIncome,
"Far above average",
"Above average",
"Average",
"Below average",
"Far below average"))
summary(GSS$tidyOpinionOfIncome)
Far above average Above average Average Below average
65 483 1118 666
Far below average Don't know No answer NA's
179 21 6 2
범주형 변수를 다룰 때 많이 고려해야 하는 것 중에 하나가 요인 범주 수준을 줄이는 것이다. 예를 들어, 결혼 상태에 대한 다양한 경우의 수가 존재한다. 이를 혼인(Married
)과 비혼(Not Married
)으로 범주를 조정하고자 하는 작업을 살펴보자.
MaritalStatus
BaseMarital
Married
), 비혼(Not Married
) Divorced Married Never married No answer Separated
411 1158 675 4 81
Widowed NA's
209 2
levels(GSS$BaseMarital) <- c("Not Married", "Married",
"Not Married", "No answer",
"Not Married", "Not Married", NA)
summary(GSS$BaseMarital)
Not Married Married No answer NA's
1376 1158 4 2
tidyverse
로 깔끔하게 범주를 재지정하면 다음과 같다. 물론 dplyr
팩키지 recode()
함수를 사용한다.
GSS <- GSS %>%
mutate(tidyMaritalStatus = recode(MaritalStatus,
Divorced = "Not Married",
`Never married` = "Not Married",
Widowed = "Not Married",
Separated = "Not Married"))
summary(GSS$tidyMaritalStatus)
Not Married Married No answer NA's
1376 1158 4 2
범주가 많은 경우 이를 줄이거나, 숫자를 일정 범위로 묶어 범주화하는 경우가 많다. 숫자형 변수지만 값에 “No answer” 혹은 “89 or order”와 같이 문자가 들어 있는 경우 전체가 문자형이 되고 Base R에서는 요인형 변수로 전환된다.
[1] "18.000000" "19.000000" "20.000000" "21.000000" "22.000000"
[6] "23.000000" "24.000000" "25.000000" "26.000000" "27.000000"
[11] "28.000000" "29.000000" "30.000000" "31.000000" "32.000000"
[16] "33.000000" "34.000000" "35.000000" "36.000000" "37.000000"
[21] "38.000000" "39.000000" "40.000000" "41.000000" "42.000000"
[26] "43.000000" "44.000000" "45.000000" "46.000000" "47.000000"
[31] "48.000000" "49.000000" "50.000000" "51.000000" "52.000000"
[36] "53.000000" "54.000000" "55.000000" "56.000000" "57.000000"
[41] "58.000000" "59.000000" "60.000000" "61.000000" "62.000000"
[46] "63.000000" "64.000000" "65.000000" "66.000000" "67.000000"
[51] "68.000000" "69.000000" "70.000000" "71.000000" "72.000000"
[56] "73.000000" "74.000000" "75.000000" "76.000000" "77.000000"
[61] "78.000000" "79.000000" "80.000000" "81.000000" "82.000000"
[66] "83.000000" "84.000000" "85.000000" "86.000000" "87.000000"
[71] "88.000000" "89 or older" "No answer"
Base R에서 먼저 as.numeric
으로 자료를 변환시키고 나서 ifelse()
함수를 사용해서 범주화한다.
Base R 범주 줄이는 방법
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
18.00 34.00 49.00 48.71 61.00 88.00 30
GSS$BaseAge <- ifelse(GSS$BaseAge < 65, "18-64", "65 and up")
GSS$BaseAge <- factor(GSS$BaseAge)
summary(GSS$BaseAge)
18-64 65 and up NA's
2011 499 30
tidyverse
범주 줄이는 방법
GSS <- GSS %>%
mutate(tidyAge = parse_number(as.character(Age))) %>%
mutate(tidyAge = if_else(tidyAge < 65, "18-65", "65 and up"),
tidyAge = factor(tidyAge))
summary(GSS$tidyAge)
18-65 65 and up NA's
2011 518 11
변수 조건에 따라 범주를 다시 재그룹화시키거나 숫자를 적당한 범위로 나눌 경우 case_when()
함수를 사용한다. 먼저 적당한 데이터를 생성시킨다. mosaic
팩키지에 HELPmiss
데이터셋이 포함되어 있다. 성별로 음주량에 대한 측정데이터가 담겨있다.
sex
: 성별i1
: 지난 1달동안 하루 평균 섭취 음주량i2
: 지난 1달동안 하루 평균 최대 섭취 음주량age
: 나이library(mosaic)
library(mosaicData)
data(HELPmiss)
HELPsmall <- HELPmiss %>%
mutate(i1 = ifelse(id == 1, NA, i1)) %>% # make one value missing
select(sex, i1, i2, age)
head(HELPsmall, 5)
sex i1 i2 age
1 male NA 26 37
2 male 56 62 37
3 male 0 0 26
4 female 5 5 39
5 male 10 13 32
Base R 파생 범주형 변수생성
# create empty vector for new variable
drinkstat <- character(length(HELPsmall$i1))
# create abstinent group
drinkstat[HELPsmall$i1 == 0] = "abstinent"
# create moderate group
drinkstat[(HELPsmall$i1>0 & HELPsmall$i1<=1 & # find those with moderate levels
HELPsmall$i2 <= 3 & HELPsmall$sex == "female") |
(HELPsmall$i1 > 0 & HELPsmall$i1 <= 2 &
HELPsmall$i2 <= 4 & HELPsmall$sex == "male")] = "moderate"
# create highrisk group
drinkstat[((HELPsmall$i1 > 1 | HELPsmall$i2 > 3) & HELPsmall$sex == "female") |
((HELPsmall$i1 > 2 | HELPsmall$i2 > 4) & HELPsmall$sex == "male")] = "highrisk"
# account for missing values
is.na(drinkstat) <- is.na(HELPsmall$i1) | is.na(HELPsmall$i2) |
is.na(HELPsmall$sex)
drinkstat <- factor(drinkstat)
table(drinkstat, useNA = "always")
drinkstat
abstinent highrisk moderate <NA>
69 372 28 1
tidyverse
파생 범주형 변수생성
HELPsmall <- HELPsmall %>%
mutate(drink_stat = case_when( i1 == 0 ~ "abstinent",
i1 <= 1 & i2 <= 3 & sex == 'female' ~ "moderate",
i1 <= 1 & i2 <= 3 & sex == 'male' & age >= 65 ~ "moderate",
i1 <= 2 & i2 <= 4 & sex == 'male' ~ "moderate",
is.na(i1) ~ "missing", # cant put NA in place of "missing"
TRUE ~ "highrisk"
))
HELPsmall %>%
group_by(drink_stat) %>%
dplyr::count()
# A tibble: 4 x 2
# Groups: drink_stat [4]
drink_stat n
<chr> <int>
1 abstinent 69
2 highrisk 372
3 missing 1
4 moderate 28
forcats
팩키지 3정성적 변수와 더불어 데이터 분석과 모형개발에서 필히 익숙하게 다뤄야 하는 데이터가 범주형 데이터다. 과거 install.packages("tidyverse")
, install.packages("forcats")
명령어를 통해서 library(tidyverse)
, library(forcats)
를 통해서 명시적으로 팩키지를 불러와서 적재했으나, 이제는 별도로 설치해서 적재할 필요는 없다. 이유는 현시점 기준 tidyverse
의 핵심 일원이 되었기 때문이다.
범주형 데이터를 처리하는 요인(factor) 자료형을 이해하고, tidyverse
생태계에서 범주형 요인을 담당하는 forcats
팩키지를 통해서 범주형 데이터를 자유자재로 다룰 수 있는 역량을 익히자.
미국 시카고 대학 독립적인 연구기관 NORC에서 장기적으로 수행하는 설문조사 GSS(General Social Survey) 데이터를 실습자료로 활용한다. tidyverse
를 도서관(library)에서 꺼내와서 메모리에 올리게 되면 gss_cat
데이터가 포함되어 있다.
forcats
팩키지에 포함되어 있는 데이터로 원하는 경우 ? gss-cat
명령어를 통해 데이터에 대한 자세한 내용을 확인할 수 있다. gss_cat
데이터프레임에 포함되어 있는 race
변수는 is.factor()
함수로 요인형으로 이를 막대그래프로 표현해보자.
ggplot2
에서 기본디폴트 설정으로 어떤 값도 없는 수준은 자동으로 drop
시킨다. 만약 변수에 포함된 모든 수준을 보려면 drop=FALSE
를 넣어 명시적으로 작성한다.
** 수준(level) 자동 제거**
막대그래프의 경우 fct_infreq()
함수를 사용해서 오름 빈도수로 정렬이 가능하다: fct_rev()
와 조합해서 사용해도 좋다. gss_cat
데이터에서 요인 수준을 조정하는데 빈도순으로 오름차순으로 요인을 fct_infreq()
로 정렬하고 나서, fct_rev()
함수로 빈도수가 높은 순부터 역으로 요인 수준을 정렬하고 이를 시각화한다.
범주형 변수 결혼상태(marital
)는 총 6개 수준이 있는데 빈도수가 다르기 때문에 가장 높은 빈도수부터 낮은 빈도수를 갖는 결혼상태로 정렬한 후에 ggplot()
으로 막대그래프를 작성한다.
요인과 관련되어 가장 많이 사용하는 기능은 다음과 같다.
수준을 조정하지 않는 경우 전반적인 패턴을 살펴보기 어렵다. 하지만, 수준 순서를 재조장하게 되면 가독성을 훨씬 높일 수 있다. fct_reorder()
함수를 사용하는데 인자가 세개 필요하다.
f
, 수준을 변경하려는 요인명x
, 수준을 변경하는데 사용되는 숫자 벡터에fun
, f
값 각각에 대해 다수 값이 있는 경우 이를 요약할 함수, 기본디폴트 함수는 중위수를 산출하는 함수 median
.** 수준(level) 순서를 변경전**
** 수준(level) 순서를 가독성 높게 적용**
먼저 mutate()
로 요인 수준을 뽑아내서 수준을 재조정한 후에 aes()
함수에서 넣는 것도 가능합니다.
relig %>%
mutate(relig = fct_reorder(relig, tvhours)) %>%
ggplot(aes(tvhours, relig)) +
geom_point()
종교별 TV 시청시간에 대한 실제품으로 사용으로 될 수 있도록 마무리를 해보자. 이를 위해서 geom_segment()
함수를 활용하여 직선을 추가한다. 그리고 기타 색상과 점크기를 조정하고 x축과 y축에 대한 라벨과 제목을 추가한다.
ggplot(relig, aes(tvhours, fct_reorder(relig, tvhours))) +
geom_point(color="red", size=3.5, alpha=0.7) +
# geom_segment(
# aes(x = 0,
# y=fct_reorder(relig, tvhours, desc=TRUE),
# xend = tvhours,
# yend = fct_reorder(relig, tvhours, desc=TRUE)),
# color = "pink",
# linetype = "dashed",
# size = 1) +
theme_minimal(base_family = "NanumGothic") +
labs(x="TV 시청시간", y="종교", title="종교별 TV 시청시간")
요인변수 내부 수준을 바꾸거나 뭉개서 합치는 기능이 자주 사용되고 있다. 먼저 범주형변수 내부 수준(level)의 명칭을 변경사흔데 fct_recode()
함수를 사용한다. 특히, 시각화를 할 때 범주형변수 수준이 길거나 가독성이 떨어지는 경우 요인변수 수준명칭을 바뀌는 것이 필수적이다.
fct_recode()
함수는 명시적으로 언급되지 않는 수준을 그대로 두고, 존재하지 않는 수준을 우연히 언급할 경우 경고 메시지를 띄운다.
# A tibble: 10 x 2
partyid n
<fct> <int>
1 No answer 154
2 Don't know 1
3 Other party 393
4 Strong republican 2314
5 Not str republican 3032
6 Ind,near rep 1791
7 Independent 4119
8 Ind,near dem 2499
9 Not str democrat 3690
10 Strong democrat 3490
요인 수준 명칭 변경 사례
gss_cat %>%
mutate(partyid = fct_recode(partyid,
"Republican, strong" = "Strong republican",
"Republican, weak" = "Not str republican",
"Independent, near rep" = "Ind,near rep",
"Independent, near dem" = "Ind,near dem",
"Democrat, weak" = "Not str democrat",
"Democrat, strong" = "Strong democrat"
)) %>%
count(partyid)
# A tibble: 10 x 2
partyid n
<fct> <int>
1 No answer 154
2 Don't know 1
3 Other party 393
4 Republican, strong 2314
5 Republican, weak 3032
6 Independent, near rep 1791
7 Independent 4119
8 Independent, near dem 2499
9 Democrat, weak 3690
10 Democrat, strong 3490
요인 수준 변경시 경고 사례
gss_cat %>%
mutate(partyid = fct_recode(partyid,
"Republican, strong" = "Strong republican",
"Republican, weak" = "Not str republican",
"Independent, near rep" = "Ind,near rep",
"Independent, near dem" = "Ind,near dem",
"Democrat, weak" = "Not str democrat",
"Democrat, strong" = "Strong democrat",
"Other" = "No answer",
"Other" = "Don't know",
"Other" = "Other party"
)) %>%
count(partyid)
# A tibble: 8 x 2
partyid n
<fct> <int>
1 Other 548
2 Republican, strong 2314
3 Republican, weak 3032
4 Independent, near rep 1791
5 Independent 4119
6 Independent, near dem 2499
7 Democrat, weak 3690
8 Democrat, strong 3490
fct_collapse()
함수는 fct_recode()
함수의 변종으로 매우 유용하다. 범주형 데이터를 분석할 경우 범주형 변수의 수준을 합쳐야 하는 경우가 종종 발생된다. 충청북도와 충청남도를 합쳐 충청도로 하거나 충청도의 대전광역시와 세종특별자치시를 충청도에 포함시키는 경우도 이런 유형의 작업에 해당된다.
fct_collapse()
함수에 합쳐질 수준을 정의하면 명시적으로 수준을 보고좋게 정리할 수 있다.
gss_cat %>%
mutate(partyid = fct_collapse(partyid,
other = c("No answer", "Don't know", "Other party"),
rep = c("Strong republican", "Not str republican"),
ind = c("Ind,near rep", "Independent", "Ind,near dem"),
dem = c("Not str democrat", "Strong democrat")
)) %>%
count(partyid)
# A tibble: 4 x 2
partyid n
<fct> <int>
1 other 548
2 rep 5346
3 ind 8409
4 dem 7180
복잡한 데이터셋을 다룰 경우 처리할 변수가 상당히 많은 경우가 있다. 이런 경우 fct_lump()
함수가 유용하다. 범주내 수준에 작은 값이 할당된 경우 이를 합쳐 의미있는 수준에 대한 값이 되도록 만드는 기능을 수행한다. n=10
으로 인자값을 넣어주면 해당 변수에 수준이 10개로 지정된다. 상황에 따라서는 fct_lump()
함수에 인자로 prob=0.1
와 같이 확률이 10% 미만이 되는 것은 모두 기타에 넣는 것도 가능하다. other_level="기타"
를 넣어 합쳐지는 수준에 대한 명칭을 별도로 지정하는 것도 가능하다.
gss_cat %>%
mutate(relig = fct_lump(relig, n = 10, other_level = "기타" )) %>%
count(relig, sort = TRUE) %>%
print(n = Inf)
# A tibble: 11 x 2
relig n
<fct> <int>
1 Protestant 10846
2 Catholic 5124
3 None 3523
4 Christian 689
5 Jewish 388
6 기타 234
7 Other 224
8 Buddhism 147
9 Inter-nondenominational 109
10 Moslem/islam 104
11 Orthodox-christian 95
Wrangling categorical data in R에 포함된 GSS 데이터셋이 요인(factor) 자료구조를 다루는데 마치 mtcars
, iris
, titanic
, mnist
와 같은 역할을 하고 있다.
원데이터는 파일 크기가 20 메가바이트를 넘고 원본 데이터는 캐글 Kaggle ML and Data Science Survey, 2017 설문조사 학습플랫폼 설문문항로 전형적인 설문문항의 한 사례로 볼 수 있다.
데이터를 가져와서 특정 변수만 추출하고 select(contains("LearningPlatformUsefulness"))
, 폭넓은 자료형태(wide)를 긴 자료형태(long)로 변형시킨다. 그리고 나서 mutate_if()
함수로 문자형자료형을 요인형자료형으로 변형시키고 나서 데이터를 정제시킨다.
# 0. 환경설정 -----
library(tidyverse)
library(extrafont)
loadfonts()
# 1. 데이터 -----
# kaggle_dat <- read_csv("https://raw.githubusercontent.com/bkaniskan/KaggleDSsurvey/master/data/multipleChoiceResponses.csv")
kaggle_dat <- read_csv("https://github.com/mbzhuang/Kaggle-ML-and-Data-Science-Survey-Analysis/blob/master/RawData/multipleChoiceResponses.csv?raw=true")
## 1.1. 데이터 정제 -----
kaggle_df <- kaggle_dat %>%
select(contains("LearningPlatformUsefulness")) %>%
gather(platform, value) %>%
mutate_if(is.character, as.factor) %>%
mutate(platform = str_remove(platform, "LearningPlatformUsefulness")) %>%
filter(!is.na(value))
플랫폼별로 빈도수를 조사한 후에 요인형 변수를 수준(level) 조정을 하고 시각화가 깔끔하게 될 수 있도록 라벨명을 조정한다.
## 1.2. 요인형 자료 -----
kaggle_cat_df <- kaggle_df %>%
group_by(platform) %>%
count(value) %>%
add_count(platform, wt=n, name="nn") %>%
mutate(pcnt = n / nn) %>%
mutate(value = fct_relevel(value, "Not Useful", "Somewhat useful", "Very useful")) %>%
mutate(value = case_when(
str_detect(value, "Somewhat") ~ "Somewhat",
str_detect(value, "Not") ~ "Not useful",
str_detect(value, "Very") ~ "Very useful"
))
작은 창에 각 학습플랫폼별로 내용을 잘 나타날 수 있도록 시각화한다.
# 2. 탐색적 데이터 분석 -----
## 2.1. 시각화 -----
kaggle_cat_df %>%
ggplot(aes(x=value, y=pcnt, group=platform)) +
geom_line() +
geom_point() +
facet_wrap(~platform) +
theme_minimal(base_family = "NanumGothic") +
scale_y_continuous(labels = scales::percent) +
labs(x="", y="응답 비율", title="캐글 설문조사",
subtitle = "학습 플랫폼별 유용성 설문",
caption = "자료출처: Kaggle ML and Data Science Survey, 2017(https://www.kaggle.com/kaggle/kaggle-survey-2017)")