KDX Competition Guideline

Page content

개요

  • 본 수업을 듣는 수강생들을 위해 간단한 튜토리얼을 만들었다.
  • 대회는 다음과 같다.

/img/r/competition/blog_kdx_guideline_files/img

1단계 패키지 불러오기

  • 데이터 가공 및 시각화 위주의 패키지를 불러온다.
library(tidyverse) # 데이터 가공 및 시각화
library(readxl) # 엑셀파일 불러오기 패키지 

2단계 데이터 불러오기

  • 데이터가 많아서 순차적으로 진행하도록 한다.
  • 각 데이터에 대한 설명은활용데이터설명(PDF)을 참조한다.

  • 먼저 제 개발환경은 아래와 같다.
    • Note: 윈도우와 Mac은 다를 수 있음을 명심하자.
sessionInfo()
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Catalina 10.15.6
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] readxl_1.3.1    forcats_0.5.0   stringr_1.4.0   dplyr_1.0.0    
##  [5] purrr_0.3.4     readr_1.3.1     tidyr_1.1.0     tibble_3.0.3   
##  [9] ggplot2_3.3.2   tidyverse_1.3.0
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.5       cellranger_1.1.0 pillar_1.4.6     compiler_4.0.2  
##  [5] dbplyr_1.4.4     tools_4.0.2      digest_0.6.25    lubridate_1.7.9 
##  [9] jsonlite_1.7.0   evaluate_0.14    lifecycle_0.2.0  gtable_0.3.0    
## [13] pkgconfig_2.0.3  rlang_0.4.7      reprex_0.3.0     cli_2.0.2       
## [17] rstudioapi_0.11  DBI_1.1.0        yaml_2.2.1       haven_2.3.1     
## [21] xfun_0.16        withr_2.3.0      xml2_1.3.2       httr_1.4.2      
## [25] knitr_1.29       fs_1.5.0         hms_0.5.3        generics_0.0.2  
## [29] vctrs_0.3.2      grid_4.0.2       tidyselect_1.1.0 glue_1.4.1      
## [33] R6_2.4.1         fansi_0.4.1      rmarkdown_2.3    modelr_0.1.8    
## [37] blob_1.2.1       magrittr_1.5     backports_1.1.8  scales_1.1.1    
## [41] ellipsis_0.3.1   htmltools_0.5.0  rvest_0.3.6      assertthat_0.2.1
## [45] colorspace_1.4-1 stringi_1.4.6    munsell_0.5.0    broom_0.7.0     
## [49] crayon_1.3.4

(1) 삼성카드 데이터

  • 우선 삼성카드 데이터를 불러와서 확인한다.
  • 한글 파일은 인코딩이 늘 항상 문제다.
    • 파일을 불러오기 전 항상 파일 인코딩을 확인하도록 한다.
readr::guess_encoding("data/Samsungcard.csv", n_max = 100)
## # A tibble: 2 x 2
##   encoding confidence
##   <chr>         <dbl>
## 1 EUC-KR         1   
## 2 GB18030        0.62
  • Encoding 확인 결과 EUC-KR로 확인하였다.
samsung_card <- read_xlsx("data/Samsungcard.xlsx")
samsung_card2 <- read.csv("data/Samsungcard.csv", fileEncoding = "EUC-KR")
  • 위 두 파일이 동일한 것을 확인해본다
head(samsung_card)
## # A tibble: 6 x 5
##   소비일자 소비업종  성별  연령대 소비건수
##      <dbl> <chr>     <chr> <chr>     <dbl>
## 1 20190101 가전/가구 남성  20대       5529
## 2 20190101 가전/가구 남성  30대      17536
## 3 20190101 가전/가구 남성  40대      22838
## 4 20190101 가전/가구 남성  50대      15801
## 5 20190101 가전/가구 남성  60대       6772
## 6 20190101 가전/가구 여성  20대       5937
head(samsung_card2)
##   소비일자  소비업종 성별 연령대 소비건수
## 1 20190101 가전/가구 남성   20대     5529
## 2 20190101 가전/가구 남성   30대    17536
## 3 20190101 가전/가구 남성   40대    22838
## 4 20190101 가전/가구 남성   50대    15801
## 5 20190101 가전/가구 남성   60대     6772
## 6 20190101 가전/가구 여성   20대     5937
  • 두 파일이 동일한 것을 확인하였다면 이제 samsung_card2는 삭제를 한다.
    • RAM을 아껴 쓰자.
rm(samsung_card2) # 객체 지우는 함수
ls() # 현재 저장된 객체 확인하는 함수
## [1] "samsung_card"

(2) 신한카드 데이터

  • 이번에는 ShinhanCard.xslx 데이터를 불러온다.
