👏지난 번 포스팅(> 바로가기)에서 NA
값을 처리해주었던 videoGames
파일을 활용하여 dlookr
패키지의 데이터 진단 작업을 해보겠습니다.
# 데이터 탐색에 필요한 dlookr과 tidyverse를 불러왔습니다.
> library(dlookr)
> library(tidyverse)
# NA값을 처리해주는 인자(na.strings)를 포함하여 데이터를 불러왔고
# videoGames에 저장하였습니다.
> videoGames <- read.csv(file = "Video_Games_Sales_as_at_22_Dec_2016.csv",
+ na.strings = c("", " ", NA))
👉 dlookr::diagnose(데이터)
는 데이터에 포함된 모든 변수의 타입, 결측값, 고유값을 확인할 수 있는 함수입니다. 데이터를 확인해보니, 결측값이 포함된 변수가 있네요.
> dlookr::diagnose(videoGames)
# A tibble: 16 x 6
variables types missing_count missing_percent unique_count unique_rate
<chr> <chr> <int> <dbl> <int> <dbl>
1 Name factor 2 0.0120 11563 0.692
2 Platform factor 0 0 33 0.00197
3 Year_of_Release factor 0 0 41 0.00245
4 Genre factor 2 0.0120 15 0.000897
5 Publisher factor 0 0 583 0.0349
6 NA_Sales numeric 0 0 402 0.0240
7 EU_Sales numeric 0 0 307 0.0184
8 JP_Sales numeric 0 0 244 0.0146
9 Other_Sales numeric 0 0 155 0.00927
10 Global_Sales numeric 2 0.0120 630 0.0377
11 Critic_Score integer 8582 51.3 83 0.00496
12 Critic_Count integer 8582 51.3 107 0.00640
13 User_Score factor 6704 40.1 97 0.00580
14 User_Count integer 9129 54.6 889 0.0532
15 Developer factor 6623 39.6 1697 0.102
16 Rating factor 6769 40.5 9 0.000538
👉 먼저 결측값이 2개정도로 작은 Name, Genre, Gloval_Sales
변수는 직접 살펴보았습니다.
# which 함수를 활용하면 변수의 na값 행 위치를 알 수 있습니다.
# 660행과 14247 행에 있습니다.
> which(is.na(videoGames$Name))
[1] 660 14247
# 데이터 명[행, 열]로 데이터 슬라이싱하여 보니, Name, Genre는 동일한 행에서 누락이 되었습니다.
# 따라서 Genre는 따로 확인하지 않겠습니다.
> videoGames[c(660, 14247), ]
Name Platform Year_of_Release Genre Publisher NA_Sales EU_Sales JP_Sales
660 <NA> GEN 1993 <NA> Acclaim Entertainment 1.78 0.53 0.00
14247 <NA> GEN 1993 <NA> Acclaim Entertainment 0.00 0.00 0.03
Other_Sales Global_Sales Critic_Score Critic_Count User_Score User_Count Developer Rating
660 0.08 2.39 NA NA <NA> NA <NA> <NA>
14247 0.00 0.03 NA NA <NA> NA <NA> <NA>
# Gloval_Sales 변수의 결측치 위치를 확인하여 데이터 슬라이싱을 통해 확인해보니
# 11617행은 이름도 제대로 확인이 안되고 NA가 많습니다.
> which(is.na(videoGames$Global_Sales))
[1] 11617 13587
> videoGames[c(11617, 13587), ]
Name
11617 Boku no Natsuyasumi 3: Hokkoku Hen: Chiisana Boku no Dai Sougen<e2>\u0080<8b>,PS3
13587 B's-LOG Party<e2>솵,PSP
Platform Year_of_Release Genre Publisher NA_Sales EU_Sales JP_Sales
11617 2007 Adventure Sony Computer Entertainment 0 0 0.08 0
13587 2010 Adventure Idea Factory 0 0 0.04 0
Other_Sales Global_Sales Critic_Score Critic_Count User_Score User_Count Developer Rating
11617 0.08 NA NA NA <NA> NA <NA> <NA>
13587 0.04 NA NA NA <NA> NA <NA> <NA>
# 따라서, 660, 11617, 13587, 14247행 모두 제외하겠습니다.
> dim(videoGames) # 제외 이전 데이터 행렬의 수를 확인하고
[1] 16719 16
> videoGames <- videoGames[-c(660, 14247, 11617, 13587), ] # 제외처리한 후
> dim(videoGames) # 다시 데이터 행렬의 수를 확인하여 잘못된 부분이 없는 점 체크하였습니다.
[1] 16715 16
👉 그리고 다시 dlookr::diagnose(데이터)
를 통해 결측값이 있는 변수만 결측값 많은 순서대로 정렬하여 살펴보았습니다.
# 먼저 위 진단 내용을 보면 User_Score가 수치형 변수인데 factor로 분류되어
# 강제로 수치형으로 변환해주었습니다.
videoGames$User_Score <- as.integer(videoGames$User_Score)
# 그리고 데이터를 보니, Use_Score의 Type이 잘 변환 되어 있고
# 결측치가 있는 변수 대부분 비율이 너무 높습니다.
# 삭제할 수도 있지만 우선은 그대로 두기러 합니다.
> videoGames %>%
+ dlookr::diagnose() %>%
+ dplyr::filter(missing_count > 0) %>%
+ dplyr::arrange(desc(missing_count))
# A tibble: 6 x 6
variables types missing_count missing_percent unique_count unique_rate
<chr> <chr> <int> <dbl> <int> <dbl>
1 User_Count integer 9125 54.6 889 0.0532
2 Critic_Score integer 8578 51.3 83 0.00497
3 Critic_Count integer 8578 51.3 107 0.00640
4 Rating factor 6765 40.5 9 0.000538
5 User_Score integer 6700 40.1 97 0.00580
6 Developer factor 6619 39.6 1697 0.102
👉 데이터 진단을 조금 더 세분화 하여 출력 해보겠습니다.
1) 수치형 - dlookr::diagnose_numeric(데이터)
# 아래와 같이 확인해보니 psych::describe() 나 동일패키지 내 함수인 dlookr::describe()와 비슷하지만,
# dlookr::diagnose_numeric()은 zero/minus/이상치/Q1/Q3 를 더 제공해주어
# 데이터 무결성을 파악하기에 좋습니다.
> dlookr::diagnose_numeric(videoGames)
# A tibble: 9 x 10
variables min Q1 mean median Q3 max zero minus outlier
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <int> <int> <int>
1 NA_Sales 0 0 0.263 0.08 0.24 41.4 4508 0 1686
2 EU_Sales 0 0 0.145 0.02 0.11 29.0 5871 0 2060
3 JP_Sales 0 0 0.0776 0 0.04 10.2 10514 0 2434
4 Other_Sales 0 0 0.0473 0.01 0.03 10.6 6601 0 2242
5 Global_Sales 0.01 0.06 0.534 0.17 0.47 82.5 0 0 1891
6 Critic_Score 13 60 69.0 71 79 98 0 0 83
7 Critic_Count 3 12 26.4 21 36 113 0 0 251
8 User_Score 1 66 75.7 78 90 96 0 0 189
9 User_Count 4 10 162. 24 81 10665 0 0 1080
2) 범주형 - dlookr::diagnose_category(데이터)
# 변수 내 각 집단별로, 전체 변수의 수/집단별 수/비율/순위를 보여줍니다.
> dlookr::diagnose_category(videoGames)
# A tibble: 77 x 6
variables levels N freq ratio rank
<chr> <fct> <int> <int> <dbl> <int>
1 Name Need for Speed: Most Wanted 16715 12 0.0718 1
2 Name FIFA 14 16715 9 0.0538 2
3 Name LEGO Marvel Super Heroes 16715 9 0.0538 3
4 Name Madden NFL 07 16715 9 0.0538 4
5 Name Ratatouille 16715 9 0.0538 5
6 Name Angry Birds Star Wars 16715 8 0.0479 6
7 Name Cars 16715 8 0.0479 7
8 Name FIFA 15 16715 8 0.0479 8
9 Name FIFA Soccer 13 16715 8 0.0479 9
10 Name Lego Batman 3: Beyond Gotham 16715 8 0.0479 10
# 데이터에서 변수와 집단(level)이 너무 많은 경우, dplyr의 filter 함수를 활용하여 ratio를 한정해서 확인해볼 수도 있습니다.
> videoGames %>%
+ dlookr::diagnose_category() %>%
+ dplyr::filter(ratio > 0.3)
# A tibble: 55 x 6
variables levels N freq ratio rank
<chr> <fct> <int> <int> <dbl> <int>
1 Platform PS2 16715 2161 12.9 1
2 Platform DS 16715 2152 12.9 2
3 Platform PS3 16715 1330 7.96 3
4 Platform Wii 16715 1320 7.90 4
5 Platform X360 16715 1262 7.55 5
6 Platform PSP 16715 1208 7.23 6
7 Platform PS 16715 1197 7.16 7
8 Platform PC 16715 974 5.83 8
9 Platform XB 16715 824 4.93 9
10 Platform GBA 16715 822 4.92 10
# … with 45 more rows
# 혹은 diagnose_category에 top 인자를 추가하여 rank 5위까지만 볼 수 있습니다.
> videoGames %>%
+ dlookr::diagnose_category(top = 5)
# A tibble: 35 x 6
variables levels N freq ratio rank
<chr> <fct> <int> <int> <dbl> <int>
1 Name Need for Speed: Most Wanted 16715 12 0.0718 1
2 Name FIFA 14 16715 9 0.0538 2
3 Name LEGO Marvel Super Heroes 16715 9 0.0538 3
4 Name Madden NFL 07 16715 9 0.0538 4
5 Name Ratatouille 16715 9 0.0538 5
6 Platform PS2 16715 2161 12.9 1
7 Platform DS 16715 2152 12.9 2
8 Platform PS3 16715 1330 7.96 3
9 Platform Wii 16715 1320 7.90 4
10 Platform X360 16715 1262 7.55 5
# … with 25 more rows
3) 이상치 - dlookr::diagnose_outier(데이터)
# 이상치 비율이 높은 순서대로 정렬하였습니다.
# 모든 변수에서 이상치가 있고 전체평균(with_mean)과 이상치 제외 평균(without_mean)의 차이가 큰 변수도 더러 보입니다.
> videoGames %>%
+ dlookr::diagnose_outlier() %>%
+ dplyr::arrange(desc(outliers_ratio))
variables outliers_cnt outliers_ratio outliers_mean with_mean without_mean
1 JP_Sales 2434 14.561771 0.4709408 0.07761173 0.01057419
2 Other_Sales 2242 13.413102 0.2672346 0.04733832 0.01327437
3 EU_Sales 2060 12.324260 0.8729175 0.14502782 0.04271102
4 Global_Sales 1891 11.313192 2.9183554 0.53351840 0.22930046
5 NA_Sales 1686 10.086748 1.6170700 0.26328687 0.11141526
6 User_Count 1080 6.461262 928.7583333 162.22990777 35.06390169
7 Critic_Count 251 1.501645 82.1354582 26.36082094 24.58559472
8 User_Score 189 1.130721 21.1693122 75.72920619 76.77864848
9 Critic_Score 83 0.496560 26.1686747 68.96767851 69.40874100
# 전체 평균(with_mean)과 이상치 평균(outliers_mean) 비율의 차이가 큰 것이 있는지 확인해보았습니다.
# 새로운 이상치 기준 변수를 outliersN 의 이름으로 추가하였고 ouliersN의 비율이 1 이상이되 큰 순서대로 내림차순 하였습니다.
# 비율이 너무 큰 경우, 이상치를 제거하거나 대체하는 것이 좋습니다.
> videoGames %>%
+ dlookr::diagnose_outlier() %>%
+ dplyr::mutate(outliersN = outliers_mean / with_mean) %>%
+ dplyr::arrange(desc(outliersN)) %>%
+ dplyr::filter(outliersN > 1)
variables outliers_cnt outliers_ratio outliers_mean with_mean without_mean outliersN
1 NA_Sales 1686 10.086748 1.6170700 0.26328687 0.11141526 6.141856
2 JP_Sales 2434 14.561771 0.4709408 0.07761173 0.01057419 6.067908
3 EU_Sales 2060 12.324260 0.8729175 0.14502782 0.04271102 6.018966
4 User_Count 1080 6.461262 928.7583333 162.22990777 35.06390169 5.724951
5 Other_Sales 2242 13.413102 0.2672346 0.04733832 0.01327437 5.645207
6 Global_Sales 1891 11.313192 2.9183554 0.53351840 0.22930046 5.470018
7 Critic_Count 251 1.501645 82.1354582 26.36082094 24.58559472 3.115816
👉 위의 함수들이 데이터의 형태를 진단하기 위한 함수였다면 이후에는 본격적인 탐색을 진행해보아야 합니다. dlookr
을 통해 기술통계량, 정규성검정, 변수간 상관관계를 확인할 수 있습니다. 😀
1) 기술통계량 - dlookr::describe()
dlookr
의 dscribe()
가 좋은 이유는 dplyr
패키지의 group_by()
를 받는 다는 점입니다. 특정 변수 내 집단 단위에서 기술통계량을 확인해 볼 수 있습니다. # 기술통계량 확인하기
> videoGames %>%
+ dlookr::describe()
# A tibble: 9 x 26
variable n na mean sd se_mean IQR skewness kurtosis p00 p01 p05 p10 p20 p25 p30 p40
<chr> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 NA_Sales 16715 0 2.63e-1 0.814 0.00629 0.24 18.8 649. 0 0 0 0 0 0 0.01 0.04
2 EU_Sales 16715 0 1.45e-1 0.503 0.00389 0.11 18.9 756. 0 0 0 0 0 0 0 0.01
3 JP_Sales 16715 0 7.76e-2 0.309 0.00239 0.04 11.2 194. 0 0 0 0 0 0 0 0
4 Other_S… 16715 0 4.73e-2 0.187 0.00144 0.03 24.6 1055. 0 0 0 0 0 0 0 0.01
5 Global_… 16715 0 5.34e-1 1.55 0.0120 0.41 17.4 604. 0.01 0.01 0.02 0.02 0.05 0.06 0.08 0.11
6 Critic_… 8137 8578 6.90e+1 13.9 0.155 19 -0.614 0.143 13 31 43 50 58 60 63 67
7 Critic_… 8137 8578 2.64e+1 19.0 0.210 24 1.16 1.03 3 4 5 6 10 12 13 17
8 User_Sc… 10015 6700 7.57e+1 17.4 0.174 24 -0.894 0.813 1 24 42 53 63 66 69 74
9 User_Co… 7590 9125 1.62e+2 561. 6.44 71 9.03 113. 4 4 5 6 8 10 12 17
# … with 9 more variables: p50 <dbl>, p60 <dbl>, p70 <dbl>, p75 <dbl>, p80 <dbl>, p90 <dbl>, p95 <dbl>, p99 <dbl>,
# p100 <dbl>
# 특정 변수를 group 하여 기술통계량 확인하기
> videoGames %>%
+ dplyr::group_by(Platform) %>%
+ dlookr::describe()
# A tibble: 279 x 27
variable Platform n na mean sd se_mean IQR skewness kurtosis p00 p01 p05 p10 p20 p25 p30
<chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 NA_Sales 2600 133 0 0.681 0.855 0.0741 0.440 4.73 29.7 0.07 0.086 0.146 0.202 0.254 0.28 0.306
2 NA_Sales 3DO 3 0 0 0 0 0 NaN NA NaN 0 0 0 0 0 0
3 NA_Sales 3DS 520 0 0.161 0.536 0.0235 0.12 6.91 53.7 0 0 0 0 0 0 0
4 NA_Sales DC 52 0 0.104 0.312 0.0433 0 2.95 7.47 0 0 0 0 0 0 0
5 NA_Sales DS 2152 0 0.178 0.534 0.0115 0.17 11.9 193. 0 0 0 0 0 0 0.01
6 NA_Sales GB 98 0 1.17 3.02 0.305 0.915 5.08 31.2 0 0 0 0 0 0 0
7 NA_Sales GBA 822 0 0.228 0.443 0.0155 0.22 6.11 55.4 0 0 0 0.01 0.02 0.03 0.04
8 NA_Sales GC 556 0 0.240 0.423 0.0180 0.21 5.60 43.4 0 0 0.01 0.02 0.04 0.05 0.06
9 NA_Sales GEN 27 0 0.714 1.11 0.214 1.02 1.94 4.11 0 0 0 0 0 0 0
10 NA_Sales GG 1 0 0 NA NA 0 NA NA 0 0 0 0 0 0 0
# … with 269 more rows, and 10 more variables: p40 <dbl>, p50 <dbl>, p60 <dbl>, p70 <dbl>, p75 <dbl>, p80 <dbl>,
# p90 <dbl>, p95 <dbl>, p99 <dbl>, p100 <dbl>
2) 정규성검정 - dlookr::normality()
shapiro-wilk 정규성 검정
을 한번에 진행하고 정리까지 해줍니다. ㅠㅠdplyr
패키지의 group_by
함수를 받아줍니다.shapiro-wilk 정규성 검정
은 데이터 5천개 이상 넘어가면 할 필요가 없어지는데요, 이 함수는 만약 5천개 이상의 데이터가 있을 경우 자동으로 5천개 데이터 샘플링을 해주고, 혹은 직접 샘플 수를 지정할 수도 있습니다. normality(.data, ..., sample = n)
nortest::ad.test()
를 사용해보겠습니다.# 아래와 같이 모든 수치형 변수에 대해 정규성 검정 되었습니다.
# 데이터가 커 자동으로 5천개 샘플링 되었습니다.
> videoGames %>%
+ dlookr::normality()
# A tibble: 9 x 4
vars statistic p_value sample
<chr> <dbl> <dbl> <dbl>
1 NA_Sales 0.340 2.96e-86 5000
2 EU_Sales 0.330 1.28e-86 5000
3 JP_Sales 0.309 2.59e-87 5000
4 Other_Sales 0.228 7.86e-90 5000
5 Global_Sales 0.361 1.58e-85 5000
6 Critic_Score 0.972 2.69e-21 5000
7 Critic_Count 0.900 4.67e-37 5000
8 User_Score 0.913 1.69e-38 5000
9 User_Count 0.273 1.75e-69 5000
# 데이터가 5천가 이상이기 때문에 참고차 Anderson-Darling normality test를 지원하는 nortest의 ad.test 함수도 실행해보았습니다.
# map에 사용자 함수를 추가해서 깔끔하게 정리해보고 싶은데 아직 어떻게 하는지 헷갈리네요.
# 정리가 되면 추가하겠습니다.
> videoGames %>%
+ purrr::keep(is.numeric) %>%
+ purrr::map(nortest::ad.test)
$NA_Sales
Anderson-Darling normality test
data: .x[[i]]
A = 3281, p-value < 0.00000000000000022
$EU_Sales
Anderson-Darling normality test
data: .x[[i]]
A = 3615.4, p-value < 0.00000000000000022
$JP_Sales
Anderson-Darling normality test
data: .x[[i]]
A = 4108.6, p-value < 0.00000000000000022
$Other_Sales
Anderson-Darling normality test
data: .x[[i]]
A = 3859.8, p-value < 0.00000000000000022
... 생략
3) 상관관계 - dlookr::correlate()
dplyr
패키지의 group_by
함수를 받아줍니다.# 각 변수간 상관관계를 구할 수 있습니다.
# 다만, var1과 var2가 차례대로 변수를 모두 가지고 오기 때문에 중복값이 존재합니다.
# 중복값은 dplyr의 filter와 함께 사용하여 걸러낼 수 있습니다.
> dlookr::correlate(videoGames)
# A tibble: 72 x 3
var1 var2 coef_corr
<fct> <fct> <dbl>
1 EU_Sales NA_Sales 0.765
2 JP_Sales NA_Sales 0.450
3 Other_Sales NA_Sales 0.639
4 Global_Sales NA_Sales 0.941
5 Critic_Score NA_Sales 0.241
6 Critic_Count NA_Sales 0.295
7 User_Score NA_Sales -0.0224
8 User_Count NA_Sales 0.246
9 NA_Sales EU_Sales 0.765
10 JP_Sales EU_Sales 0.435
# 중복값을 걸러내려면 아래와 같이 조건을 걸어주면 되고,
# 저는 상관관계가 0.4 이상인 데이터만 조건도 추가하여 내림차순으로 정렬해주었습니다.
> videoGames %>%
+ dlookr::correlate() %>%
+ dplyr::filter(as.integer(var1) > as.integer(var2) & coef_corr > 0.4) %>%
+ dplyr::arrange(desc(coef_corr))
# A tibble: 10 x 3
var1 var2 coef_corr
<fct> <fct> <dbl>
1 Global_Sales NA_Sales 0.941
2 Global_Sales EU_Sales 0.901
3 EU_Sales NA_Sales 0.765
4 Global_Sales Other_Sales 0.749
5 Other_Sales EU_Sales 0.723
6 Other_Sales NA_Sales 0.639
7 Global_Sales JP_Sales 0.612
8 JP_Sales NA_Sales 0.450
9 JP_Sales EU_Sales 0.435
10 Critic_Count Critic_Score 0.426
# 위 데이터에서 total sales값인 Global_Sales 변수를 제외하고 확인하고 싶어 추가로 조건처리 해주었습니다.
# 유럽(EU_Sales)과 북미(NA_Sales)의 상관관계가 상당이 큽니다.
> videoGames %>%
+ dlookr::correlate() %>%
+ dplyr::filter(as.integer(var1) > as.integer(var2) & coef_corr > abs(0.4)) %>%
+ dplyr::arrange(desc(coef_corr)) %>%
+ dplyr::filter(var1 != "Global_Sales")
# A tibble: 6 x 3
var1 var2 coef_corr
<fct> <fct> <dbl>
1 EU_Sales NA_Sales 0.765
2 Other_Sales EU_Sales 0.723
3 Other_Sales NA_Sales 0.639
4 JP_Sales NA_Sales 0.450
5 JP_Sales EU_Sales 0.435
6 Critic_Count Critic_Score 0.426
cor()
함수로도 확인할 수 있습니다.dlookr::correlate()
와 비교하면 cor()
은 상관계수 행렬도 이기 때문에 조금 더 시각화에 가깝습니다.dlookr::correlate()
가 더 유용한 듯 합니다.> videoGames %>%
+ na.omit() %>%
+ purrr::keep(is.numeric) %>%
+ cor()
NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales Critic_Score Critic_Count User_Score User_Count
NA_Sales 1.00000000 0.84010651 0.46736643 0.72697184 0.95549579 0.2339939 0.2824937 0.08649859 0.24458335
EU_Sales 0.84010651 1.00000000 0.51917303 0.71632003 0.93873631 0.2122475 0.2640098 0.05572535 0.28271432
JP_Sales 0.46736643 0.51917303 1.00000000 0.39437822 0.61274980 0.1462993 0.1680913 0.12672516 0.07271912
Other_Sales 0.72697184 0.71632003 0.39437822 1.00000000 0.80437941 0.1914234 0.2380568 0.05734091 0.23920789
Global_Sales 0.95549579 0.93873631 0.61274980 0.80437941 1.00000000 0.2373968 0.2889865 0.08856985 0.26305942
Critic_Score 0.23399390 0.21224745 0.14629926 0.19142340 0.23739679 1.0000000 0.3940161 0.58209317 0.26432675
Critic_Count 0.28249365 0.26400976 0.16809130 0.23805679 0.28898649 0.3940161 1.0000000 0.19445169 0.36239666
User_Score 0.08649859 0.05572535 0.12672516 0.05734091 0.08856985 0.5820932 0.1944517 1.00000000 0.01768863
User_Count 0.24458335 0.28271432 0.07271912 0.23920789 0.26305942 0.2643267 0.3623967 0.01768863 1.00000000
이상으로, dlookr을 통한 데이터 진단과 탐색을 알아보았는데요, 이후 시각화 방법과 데이터 변환 방법도 가능한 패키지라 차근차근 공부해보도록 하겠습니다. 🙂