shinhancard <- read_xlsx("data/Shinhancard.xlsx")
head(shinhancard)
## # A tibble: 6 x 8
##   일별    성별  연령대별 업종               `카드이용건수(천건)`… ...6  ...7   ...8
##   <chr>   <chr> <chr>    <chr>                           <dbl> <lgl> <lgl> <dbl>
## 1 201901… F     20대     M001_한식                       299.  NA    NA       10
## 2 201901… F     20대     M002_일식/중식/양식…               88.3 NA    NA       NA
## 3 201901… F     20대     M003_제과/커피/패스트푸드…              291.  NA    NA       NA
## 4 201901… F     20대     M004_기타요식                   446.  NA    NA       NA
## 5 201901… F     20대     M005_유흥                        24.2 NA    NA       NA
## 6 201901… F     20대     M006_백화점                      35.3 NA    NA       NA
  • 위 데이터를 불러오니 불필요한 6:8 변수가 불러온 것을 확인할 수 있다.
    • 실제 엑셀 데이터를 열어도 빈값임을 확인할 수 있다.
    • 따라서, 6:8 변수는 삭제한다.
shinhancard <- shinhancard %>% 
  select(-c(6:8))

head(shinhancard)
## # A tibble: 6 x 5
##   일별     성별  연령대별 업종                      `카드이용건수(천건)`
##   <chr>    <chr> <chr>    <chr>                                    <dbl>
## 1 20190101 F     20대     M001_한식                                299. 
## 2 20190101 F     20대     M002_일식/중식/양식                       88.3
## 3 20190101 F     20대     M003_제과/커피/패스트푸드                291. 
## 4 20190101 F     20대     M004_기타요식                            446. 
## 5 20190101 F     20대     M005_유흥                                 24.2
## 6 20190101 F     20대     M006_백화점                               35.3

(3) 지인플러스

  • 지인플러스는 아파트시세(GIN00009A)와 아파트 거래량(GIN00008B)을 담은 코드이다.
gin_8a <- read_csv("data/GIN00008A.csv")
gin_9a <- read_csv("data/GIN00009A.csv")
  • 위 두개의 데이터를 확인해본다.
glimpse(gin_8a)
## Rows: 937,904
## Columns: 9
## $ ym             <dbl> 200601, 200602, 200603, 200604, 200605, 200606, 200607…
## $ area_lvl_scor  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ lgdng_cd       <chr> "0000000000", "0000000000", "0000000000", "0000000000"…
## $ trd_cont       <dbl> 23357, 38617, 52241, 44253, 41916, 30257, 28613, 37362…
## $ avg_trd_cont   <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ trd_deal_rat   <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ mtrnt_cont     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ avg_mtrnt_cont <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ mtrnt_deal_rat <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
glimpse(gin_9a)
## Rows: 785,805
## Columns: 4
## $ lgdng_cd <dbl> 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+0…
## $ std_date <date> 2006-01-21, 2006-02-21, 2006-03-21, 2006-04-21, 2006-05-21,…
## $ trd_prc  <dbl> 1289, 1271, 1291, 1307, 1321, 1335, 1357, 1381, 1411, 1444, …
## $ ldpb_prc <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …

(4) JSON 파일 불러오기

  • JSON 파일 불러올 때에는 jsonlite 패키지를 활용한다.
library(jsonlite)
GIN_10m <- fromJSON("data/center_GIN00010M.json")
glimpse(GIN_10m)
## Rows: 20,572
## Columns: 8
## $ AREA_LVL_SCOR <int> 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3…
## $ LGDNG_CD      <chr> "1100000000", "1111000000", "1111010100", "1111010200",…
## $ CTPV_NM       <chr> "서울특별시", "서울특별시", "서울특별시", "서울특별시", "서울특별시", "서울특별시", "…
## $ CTGG_NM       <chr> NA, "종로구", "종로구", "종로구", "종로구", "종로구", "종로구", "종로구", "종…
## $ EMD_NM        <chr> NA, NA, "청운동", "신교동", "궁정동", "효자동", "창성동", "통의동", "적선동"…
## $ LA            <dbl> 37.52934, 37.58586, 37.58920, 37.58449, 37.58468, 37.58…
## $ LNGT          <dbl> 126.9515, 126.9775, 126.9693, 126.9679, 126.9731, 126.9…
## $ PYN_CN        <chr> "{\"type\": \"Polygon\", \"coordinates\": [[[126.979658…
  • PYN_CN의 값이 조금 다른 것을 확인할 수 있다.
    • 이 부분은 추후 전처리할 때 정리하는 것으로 확인한다.

(5) SSC_Data

  • 이번에는 Mcorporation내 폴더 데이터를 올리도록 한다.
  • 이번에 파일을 불러올 때는 readr::read_csv()를 활용하여 불러온다.
readr::guess_encoding("data/Mcorporation/KDX시각화경진대회_SSC_DATA.csv")
## # A tibble: 2 x 2
##   encoding confidence
##   <chr>         <dbl>
## 1 EUC-KR         1   
## 2 GB18030        0.76
ssc_data <- read_csv("data/Mcorporation/KDX시각화경진대회_SSC_DATA.csv", locale = locale("ko", encoding = "EUC-KR"))
glimpse(ssc_data)
## Rows: 76,580
## Columns: 5
## $ 소비일자 <dbl> 20190101, 20190101, 20190101, 20190101, 20190101, 20190101, 2019…
## $ 소비업종 <chr> "가전/가구", "가전/가구", "가전/가구", "가전/가구", "가전/가구", "가전/가구", "가전/가구", "…
## $ 성별     <chr> "남성", "남성", "남성", "남성", "남성", "여성", "여성", "여성", "여성", "여성", "남…
## $ 연령대   <chr> "20대", "30대", "40대", "50대", "60대", "20대", "30대", "40대", "50대", …
## $ 소비건수 <dbl> 5529, 17536, 22838, 15801, 6772, 5937, 12895, 16896, 14025, 5909…

(6) 다중 엑셀파일 불러오기 예제

  • 상품 카데고리 데이터_KDX 시각화 폴더 내 엑셀 데이터를 확인해본다.
list.files(path = "data/Mcorporation/상품 카테고리 데이터_KDX 시각화 경진대회 Only/")
##  [1] "PC사무기기.xlsx"             "TV홈시어터.xlsx"            
##  [3] "가공식품.xlsx"               "가방지갑잡화.xlsx"          
##  [5] "건강관련용품.xlsx"           "건강식품.xlsx"              
##  [7] "계절가전.xlsx"               "골프용품.xlsx"              
##  [9] "공구류.xlsx"                 "구기.xlsx"                  
## [11] "국내외여행.xlsx"             "기타 스포츠.xlsx"           
## [13] "낚시.xlsx"                   "남성의류.xlsx"              
## [15] "노트북.xlsx"                 "농축수산물.xlsx"            
## [17] "도서음반DVD.xlsx"            "등산용품.xlsx"              
## [19] "메이크업.xlsx"               "문구사무용품.xlsx"          
## [21] "미용가전.xlsx"               "반려동물.xlsx"              
## [23] "생활가구.xlsx"               "생활가전.xlsx"              
## [25] "생활용품.xlsx"               "서비스티켓.xlsx"            
## [27] "성인용품.xlsx"               "세탁청소세면.xlsx"          
## [29] "수납가구.xlsx"               "수납용품.xlsx"              
## [31] "수영.xlsx"                   "스키보드.xlsx"              
## [33] "스킨케어.xlsx"               "스포츠의류.xlsx"            
## [35] "신발.xlsx"                   "악세서리시계주얼리.xlsx"    
## [37] "안전용품.xlsx"               "언더웨어.xlsx"              
## [39] "업소위생용품.xlsx"           "여성의류.xlsx"              
## [41] "완구키덜트게임.xlsx"         "욕실가전.xlsx"              
## [43] "욕실용품.xlsx"               "유아용품.xlsx"              
## [45] "유아패션.xlsx"               "음료.xlsx"                  
## [47] "음향가전.xlsx"               "인테리어용품.xlsx"          
## [49] "자동차용품.xlsx"             "자전거사이클보드인라인.xlsx"
## [51] "주방가전.xlsx"               "주방수납잡화.xlsx"          
## [53] "주방식기용기.xlsx"           "주방조리기구.xlsx"          
## [55] "출산임부용품.xlsx"           "취미악기.xlsx"              
## [57] "침실가구.xlsx"               "침실인테리어.xlsx"          
## [59] "카메라캠코더.xlsx"           "캠핑용품.xlsx"              
## [61] "테마의류.xlsx"               "헤어바디용품.xlsx"          
## [63] "헬스기구용품.xlsx"           "휴대폰악세서리.xlsx"
  • 몇가지 파일을 열어본다.
  • 엑셀 데이터의 변수 등이 동일한 것을 확인할 수 있다.
  • 이제 위 데이터를 한꺼번에 불러와서 하나의 데이터셋으로 합친다.
  • 검색키워드 Multiple Excel Files import in R
files <- list.files(path = "data/Mcorporation/상품 카테고리 데이터_KDX 시각화 경진대회 Only/", pattern = "*.xlsx", full.names = T)

products <- sapply(files, read_excel, simplify=FALSE) %>% 
  bind_rows(.id = "id") %>% 
  select(-id)

glimpse(products)
## Rows: 1,837,833
## Columns: 7
## $ 구매날짜   <dbl> 20190101, 20190101, 20190101, 20190101, 20190101, 20190101, 20…
## $ 카테고리명 <chr> "PC/사무기기", "PC/사무기기", "PC/사무기기", "PC/사무기기", "PC/사무기기", "PC/사무기기…
## $ 고객성별   <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F…
## $ 고객나이   <dbl> 10, 10, 10, 10, 20, 20, 20, 20, 30, 30, 30, 30, 40, 40, 40, 40…
## $ OS유형     <chr> "IOS", "WINDOWS", "안드로이드", "없음", "IOS", "WINDOWS", "안드로이드", …
## $ 구매금액   <dbl> 352443, 84000, 80870, 3700, 27714776, 11414514, 21223319, 4832…
## $ 구매수     <dbl> 13, 1, 8, 1, 381, 60, 252, 41, 240, 75, 423, 19, 58, 110, 436…

3단계 데이터 시각화

  • 먼저, 데이터 저장 용량을 고려하여 products 데이터셋을 제외하고 나머지는 모두 삭제한다.
  • 데이터 시각화는 변수의 종류에 따른 시각화를 구현한 것이다.
  • 시각화 참조자료는 다음에서 작성이 가능하다.
  • 아래 샘플은 필자가 공부하는 형태를 구현한 것이다. 참조하기를 바란다.

(1) 수치형 변수 ~ 수치형 변수

  • 수치형 변수 ~ 수치형 변수 시각화의 대표적인 기법은 산점도(scatter) 또는 correlation이라 부른다.
    • scatter 시각화를 구현한다.
# load package and data
library(ggplot2)
data(mpg, package="ggplot2")
# mpg <- read.csv("http://goo.gl/uEeRGu")

# Scatterplot
theme_set(theme_bw())  # pre-set the bw theme.
g <- ggplot(mpg, aes(cty, hwy))
g + geom_count(col="tomato3", show.legend=F) +
  labs(subtitle="mpg: city vs highway mileage", 
       y="hwy", 
       x="cty", 
       title="Counts Plot")

  • 위 그래프를 작성한 뒤에는 반드시 데이터의 유형을 확인한다.
class(mpg$cty); class(mpg$hwy)
## [1] "integer"
## [1] "integer"
  • 위 작업을 하는 이유는 현재 내 데이터에서 위 데이터 유형과 비슷한 것인지 확인하기 위한 것이다.
    • 단 산점도를 시각화할 때 유의점이 있다. 데이터가 크기 때문에 시각화 구현에 시간이 소요된다.
    • 이 때 필요한 방법론이 샘플링이다.
temp_products <- sample_n(products, 1000)
g <- ggplot(temp_products, aes(x = 구매수, y = 구매금액))
g + geom_count(col="tomato3", show.legend=F) +
  labs(subtitle="products: count vs revenue ", 
       y="revenue", 
       x="count", 
       title="Counts Plot")

  • 분명 동일한 시각화를 작성하였지만, 다르게 나왔다. 이럴 경우에는 x + y축에 log Transformation를 해준다.
g + 
  geom_count(col="tomato3", show.legend=F) + 
  scale_x_log10() + 
  scale_y_log10() + 
  labs(subtitle="products: count vs revenue ", 
       y="revenue", 
       x="count", 
       title="Counts Plot")

  • 위 그래프를 보고 해석하는 것은 수강생들이 해야 하는 업무이다.

(2) 범주형 변수 ~ 수치형 변수

  • 대표적인 방법으로는 boxplot이 있다.
  • 그러나, 이번에는 카테고리명 기준으로 평균 구매금액의 평균을 구해본다. - 이번에도 마찬가지로 샘플을 보여준뒤 참조하는 형태로 작성한다.
cty_mpg <- aggregate(mpg$cty, by=list(mpg$manufacturer), FUN=mean) 
colnames(cty_mpg) <- c("make", "mileage")  
cty_mpg <- cty_mpg[order(cty_mpg$mileage), ]
cty_mpg$make <- factor(cty_mpg$make, levels = cty_mpg$make) 
head(cty_mpg, 4)
##          make  mileage
## 9     lincoln 11.33333
## 8  land rover 11.50000
## 3       dodge 13.13514
## 10    mercury 13.25000
  • 이렇게 정렬한 것을 시각화로 구현하는 것이다.
library(ggplot2)
theme_set(theme_bw())

# Draw plot
ggplot(cty_mpg, aes(x=make, y=mileage)) + 
  geom_bar(stat="identity", width=.5, fill="tomato3") + 
  labs(title="Ordered Bar Chart", 
       subtitle="Make Vs Avg. Mileage", 
       caption="source: mpg") + 
  theme(axis.text.x = element_text(angle=65, vjust=0.6))

  • 이제 내 데이터에 확인해보자.
cat_rev <- aggregate(products$카테고리명, by=list(products$구매금액), FUN=mean) 
  • 위 코드를 실행하면 속도가 굉장히 더딘 것을 확인할 수 있다.
  • 실제로 aggregate() 함수는 오래 걸린다.
    • 그래서 dplyr를 활용하여 피벗테이블을 만든다.
library(ggplot2) 

cat_rev <- products %>%
  group_by(카테고리명) %>% 
  summarise(mean = mean(구매금액)) %>% 
  arrange(desc(mean)) 

cat_rev <- cat_rev[order(cat_rev$mean, decreasing = TRUE), ]  # sort
cat_rev$카테고리명 <- factor(cat_rev$카테고리명, levels = cat_rev$카테고리명)  # to retain the order in plot.
head(cat_rev)
## # A tibble: 6 x 2
##   카테고리명         mean
##   <fct>             <dbl>
## 1 도서/음반/DVD 93366896.
## 2 서비스/티켓   89818959.
## 3 여성의류      62282167.
## 4 신발          58230514.
## 5 가공식품      48249770.
## 6 PC/사무기기   30909343.
  • 이제 위 데이터를 시각화 해본다.
# 맥 유저만 아래 코드 적용
theme_set(theme_classic(base_family='NanumGothic'))

ggplot(cat_rev %>% head(20), aes(x = 카테고리명, y = mean)) + 
  geom_bar(stat="identity", width=.5, fill="tomato3") + 
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) + 
  labs(title="Ordered Bar Chart", 
       subtitle="카테고리명 Vs Avg. 구매금액", 
       caption="source: products")

category_list <- cat_rev$카테고리명
category_list
##  [1] 도서/음반/DVD             서비스/티켓              
##  [3] 여성의류                  신발                     
##  [5] 가공식품                  PC/사무기기              
##  [7] 농축수산물                가방/지갑/잡화           
##  [9] 메이크업 용품             국내외여행               
## [11] 건강식품                  남성의류                 
## [13] 문구/사무용품             스포츠의류/잡화          
## [15] 주방가전                  계절가전                 
## [17] 음료                      악세서리/시계/주얼리     
## [19] 생활 가전                 반려동물용품             
## [21] 완구/키덜트/게임          인테리어용품             
## [23] 휴대폰/악세서리           생활 가구                
## [25] 유아/아동용품             세탁/청소/세면 용품      
## [27] 공구류                    취미/악기                
## [29] 유아/아동의류             건강 관련용품            
## [31] 침실 인테리어             헤어/바디케어            
## [33] 주방식기/용기             노트북/태블릿/학습가전   
## [35] 스킨케어                  생활용품                 
## [37] 침실 가구                 언더웨어                 
## [39] TV/홈시어터               주방조리기구             
## [41] 미용가전/안마기           골프용품                 
## [43] 음향가전                  자동차 관련용품          
## [45] 주방수납/잡화             안전용품                 
## [47] 카메라/캠코더             수납용품                 
## [49] 캠핑용품                  등산용품                 
## [51] 자전거/사이클/보드/인라인 기타 스포츠/스포츠 용품  
## [53] 욕실가전                  수영용품                 
## [55] 출산용품/임부용품         욕실용품                 
## [57] 구기종목 용품             헬스기구용품             
## [59] 낚시용품                  수납가구                 
## [61] 테마의류                  업소 위생용품            
## [63] 성인용품                  스키/보드용품            
## 64 Levels: 도서/음반/DVD 서비스/티켓 여성의류 신발 가공식품 ... 스키/보드용품
  • list 추후 작성을 위해 list로 남겨 놓는다.

  • 이번에는 카테고리명 ~ 평균 구매건수에 관한 시각화를 작성해본다.

  • 해석은 각자 진행하고 반영하면 된다.

(3) 위 두 그래프 확장하기

  • 성별 및 연령대별로 추가적인 변수를 넣어 확인해보는 시각화를 만들어 본다.
    • 먼저 성별을 기준으로 산점도를 작성해본다.
temp_products <- sample_n(products, 1000)
g <- ggplot(temp_products, aes(x = 구매수, y = 구매금액))
# g + geom_count(col="tomato3", show.legend=F) +
g + geom_point(aes(colour = 고객성별)) + 
  scale_x_log10() + 
  scale_y_log10() + 
  labs(subtitle="products: count vs revenue ", 
       y="revenue", 
       x="count", 
       title="Counts Plot")

  • 상대적으로 시각화 눈에 잘 들어오지 않는다.
    • 이러한 경우 facet_() 함수 계열을 활용해본다.
g <- ggplot(temp_products, aes(x = 구매수, y = 구매금액))
# g + geom_count(col="tomato3", show.legend=F) +
g + geom_point(col="tomato3") + 
  scale_x_log10() + 
  scale_y_log10() + 
  facet_grid(고객성별 ~.) + 
  labs(subtitle="products: count vs revenue ", 
       y="revenue", 
       x="count", 
       title="Counts Plot")

  • 없음의 값이 상대적으로 작기 때문에 해당 영역은 제외하고 데이터셋을 재구성한다.
  • 이 때, filter() 함수를 활용한다.
gender_products <- products %>% 
  filter(고객성별 != "없음")

dim(products); dim(gender_products)
## [1] 1837833       7
## [1] 1732078       7
  • 약 10만개의 데이터가 줄어든 것을 확인할 수 있다.
temp_products <- sample_n(gender_products, 1000)
g <- ggplot(temp_products, aes(x = 구매수, y = 구매금액))
# g + geom_count(col="tomato3", show.legend=F) +
g + geom_point(col="tomato3") + 
  scale_x_log10() + 
  scale_y_log10() + 
  facet_grid(고객성별 ~.) + 
  labs(subtitle="products: count vs revenue ", 
       y="revenue", 
       x="count", 
       title="Counts Plot")

  • 훨씬 더 시각적으로 비교가 잘 되는 것을 확인할 수 있다.
  • 이번에는 막대 그래프를 추가해본다.
cat_rev <- products %>%
  group_by(카테고리명, 고객성별) %>% 
  summarise(mean = mean(구매금액)) %>% 
  arrange(desc(mean)) 

glimpse(cat_rev)
## Rows: 192
## Columns: 3
## Groups: 카테고리명 [64]
## $ 카테고리명 <chr> "도서/음반/DVD", "서비스/티켓", "신발", "PC/사무기기", "문구/사무용품", "가공식품", "여성의…
## $ 고객성별   <chr> "없음", "없음", "없음", "없음", "없음", "없음", "없음", "F", "없음", "F", "없음"…
## $ mean       <dbl> 376868009, 308278103, 243189502, 212857790, 174581259, 143…
cat_rev <- cat_rev[order(cat_rev$mean, decreasing = TRUE), ]  # sort
cat_rev
## # A tibble: 192 x 3
## # Groups:   카테고리명 [64]
##    카테고리명    고객성별       mean
##    <chr>         <chr>         <dbl>
##  1 도서/음반/DVD 없음     376868009.
##  2 서비스/티켓   없음     308278103.
##  3 신발          없음     243189502.
##  4 PC/사무기기   없음     212857790.
##  5 문구/사무용품 없음     174581259.
##  6 가공식품      없음     143698037.
##  7 여성의류      없음     117868620.
##  8 여성의류      F        100027424.
##  9 공구류        없음      96215460.
## 10 도서/음반/DVD F         90766413.
## # … with 182 more rows
  • 위 데이터를 보면 알겠지만, 없음이 데이터의 비율이 높게 형성된 것을 확인할 수 있다.
  • 이는 마케팅 기획에 있어서 적합하지 않을 뿐 아니라 데이터의 상대적으로 적기 때문에 제거한다.
cat_rev2 <- cat_rev %>% 
  filter(고객성별 != "없음")
cat_rev2
## # A tibble: 128 x 3
## # Groups:   카테고리명 [64]
##    카테고리명     고객성별       mean
##    <chr>          <chr>         <dbl>
##  1 여성의류       F        100027424.
##  2 도서/음반/DVD  F         90766413.
##  3 서비스/티켓    F         82775484.
##  4 서비스/티켓    M         75524898.
##  5 도서/음반/DVD  M         68399900.
##  6 가공식품       F         58375598.
##  7 신발           F         55024533.
##  8 신발           M         43104913.
##  9 메이크업 용품  F         38278015.
## 10 가방/지갑/잡화 F         38144345.
## # … with 118 more rows
ggplot(cat_rev2, aes(x = 카테고리명, y = mean, fill = 고객성별)) +
  geom_bar(stat="identity", position = "dodge", width=.5)

  • 데이터의 값이 많다보니 카테고리를 구분해서 보도록 한다.
i = 1
j = i+7
category_list <- as.character(category_list)

cat_rev2 %>% 
  filter(카테고리명 %in% category_list[c(i:as.numeric(i+7))]) %>% 
  ggplot(aes(x = 카테고리명, y = mean, fill = 고객성별)) +
  geom_bar(stat="identity", position = "dodge", width=.5) + 
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) + 
  labs(title="Ordered Bar Chart", 
  subtitle="카테고리명 Vs Avg. 구매금액 by 고객성별", 
  caption="source: products")

category_graph <- function(df, cat_list = cat_list) {
  category_list <- sort(as.character(cat_list))

  print(category_list)
  for (i in seq(1, 64, by = 8)) {
      i = i
      j = i+7
      plot <- df %>% 
        filter(카테고리명 %in% category_list[i:j]) %>% 
        ggplot(aes(x = 카테고리명, y = mean, fill = 고객성별)) +
        geom_bar(stat="identity", position = "dodge", width=.5) + 
        theme(axis.text.x = element_text(angle=65, vjust=0.6)) + 
        labs(title="Ordered Bar Chart", 
             subtitle="카테고리명 Vs Avg. 구매금액 by 고객성별", 
             caption="source: products")
      
      print(plot)
  }
}

category_graph(cat_rev2, category_list)
##  [1] "PC/사무기기"               "TV/홈시어터"              
##  [3] "가공식품"                  "가방/지갑/잡화"           
##  [5] "건강 관련용품"             "건강식품"                 
##  [7] "계절가전"                  "골프용품"                 
##  [9] "공구류"                    "구기종목 용품"            
## [11] "국내외여행"                "기타 스포츠/스포츠 용품"  
## [13] "낚시용품"                  "남성의류"                 
## [15] "노트북/태블릿/학습가전"    "농축수산물"               
## [17] "도서/음반/DVD"             "등산용품"                 
## [19] "메이크업 용품"             "문구/사무용품"            
## [21] "미용가전/안마기"           "반려동물용품"             
## [23] "생활 가구"                 "생활 가전"                
## [25] "생활용품"                  "서비스/티켓"              
## [27] "성인용품"                  "세탁/청소/세면 용품"      
## [29] "수납가구"                  "수납용품"                 
## [31] "수영용품"                  "스키/보드용품"            
## [33] "스킨케어"                  "스포츠의류/잡화"          
## [35] "신발"                      "악세서리/시계/주얼리"     
## [37] "안전용품"                  "언더웨어"                 
## [39] "업소 위생용품"             "여성의류"                 
## [41] "완구/키덜트/게임"          "욕실가전"                 
## [43] "욕실용품"                  "유아/아동용품"            
## [45] "유아/아동의류"             "음료"                     
## [47] "음향가전"                  "인테리어용품"             
## [49] "자동차 관련용품"           "자전거/사이클/보드/인라인"
## [51] "주방가전"                  "주방수납/잡화"            
## [53] "주방식기/용기"             "주방조리기구"             
## [55] "출산용품/임부용품"         "취미/악기"                
## [57] "침실 가구"                 "침실 인테리어"            
## [59] "카메라/캠코더"             "캠핑용품"                 
## [61] "테마의류"                  "헤어/바디케어"            
## [63] "헬스기구용품"              "휴대폰/악세서리"

  • 가나다 순으로 카테고리시각화를 구현한 뒤, 고객성별로 비교할 수 있다.
  • 카테고리, 고객성별 대신에, 고객나이, OS유형 등을 조합해서 시각화를 작성한 뒤 비교하는 것은 수강생들에게 남겨둔다.

(4) 시계열 그래프

library(ggplot2)

# Compute % Returns
economics$returns_perc <- c(0, diff(economics$psavert)/economics$psavert[-length(economics$psavert)])

# Allow Default X Axis Labels
ggplot(economics, aes(x=date)) + 
  geom_line(aes(y=returns_perc)) + 
  labs(title="Time Series Chart", 
       subtitle="Returns Percentage from 'Economics' Dataset", 
       caption="Source: Economics", 
       y="Returns %")

glimpse(economics)
## Rows: 574
## Columns: 7
## $ date         <date> 1967-07-01, 1967-08-01, 1967-09-01, 1967-10-01, 1967-11…
## $ pce          <dbl> 506.7, 509.8, 515.6, 512.2, 517.4, 525.1, 530.9, 533.6, …
## $ pop          <dbl> 198712, 198911, 199113, 199311, 199498, 199657, 199808, …
## $ psavert      <dbl> 12.6, 12.6, 11.9, 12.9, 12.8, 11.8, 11.7, 12.3, 11.7, 12…
## $ uempmed      <dbl> 4.5, 4.7, 4.6, 4.9, 4.7, 4.8, 5.1, 4.5, 4.1, 4.6, 4.4, 4…
## $ unemploy     <dbl> 2944, 2945, 2958, 3143, 3066, 3018, 2878, 3001, 2877, 27…
## $ returns_perc <dbl> 0.000000000, 0.000000000, -0.055555556, 0.084033613, -0.…
  • 여기서 주목해야 하는 것은 date의 객체가 date라는 것이다.
class(economics$date)
## [1] "Date"
  • 그런데, 만약 date의 형태가 다르면 어떻게 해야할까?
  • 그럼 변환해야 한다.
    • 간단한 예시로 확인한다. (기본 문법)
temp_date <- "20200110"
conv_date <- as.Date(temp_date, format = "%Y%m%d")
print(conv_date)
## [1] "2020-01-10"
class(conv_date)
## [1] "Date"
glimpse(shinhancard)
## Rows: 195,599
## Columns: 5
## $ 일별                 <chr> "20190101", "20190101", "20190101", "20190101", "2…
## $ 성별                 <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", …
## $ 연령대별             <chr> "20대", "20대", "20대", "20대", "20대", "20대", "20대", "20…
## $ 업종                 <chr> "M001_한식", "M002_일식/중식/양식", "M003_제과/커피/패스트푸드", "M…
## $ `카드이용건수(천건)` <dbl> 298.9, 88.3, 290.6, 446.3, 24.2, 35.3, 388.0, 557.5, 36.…
  • 위 데이터에서 보는 것처럼 일별이 있지만, <chr>문자열로 기록되는 것을 확인할 수 있다.
  • 이 데이터를 변환한다.
shinhancard$일별 <- as.Date(shinhancard$일별, format = "%Y%m%d")
glimpse(shinhancard)
## Rows: 195,599
## Columns: 5
## $ 일별                 <date> 2019-01-01, 2019-01-01, 2019-01-01, 2019-01-01, 2…
## $ 성별                 <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", …
## $ 연령대별             <chr> "20대", "20대", "20대", "20대", "20대", "20대", "20대", "20…
## $ 업종                 <chr> "M001_한식", "M002_일식/중식/양식", "M003_제과/커피/패스트푸드", "M…
## $ `카드이용건수(천건)` <dbl> 298.9, 88.3, 290.6, 446.3, 24.2, 35.3, 388.0, 557.5, 36.…
# Allow Default X Axis Labels
ggplot(shinhancard, aes(x=일별)) + 
  geom_line(aes(y=`카드이용건수(천건)`)) + 
  labs(title="Time Series Chart", 
       subtitle="Returns Percentage from 'Economics' Dataset", 
       caption="Source: Economics", 
       y="Returns %")

  • 이상하다, 분명 시각화를 진행했는데, 검은색의 데이터가 존재한다.
  • 왜 그럴까?
shinhancard %>% 
  filter(일별 == "2019-01-01") %>% 
  dim()
## [1] 355   5
shinhancard %>% 
  rename(date = "일별") %>% 
  group_by(date) %>% 
  summarise(mean = mean(`카드이용건수(천건)`)) %>% 
  ggplot(aes(x=date)) + 
  geom_line(aes(y=mean)) + 
  theme(axis.text.x = element_text(angle=65, vjust=0.6)) + 
  labs(title="Time Series Chart", 
       subtitle="Avg. Sales from 'Shinhan Card' Dataset", 
       caption="Source: Shinhan Card", 
       y="Avg. Sales (1000)") + 
  theme_bw()

  • 이번에는 그룹별로 시각화를 구현한다.
shinhancard %>% 
  rename(date = "일별", gender = "성별") %>%    
  group_by(date, gender) %>% 
  summarise(mean = mean(`카드이용건수(천건)`)) %>% 
  ggplot(aes(x=date)) + 
  geom_line(aes(y=mean, colour = gender)) + 
  labs(title="Time Series Chart", 
       subtitle="Avg. Sales from 'Shinhan Card' Dataset", 
       caption="Source: Shinhan Card", 
       y="Avg. Sales (1000)")

  • 이번에는 연령대별로 소비패턴을 확인해보자.
shinhancard %>% 
  rename(date = "일별") %>%  
  group_by(date, 연령대별) %>% 
  summarise(mean = mean(`카드이용건수(천건)`)) %>% 
  ggplot(aes(x=date)) + 
  geom_line(aes(y=mean, colour = 연령대별)) + 
  labs(title="Time Series Chart", 
       subtitle="Avg. Sales from 'Shinhan Card' Dataset", 
       caption="Source: Shinhan Card", 
       y="Avg. Sales (1000)")

  • 위와 같이 그래프를 확장하면서 계속 그릴 수가 있다.
  • 성별로 구분해서 보는 것도 도움이 되기 때문에, 이 부분은 수강생들에게 맡기도록 한다.