분포란? 

확률밀도함수가 생긴 모양새


 - 연속형확률 분포 : 지수분포, 로그정규분포, t분포, 카이제곱분포, 감마분포 등

 - 이산형 확률분포 : 베르누이분포, 이항분포, 포아송분포 등


모수란?

Prameters, 모든 확률분포의 모양을 결정짓는 결정적인 수. 모든 확률 분포는 한 개 이상의 모수를 가진다.


 - 가령, 가장 유명한 정규분포의 경우 평균,분산의 2개의 모수가 존재

 - 대부분의 경우 모수를 정확히 알 수 없고, 이를 추측하는 과정을 추정(Estimation)이라 함.


비모수적 모델?

모수를 통해 모델을 결정짓지 못하는 경우 비모수적 모델이라 함


 - Ex : KNN


이 경우, 학습 이전에 조건을 주게 되는데 이는 모수와는 다른 개념이다.

 


정리하자면,

 - 모수적 모델: 회귀모델, 로지스틱회귀모델, 1차/2차 판별모델

 - 비모수적 모델: 의사결정나무, 랜덤포레스트 (Random Forest), K-최근접이웃



반응형
Posted by JoeSung
,

Contents

  1. NA 체크 (N/A Check)
  2. 이상값 체크 (Outlier Checke)
  3. 현실성 체크 (Realistic Check)
  4. 개별 컬럼 시각화 (Single Feature Visualization)
  5. 파생변수 생성 (Feature Engineering)
  6. 연관관계 시각화 (Relationship Visaulization)

1. NA값 체크

모든 테이블의 N/A 값 확인을 위하여 N/A 검사기를 제작하여 확인한다.

1.1 회원정보(customer) 테이블 N/A 검사

## N/A 검사기
for( i in 1 : ncol(customer)){
  x <- sum(is.na(customer[,i])) 
  if (x != 0){ 
    y <- paste(colnames(customer)[i] ," : ", round(x/nrow(customer), 3) *100, "% 의 NA 비율 보유" )
    print(y) 
  } else{
    paste("N/A값이 없습니다.")
  } 
}
## [1] "HOM_PST_NO  :  6.8 % 의 NA 비율 보유"

1.2 쇼핑업종 상품구매정보(shopping) 테이블 N/A 검사

## N/A 검사기
for( i in 1 : ncol(shopping)){
  x <- sum(is.na(shopping[,i])) 
  if (x != 0){ 
    y <- paste(colnames(shopping)[i] ," : ", round(x/nrow(shopping), 3) *100, "%") 
    print(y) 
  } else{
    paste("N/A값이 없습니다.")
  } 
}

1.3 쇼핑 외업종 상품구매정보(nonshopping) 테이블 N/A 검사

## N/A 검사기
for( i in 1 : ncol(nonshopping)){
  x <- sum(is.na(nonshopping[,i])) 
  if (x != 0){ 
    y <- paste(colnames(nonshopping)[i] ," : ", round(x/nrow(nonshopping), 3) *100, "%") 
    print(y) 
    } else{
    paste("N/A값이 없습니다.")
  } 
}

1.4 카테고리(category) 테이블 N/A 검사

## N/A 검사기
for( j in 1 : ncol(category)){
  x <- sum(is.na(category[,c(j)])) 
  if (x != 0){ 
    y <- paste(colnames(category)[j] ," : ", round(x/nrow(category), 3) *100, "%") 
    print(y) 
  } else{
    paste("N/A값이 없습니다.")
  } 
}
NA 값 탐색 정리
  • 전체 테이블 중 customer 테이블의 “HOM_PST_NO” 컬럼만 6.8 %의 비율로 NA 값이 존재하는 것을 확인할 수 있었다.

2. 이상치 (Outlier) 체크

이상치의 정의

변수의 분포에서 비정상적으로 분포를 벗어난 값이다. 각 변수의 분포에서 비정상적으로 극단값을 갖는 경우나 자료에 타당도가 없는 경우, 비현실적인 변수값들이 이에 해당한다. [네이버 백과사전]

  • 뒤에서 탐색할 부분에서 이상치라고 부를만한 것이 발견되지 않았음

3. Realistic 여부 체크 (현실적인 데이터인가?)

3.1 BUY_AM이 0인 경우

## BUY_AM이 0인 경우 
buy_am_is_0 <- temp_sho[ temp_sho$BUY_AM == 0 , c(3,4,9,13,14,15) ]

pd_s_zero <- as.character(unique(buy_am_is_0$PD_S_NM))
paste(" 구매금액(BUY_AM)이 0원인 상품은" , pd_s_zero, "입니다.")
##  [1] " 구매금액(BUY_AM)이 0원인 상품은 HOT 입니다."                   
##  [2] " 구매금액(BUY_AM)이 0원인 상품은 컵얼음 입니다."                
##  [3] " 구매금액(BUY_AM)이 0원인 상품은 봉지얼음 입니다."              
##  [4] " 구매금액(BUY_AM)이 0원인 상품은 팬시용품 입니다."              
##  [5] " 구매금액(BUY_AM)이 0원인 상품은 슬러피원액 입니다."            
##  [6] " 구매금액(BUY_AM)이 0원인 상품은 기타판매용소모품 입니다."      
##  [7] " 구매금액(BUY_AM)이 0원인 상품은 공병공박스 입니다."            
##  [8] " 구매금액(BUY_AM)이 0원인 상품은 소주공병 입니다."              
##  [9] " 구매금액(BUY_AM)이 0원인 상품은 맥주공병 입니다."              
## [10] " 구매금액(BUY_AM)이 0원인 상품은 기타 입니다."                  
## [11] " 구매금액(BUY_AM)이 0원인 상품은 바디보습 입니다."              
## [12] " 구매금액(BUY_AM)이 0원인 상품은 BB/파운데이션/컴팩트류 입니다."
정리
  • 총 12종류의 0원 상품이 있었으며, 환급이 되는 공병, 편의점에서 음료를 구매했을 경우 추가로 주는 얼음등 제공품류는 0원으로 영수증에 기록됨

  • 차후 변수에서 따로 처리를 하지는 않는다. 이 또한 라이프스타일의 하나로 반영하기로 함.

3.2 BUY_CT가 이상하게 높은 경우 ( > 1000)

over_1000 <- temp_sho[temp_sho$BUY_CT >= 1000, c(10,13)] %>%
  group_by(PD_S_NM) %>%
  summarise( avgct = round(mean(BUY_CT)))

paste("BUY_CT가 1000 이상인 상품의 수는", nrow(over_1000), "개 입니다")
## [1] "BUY_CT가 1000 이상인 상품의 수는 93 개 입니다"
paste("그 중에서 20개만을 샘플로 보면 다음과 같습니다")
## [1] "그 중에서 20개만을 샘플로 보면 다음과 같습니다"
sample_n(over_1000, 20)
## # A tibble: 20 x 2
##           PD_S_NM avgct
##             <chr> <dbl>
##  1 호주산목초비육  1482
##  2 호주산곡물비육  1598
##  3     반건고등어  1110
##  4   수입냉동연어  1706
##  5   고당도바나나  1358
##  6     NB돼지고기  1437
##  7           석화  1094
##  8             마  1128
##  9           연근  1254
## 10       기타조개  2070
## 11         활어회  1055
## 12       한우채끝  1376
## 13       한우안심  1551
## 14       산지한우  1396
## 15           고추  1068
## 16         코다리  1016
## 17         명태알  1024
## 18         랍스터  1689
## 19         주꾸미  1452
## 20       일반수박  3256
정리
  • 대부분이 g이나 kg등으로 무게를 측정하는 상품류인 육류나 과일류인 것으로 미루어보아 BUY_CT 변수는 갯수뿐 아니라 무게도 나타내는 숫자가 섞여서 사용되고 있음을 알 수 있었다.

  • 따라서, BUY_CT 변수를 정제없이 feature로 사용하기엔 부적절함을 확인함

3.3 영수증번호 쇼핑업종 상품코드 모두같은데 금액이 다른 데이터 존재

rct_biz_pdc_same <- temp_sho %>%
  mutate( temp_div = paste(RCT_NO, BIZ_UNIT.x, PD_S_C.x, sep="-"),
          ct_multiple_am = BUY_AM*BUY_CT ) %>%
  select(temp_div, ct_multiple_am, PD_S_NM) %>%
  group_by(temp_div, PD_S_NM) %>%
  summarise( n = n() ) %>%
  filter( n >= 2)
## Warning in BUY_AM * BUY_CT: NAs produced by integer overflow
## [1] "영수증번호, 쇼핑업종, 상품코드가 같은 상품의 수는 399593 개 입니다"
## [1] "그 중에서 20개만을 샘플로 보면 다음과 같습니다"
##  [1] "트래디셔널"         "구강청정제"         "딸기"              
##  [4] "컵라면"             "수입과채혼합음료"   "과일음료"          
##  [7] "마켓피자"           "영캐주얼"           "다이소"            
## [10] "시금치"             "요리용치즈"         "참치회"            
## [13] "사과"               "옷걸이"             "기능성웰빙돼지고기"
## [16] "콘스낵"             "일반스낵"           "고추"              
## [19] "곡물가루"           "친환경채소(특약)"
정리
  • 한식의 경우 대표적인 예시였는데, 소카테고리의 경우 개별 제품을 대표하지 않을 수 있다는 사실을 알 수 있음

  • 가령, 한식이라고 PD_S_NM이 적혀있더라도 다른 한식의 종류가 더 있을 수 있다는 의미이다.

4. 개별 컬럼 시각화 ( Single Column Visualization )

4.1 고객정보(customer) 테이블

head(customer, 5) ## head를 통한 테이블 뷰 생성
##   ID GENDER AGE_PRD HOM_PST_NO
## 1  1      1   60PRD         52
## 2  2      2   60PRD         80
## 3  3      2   60PRD        620
## 4  4      1   60PRD        120
## 5  5      1   60PRD         NA
glimpse(customer) ## 컬럼 요약
## Observations: 20,000
## Variables: 4
## $ ID         <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ...
## $ GENDER     <int> 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, ...
## $ AGE_PRD    <fctr> 60PRD, 60PRD, 60PRD, 60PRD, 60PRD, 60PRD, 60PRD, 6...
## $ HOM_PST_NO <int> 52, 80, 620, 120, NA, 58, 52, 480, 470, 55, 72, 61,...
summary(customer) ## 값 요약
##        ID            GENDER       AGE_PRD       HOM_PST_NO   
##  Min.   :    1   Min.   :1.000   20PRD:2339   Min.   :  0.0  
##  1st Qu.: 5001   1st Qu.:1.000   30PRD:5053   1st Qu.: 56.0  
##  Median :10000   Median :2.000   40PRD:5183   Median :130.0  
##  Mean   :10000   Mean   :1.609   50PRD:4744   Mean   :214.9  
##  3rd Qu.:15000   3rd Qu.:2.000   60PRD:2681   3rd Qu.:420.0  
##  Max.   :20000   Max.   :2.000                Max.   :630.0  
##                                               NA's   :1365
nrow(customer) ## customer 테이블 row 수
## [1] 20000

4.1.1 ID

ID의 갯수가 중복이 없는지 확인한다.

if (length(customer$ID) == length(unique(customer$ID))){
  print(paste("ID 갯수는 중복 없이", length(customer$ID),"개 입니다."))
}
## [1] "ID 갯수는 중복 없이 20000 개 입니다."

4.1.2 GENDER

tempGender <- customer$GENDER
tempGender <- ifelse(tempGender == 1, "남자", "여자")
prop.table(table(tempGender))
## tempGender
##    남자    여자 
## 0.39075 0.60925
ggplot(data.table(tempGender), aes(x=tempGender, color=tempGender, fill = tempGender) ) + 
  geom_bar(width=0.5) +
  ggtitle("LPOINT 회원 성별 분포")

4.1.3 AGE_PRD

prop.table(table(customer$AGE_PRD)) 
## 
##   20PRD   30PRD   40PRD   50PRD   60PRD 
## 0.11695 0.25265 0.25915 0.23720 0.13405
ggplot(customer, aes(x=AGE_PRD, color = AGE_PRD, fill = AGE_PRD)) + 
  geom_bar(width=0.5) +
  ggtitle("LPOINT 회원 연령 분포")

  • 롯데의 주요 고객층은 3~50대에 분포해있으며, 20대와 60대의 고객층이 상대적으로 적은 것을 시각적으로 확인할 수 있다.

4.1.4 HOM_PST_NO

ggplot(data = subset(customer, !is.na(HOM_PST_NO)), aes(x=HOM_PST_NO, color = HOM_PST_NO, fill = HOM_PST_NO)) +
  geom_histogram(binwidth = 5) + 
  ggtitle("HOM_PST_NO")

  • N/A값 데이터 탐색시에 유일하게 N/A 값이 발견된 컬럼이므로 ggplot 사용시 N/A 처리를 위하여 subset으로 N/A 값을 제거하고 그래프를 그려준다.

  • LPOINT 이용자가 확연히 몰려있는 지역이 있는 것을 확인할 수 있다.

  • 따라서, 이용자 500명 이상 지역 기준으로 뎁스를 한번 더 들어가 분석을 실행한다.

temp <- na.omit(customer) ## NA 값 핸들링
customer_idCount_byHOM_PST_NO <- sqldf(
  'select "HOM_PST_NO", count("ID")
  from temp
  group by HOM_PST_NO
  having count(ID) >= 500
  order by count(ID) desc') ## 500개 이상의 ID 값을 가지고 있는 지역을 추출

top5_custo <- customer[ customer$HOM_PST_NO %in% customer_idCount_byHOM_PST_NO$HOM_PST_NO,]

print(customer_idCount_byHOM_PST_NO)
##   HOM_PST_NO count("ID")
## 1        100        1004
## 2         55         914
## 3        160         595
## 4        470         594
## 5        130         539
## 6        480         504
## 7        460         503
  • 100, 55, 160, 470, 130, 480, 460 지역 (HOM_PST_NO) 순으로 높은 회원수 보유하고 있었다.
## 500명 이상의 연령분포
ggplot(top5_custo, aes(x=AGE_PRD, color = AGE_PRD, fill = AGE_PRD)) + 
  geom_bar(width=0.5) +
  ggtitle("LPOINT 회원 지역별 연령 분포") +
  facet_wrap(~ HOM_PST_NO)

## 500명 이상 보유 지역의 성별 분포
ggplot(top5_custo, aes(x=GENDER, color = GENDER, fill = GENDER)) + 
  geom_bar(width=0.5) +
  ggtitle("LPOINT 회원 지역별 성별 분포") +
  facet_wrap(~ HOM_PST_NO)

custo_HOM_PST_NO_55 <- customer %>% 
  filter(HOM_PST_NO==55)

paste("55번 지역의 성별 분포")
## [1] "55번 지역의 성별 분포"
prop.table(table(ifelse(custo_HOM_PST_NO_55$GENDER == 1, "남자","여자")))
## 
##      남자      여자 
## 0.3238512 0.6761488
paste("전체 지역의 성별 분포")
## [1] "전체 지역의 성별 분포"
prop.table(table(custo_HOM_PST_NO_55$AGE_PRD))
## 
##      20PRD      30PRD      40PRD      50PRD      60PRD 
## 0.04595186 0.16411379 0.28665208 0.27133479 0.23194748
  • 55번 지역 특이지역 발견
    • 여성비율이 전체 평균보다 약 6.7% 높고, 60대의 비율 높음, 30대의 비율 낮음
HOM_PST_NO 정리
  • 회원수가 500명 이상되는 지역을 7구역 추출하였으며, 이 중 55번 지역의 경우 성별 비율에서 전체데이터보다 여성의 비율이 7% 가량 높은 것을 확인할 수 있었다.

  • 차후 특정 지역을 타게팅한 모델링 시에 55번 지역에 맞춘 모델링을 별도로 할 경우 높은 예측력을 가질 수 있을 것으로 기대됨

4.2 쇼핑 업종 테이블 (shopping)

## 
Read 84.6% of 3641082 rows
Read 3641082 rows and 9 (of 9) columns from 0.160 GB file in 00:00:03
head(shopping, 5) ## head를 통한 테이블 뷰 생성
##      ID RCT_NO BIZ_UNIT PD_S_C BR_C    DE_DT DE_HR BUY_AM BUY_CT
## 1: 4008   2108   백화점    215    2 20150216    13  59600      2
## 2: 6379   2109   백화점     75   29 20150213    11  35000      1
## 3: 6379   2109   백화점    149    4 20150115    10  85000      1
## 4: 8002   2110   백화점    138   10 20151220    10  25000      1
## 5: 8002   2110   백화점    138   10 20151220    10  21000      1
glimpse(shopping) ## 컬럼 요약
## Observations: 3,641,082
## Variables: 9
## $ ID       <int> 4008, 6379, 6379, 8002, 8002, 8002, 7252, 5072, 5072,...
## $ RCT_NO   <int> 2108, 2109, 2109, 2110, 2110, 2110, 2111, 2112, 2112,...
## $ BIZ_UNIT <chr> "백화점", "백화점", "백화점", "백화점", "백화점", "백화점", "백화점", "백화점...
## $ PD_S_C   <int> 215, 75, 149, 138, 138, 558, 13, 223, 216, 121, 121, ...
## $ BR_C     <int> 2, 29, 4, 10, 10, 4, 29, 2, 2, 2, 2, 37, 37, 1, 2, 29...
## $ DE_DT    <int> 20150216, 20150213, 20150115, 20151220, 20151220, 201...
## $ DE_HR    <int> 13, 11, 10, 10, 10, 10, 10, 12, 12, 11, 11, 14, 14, 1...
## $ BUY_AM   <int> 59600, 35000, 85000, 25000, 21000, 79200, 5400, 15800...
## $ BUY_CT   <int> 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,...
summary(shopping) ## 값 요약
##        ID            RCT_NO         BIZ_UNIT             PD_S_C      
##  Min.   :    1   Min.   :     1   Length:3641082     Min.   :   1.0  
##  1st Qu.: 3861   1st Qu.: 59806   Class :character   1st Qu.: 123.0  
##  Median : 7463   Median :135039   Mode  :character   Median : 437.0  
##  Mean   : 8332   Mean   :156403                      Mean   : 568.9  
##  3rd Qu.:12516   3rd Qu.:239189                      3rd Qu.: 993.0  
##  Max.   :20000   Max.   :481781                      Max.   :1627.0  
##       BR_C            DE_DT              DE_HR          BUY_AM         
##  Min.   :   1.0   Min.   :20141229   Min.   : 0.0   Min.   :        0  
##  1st Qu.:  11.0   1st Qu.:20150404   1st Qu.:14.0   1st Qu.:     2000  
##  Median :  36.0   Median :20150630   Median :16.0   Median :     4480  
##  Mean   : 185.4   Mean   :20150622   Mean   :16.3   Mean   :    24818  
##  3rd Qu.: 106.0   3rd Qu.:20150925   3rd Qu.:19.0   3rd Qu.:    10000  
##  Max.   :4828.0   Max.   :20151231   Max.   :23.0   Max.   :166030000  
##      BUY_CT        
##  Min.   :    1.00  
##  1st Qu.:    1.00  
##  Median :    1.00  
##  Mean   :   12.49  
##  3rd Qu.:    1.00  
##  Max.   :10050.00
paste("shopping 테이블의 총 데이터 건수 : ",nrow(shopping) )
## [1] "shopping 테이블의 총 데이터 건수 :  3641082"

4.2.1 ID

paste("ID 갯수는 중복 없이", length(unique(shopping$ID)),"개 입니다.")
## [1] "ID 갯수는 중복 없이 18550 개 입니다."
  • 전체 등록 회원 수는 20,000명이었던 반면, 실제 유통 구매데이터가 1건이라도 있는 회원 수는 18,550명으로 나타났다.
## 영수증 번호 유니크
temp <- unique(paste(shopping$RCT_NO,shopping$BIZ_UNIT))
cnt_customer_buying <- sum(temp==temp) ## 갯수 카운트

## 아이디 유니크
temp2 <- unique(customer$ID)
unique_customer_buying <- sum(temp2==temp2) ## id의 unique를 확인

avg_buying_count <- cnt_customer_buying / unique_customer_buying
paste("회원 한명당 평균 구매 건수는", round(avg_buying_count, 1), "건 입니다.")
## [1] "회원 한명당 평균 구매 건수는 52.6 건 입니다."

4.2.2 RCT_NO

ggplot(shopping, aes(x = RCT_NO, color = RCT_NO, fill = RCT_NO)) +
  geom_bar()

  • 영수증번호(RCT_NO)의 경우 25건 이상이 일정부분 이상치인 것으로 관측됨
rctCnt_over_25 <- shopping %>%
  group_by(RCT_NO, BIZ_UNIT) %>%
  summarise( cntRct = n() ) %>%
  filter( cntRct > 25 )

rctno_over_25 <- rctCnt_over_25$RCT_NO
paste("전체 영수증 중의 약 ",round(nrow(unique(rctCnt_over_25)) / length(unique(shopping$RCT_NO)), 3)*100, "% 가 25건 이상 구매함")
## [1] "전체 영수증 중의 약  1.3 % 가 25건 이상 구매함"
shopping_rctCnt_over_25 <- shopping[shopping$RCT_NO %in% rctno_over_25,]

## 평균 구매액
paste("전체 평균 구매액 : ", round(mean(shopping$BUY_AM), 1), "원" ) 
## [1] "전체 평균 구매액 :  24818.4 원"
paste("25건 이상 구매한 건의 평균 구매액 : ", round(mean(shopping_rctCnt_over_25$BUY_AM), 1), "원" )
## [1] "25건 이상 구매한 건의 평균 구매액 :  11824.3 원"
  • 전체 영수증 중 25건 이상 구매한 건의 특징 분석 결과, 오히려 많은 갯수를 구매한 영수증일수록 평균 거래금액이 약 만원가량 낮았다.
count_customer_shopping <-
  sqldf('select "ID", count("RCT_NO") as RCT_NO
        from shopping
        group by ID
        order by count(RCT_NO) desc'
  )

head(count_customer_shopping)
##      ID RCT_NO
## 1 16742   5469
## 2  9677   3417
## 3  9990   3306
## 4   178   3187
## 5 12178   2520
## 6  4443   2341
  • 횟수로 최고 VIP 16742 회원, 2015년 기준 5469번 결제했다.
id16742 <- sqldf('select "ID", sum("BUY_AM")
      from shopping
      where ID = 16742')

head(id16742)
##      ID sum("BUY_AM")
## 1 16742      13092690
id_BUYAM_rank <- sqldf('select "ID", sum("BUY_AM")
                       from shopping
                       group by ID
                       order by sum(BUY_AM) desc')

head(id_BUYAM_rank)
##      ID sum("BUY_AM")
## 1 13087     611749918
## 2  7278     342051200
## 3  2807     323160907
## 4  9038     310334084
## 5  6663     284605677
## 6  2363     273316980
  • 하지만, 구매 건수가 많다고 해서 구매금액 기준으로 높은 순위를 기록하지는 않았다.

4.2.3 BIZ_UNIT

prop.table(table(shopping$BIZ_UNIT))
## 
##     대형마트 드러그스토어       백화점     슈퍼마켓       편의점 
##  0.474334827  0.006119335  0.256163690  0.207160399  0.056221749
ggplot(shopping, aes(x=BIZ_UNIT, color = BIZ_UNIT, fill = BIZ_UNIT)) + 
  geom_bar(width=0.5) +
  ggtitle("LPOINT 회원 채널별 이용 건수 비율")

- 대형마트(47.4%)에서 주로 포인트 적립을 한다는 것을 알 수 있었다.

4.2.4 DE_DT

month <- substr(shopping$DE_DT, 5, 6)

shopping%>%
  ggplot(., aes(x=month, color=month, fill=month))+
  geom_bar()+
  ggtitle("월별 분포")

4.2.5 DE_HR

shopping%>%
  ggplot(., aes(x=DE_HR))+
  geom_bar()+
  ggtitle("시간별 분포")

4.2.6 BUY_AM, BUY_CT ~ 평균 이용금액, 평균 이용건수

## 이용금액
## 평균
sum(as.numeric(shopping$BUY_AM)) / length(unique(shopping$ID)) # 평균 4,871,479원
## [1] 4871479
## 중앙값
shopping%>%
  group_by(ID)%>%
  summarise(AMOUNT = sum(BUY_AM))%>%
  arrange(AMOUNT)%>%
  summarise(mid = median(AMOUNT)) # 중앙값 1,846,396원 
## # A tibble: 1 x 1
##       mid
##     <dbl>
## 1 1846396
## 사분위수  
id_amount <- shopping%>%
  group_by(ID)%>%
  summarise(AMOUNT = sum(BUY_AM))%>%
  arrange(AMOUNT)
quantile(id_amount$AMOUNT)
##        0%       25%       50%       75%      100% 
##       400    486750   1846396   4875316 611749918
  • 평균이 3사분위수와 거의 비슷한 수치를 보이고 있는데 이 말은 즉, 고객의 75%가 평균보다 적은 금액을 사용했고 상위 25%만이 평균보다 높은 금액을 사용한 것으로 해석된다.
## ID당 방문횟수
## 평균 방문횟수
x0 <- shopping %>%
  group_by(RCT_NO, BIZ_UNIT) %>%
  summarise( n = n())

round( nrow(x0) / length(unique(shopping$ID)) , 2 )
## [1] 56.68
## 중앙값
x <- shopping %>%
  mutate( temp = paste(RCT_NO, BIZ_UNIT)) %>%
  select(ID, temp, BUY_CT) %>%
  group_by(ID, temp) %>%
  summarise( count_ID_visit = length(BUY_CT) )

x <- x %>%
  group_by(ID) %>%
  summarise(count_visit_id = n())

paste("방문횟수의 중앙값은", median(as.vector(unlist(x[2]))) ,"입니다.")
## [1] "방문횟수의 중앙값은 35 입니다."
## 사분위수
quantile(as.vector(unlist(x[2])))
##   0%  25%  50%  75% 100% 
##    1   11   35   82 1192
quantile(as.vector(unlist(x[2])), 0.65)
## 65% 
##  59
data.table(sort(as.vector(unlist(x[2])))) %>%
  ggplot(. , aes(x= c(1:18550) , y = V1 )) +
  geom_line() +
  ggtitle("ID별 방문횟수 그래프") +
  labs(x = " ", y = "ID별 방문횟수")

정리
  • 사분위수에서 볼 수 있듯이, 평균은 약 65% 지점에 존재하므로 방문횟수가 많은 일부 ID가 평균을 끌어올렸음을 확인할 수 있었다.

  • 그래프에서 볼 수 있듯이, 그래프의 기울기가 급등하는 구간이 존재하므로 일부 헤비유져가 존재함을 알 수 있다.

4.3 쇼핑외 업종 테이블 (nonshopping)

head(shopping, 5) ## head를 통한 테이블 뷰 생성
##      ID RCT_NO BIZ_UNIT PD_S_C BR_C    DE_DT DE_HR BUY_AM BUY_CT
## 1: 4008   2108   백화점    215    2 20150216    13  59600      2
## 2: 6379   2109   백화점     75   29 20150213    11  35000      1
## 3: 6379   2109   백화점    149    4 20150115    10  85000      1
## 4: 8002   2110   백화점    138   10 20151220    10  25000      1
## 5: 8002   2110   백화점    138   10 20151220    10  21000      1
glimpse(shopping) ## 컬럼 요약
## Observations: 3,641,082
## Variables: 9
## $ ID       <int> 4008, 6379, 6379, 8002, 8002, 8002, 7252, 5072, 5072,...
## $ RCT_NO   <int> 2108, 2109, 2109, 2110, 2110, 2110, 2111, 2112, 2112,...
## $ BIZ_UNIT <chr> "백화점", "백화점", "백화점", "백화점", "백화점", "백화점", "백화점", "백화점...
## $ PD_S_C   <int> 215, 75, 149, 138, 138, 558, 13, 223, 216, 121, 121, ...
## $ BR_C     <int> 2, 29, 4, 10, 10, 4, 29, 2, 2, 2, 2, 37, 37, 1, 2, 29...
## $ DE_DT    <int> 20150216, 20150213, 20150115, 20151220, 20151220, 201...
## $ DE_HR    <int> 13, 11, 10, 10, 10, 10, 10, 12, 12, 11, 11, 14, 14, 1...
## $ BUY_AM   <int> 59600, 35000, 85000, 25000, 21000, 79200, 5400, 15800...
## $ BUY_CT   <int> 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,...
summary(shopping) ## 값 요약
##        ID            RCT_NO         BIZ_UNIT             PD_S_C      
##  Min.   :    1   Min.   :     1   Length:3641082     Min.   :   1.0  
##  1st Qu.: 3861   1st Qu.: 59806   Class :character   1st Qu.: 123.0  
##  Median : 7463   Median :135039   Mode  :character   Median : 437.0  
##  Mean   : 8332   Mean   :156403                      Mean   : 568.9  
##  3rd Qu.:12516   3rd Qu.:239189                      3rd Qu.: 993.0  
##  Max.   :20000   Max.   :481781                      Max.   :1627.0  
##       BR_C            DE_DT              DE_HR          BUY_AM         
##  Min.   :   1.0   Min.   :20141229   Min.   : 0.0   Min.   :        0  
##  1st Qu.:  11.0   1st Qu.:20150404   1st Qu.:14.0   1st Qu.:     2000  
##  Median :  36.0   Median :20150630   Median :16.0   Median :     4480  
##  Mean   : 185.4   Mean   :20150622   Mean   :16.3   Mean   :    24818  
##  3rd Qu.: 106.0   3rd Qu.:20150925   3rd Qu.:19.0   3rd Qu.:    10000  
##  Max.   :4828.0   Max.   :20151231   Max.   :23.0   Max.   :166030000  
##      BUY_CT        
##  Min.   :    1.00  
##  1st Qu.:    1.00  
##  Median :    1.00  
##  Mean   :   12.49  
##  3rd Qu.:    1.00  
##  Max.   :10050.00
paste("nonshopping 테이블의 총 데이터 건수 : ",nrow(nonshopping) )
## [1] "nonshopping 테이블의 총 데이터 건수 :  178659"

4.3.1 ID

print(paste("쇼핑외업종을 이용한 고객은 ", length(unique(nonshopping$ID)),"명 입니다.", sep=''))
## [1] "쇼핑외업종을 이용한 고객은 17621명 입니다."

4.3.2 RCT_NO

prop.table(table(nonshopping$BIZ_UNIT))
## 
##         면세점       야구관람         여행사         영화관           카페 
##   0.0987075938   0.0028154193   0.0003862106   0.3360535993   0.2137647698 
##       테마파크 패밀리레스토랑     패스트푸드           호텔 
##   0.0705030253   0.0174186579   0.2393218366   0.0210288874
nonshopping %>%
  ggplot(. , aes(x=BIZ_UNIT, color = BIZ_UNIT, fill = BIZ_UNIT)) +
  geom_bar() +
  ggtitle("쇼핑외 업종 분포")

  • 주로 이용하는 쇼핑외업종은 영화관, 패스트푸드, 카페 순으로 나타났다.

4.3.3 CRYM

month <- substr(nonshopping$CRYM, 5, 6)

nonshopping %>%
  select(CRYM) %>%
  ggplot(., aes(x=month, color = month, fill = month)) +
  geom_bar() +
  ggtitle(" 월별 분포 ")

4.3.4 U_AM

temp <- sum(as.numeric(nonshopping$U_AM)) / length(unique(nonshopping$ID))
paste("1인당 고객당 비유통 평균 거래금액 : ", round(temp,1), "원")
## [1] "1인당 고객당 비유통 평균 거래금액 :  690969.8 원"
nonshopping %>%
  group_by(ID) %>%
  summarise(AMOUNT = sum(U_AM)) %>%
  ggplot(., aes(x=ID, y=AMOUNT)) +
  geom_line()

## 이용금액이 월등히 높은 고객 분석
nonshopping%>%
  group_by(ID)%>%
  summarise(AMOUNT = sum(U_AM))%>%
  arrange(desc(AMOUNT)) # 고객번호 16002
## # A tibble: 17,621 x 2
##       ID    AMOUNT
##    <int>     <int>
##  1 16002 358939042
##  2  6531 159791375
##  3  6207 144450199
##  4  1522  77452905
##  5   291  65521067
##  6 14858  59167863
##  7  1497  51070225
##  8 13014  45284700
##  9   483  45088310
## 10  1151  30696600
## # ... with 17,611 more rows
nonshopping[nonshopping$ID==16002, ] # 면세점만 이용했음
##        ID BIZ_UNIT   CRYM     U_AM U_CT
##  1: 16002   면세점 201504 50849507   67
##  2: 16002   면세점 201503 46202292   69
##  3: 16002   면세점 201505 36209031   47
##  4: 16002   면세점 201512 16731357   15
##  5: 16002   면세점 201510 12165358   10
##  6: 16002   면세점 201508 23777476   17
##  7: 16002   면세점 201509 16122565   12
##  8: 16002   면세점 201507 24658081   26
##  9: 16002   면세점 201511  8846315   11
## 10: 16002   면세점 201506 44386764   53
## 11: 16002   면세점 201501 42293614   58
## 12: 16002   면세점 201502 36696682   59
  • ID가 16002인 회원이 압도적으로 구매금액이 높은데, 모든 거래가 면세점 (B03)에서 이루어진 것을 알 수 있었다.

4.3.5 U_CT

temp <- nonshopping %>%
  group_by(ID) %>%
  summarise(COUNT = sum(U_CT)) %>%
  summarise(AVG_COUNT = mean(COUNT)) # 18.52398

paste("1인당 고객당 비유통 평균 거래건수 : ", round(temp,1), "건")
## [1] "1인당 고객당 비유통 평균 거래건수 :  18.5 건"
nonshopping%>%
  group_by(ID)%>%
  summarise(COUNT = sum(U_CT))%>%
  ggplot(., aes(x=ID, y=COUNT))+
  geom_line()

## 이용건수가 월등히 높은 고객 분석
nonshopping%>%
  group_by(ID)%>%
  summarise(COUNT=sum(U_CT))%>%
  arrange(desc(COUNT))
## # A tibble: 17,621 x 2
##       ID COUNT
##    <int> <int>
##  1   291   601
##  2  6207   470
##  3 16002   444
##  4 18429   336
##  5  3206   296
##  6  4445   261
##  7  1090   256
##  8  7093   242
##  9  1273   240
## 10  6922   239
## # ... with 17,611 more rows
nonshopping[nonshopping$ID==291, ]
##      ID   BIZ_UNIT   CRYM    U_AM U_CT
##  1: 291     면세점 201508 3542827   52
##  2: 291     면세점 201507 4517031   54
##  3: 291       카페 201504    8120    1
##  4: 291     면세점 201502 5772774   60
##  5: 291     면세점 201501 5335658   27
##  6: 291 패스트푸드 201508   14100    5
##  7: 291     면세점 201504 5583184   36
##  8: 291 패스트푸드 201506    5900    2
##  9: 291     면세점 201510 5465033   39
## 10: 291 패스트푸드 201503   30400   10
## 11: 291 패스트푸드 201505   54600    8
## 12: 291     면세점 201503 7291577   51
## 13: 291   테마파크 201501    6500    1
## 14: 291 패스트푸드 201512   34700    5
## 15: 291       카페 201509   11500    1
## 16: 291       호텔 201505   45200    1
## 17: 291 패스트푸드 201509   29900    7
## 18: 291 패스트푸드 201504   57900   13
## 19: 291 패스트푸드 201502   14200    6
## 20: 291     면세점 201511 5742657   50
## 21: 291     면세점 201512 3741056   33
## 22: 291 패스트푸드 201501   23800    3
## 23: 291       카페 201506   14400    1
## 24: 291 패스트푸드 201511   35100    6
## 25: 291       호텔 201504   42000    1
## 26: 291 패스트푸드 201510   32100    6
## 27: 291       카페 201505    7520    1
## 28: 291   테마파크 201502   24000    2
## 29: 291     면세점 201506 4660284   32
## 30: 291     면세점 201505 9222506   48
## 31: 291     면세점 201509 4128340   34
## 32: 291 패스트푸드 201507   26200    5
##      ID   BIZ_UNIT   CRYM    U_AM U_CT
temp <- nonshopping[nonshopping$ID==291, ]

temp %>%
  select(BIZ_UNIT, U_CT, U_AM) %>%
  ggplot(. , aes(x = BIZ_UNIT, y = U_CT, color = BIZ_UNIT, fill = BIZ_UNIT))+
  geom_bar(stat = "identity")

  • 구매 건수가 높은 ID의 경우에도 면세점 사랑은 계속 되었다.
nonshopping%>%
  group_by(MONTH=substr(nonshopping$CRYM,5,6),BIZ_UNIT)%>%
  summarise(COUNT=sum(U_CT))%>%
  ggplot(., aes(x=MONTH, y=COUNT, group=BIZ_UNIT, colour=BIZ_UNIT))+
  geom_line()+
  facet_wrap(~BIZ_UNIT)

  • 영화관의 이용건수가 6월부터 8월까지 가파르게 상승!
  • 베테랑 / 암살 등 흥행영화가 그 시기에 상영

4.3.6 BIZ_UNIT + CRYM + U_AM

nonshopping%>%
  group_by(MONTH=substr(nonshopping$CRYM,5,6),BIZ_UNIT)%>%
  summarise(AMOUNT=sum(U_AM))%>%
  ggplot(., aes(x=MONTH, y=AMOUNT, group=BIZ_UNIT, colour=BIZ_UNIT))+
  geom_line()+
  facet_wrap(~BIZ_UNIT)

  • 면세점의 이용금액이 8월에서 9월 사이 급격히 하락!
  • 메르스의 여파로 소비심리가 위축된 것으로 판단

4.3.7 DE_DT

shopping%>%
  group_by(month=substr(DE_DT, 5,6),BIZ_UNIT)%>%
  summarise(count=length(ID))%>%
  ggplot(., aes(x=month, y=count, group=BIZ_UNIT, color=BIZ_UNIT))+
  geom_line()

  • 면세점의 경우 시즌에 따른 변동 폭이 상대적으로 다른 계열사보다 더 크게 나타났다.
## 시간대별
shopping%>%
  group_by(DE_HR,BIZ_UNIT)%>%
  summarise(count=length(ID))%>%
  ggplot(., aes(x=DE_HR, y=count, group=BIZ_UNIT, color=BIZ_UNIT))+
  geom_line()

  • 대형마트나 슈퍼마켓의 경우 저녁 식사 시간(보통18시)이 지나면 고객이 좀 줄어드는 것을 확인할 수 있었다.

5. 파생변수 생성 (Feature Engineering)

5.1 테이블 병합

고객정보와 구매정보 merge
customer_shopping <- merge(customer, shopping, by="ID", all.y = TRUE)
customer_shopping$GENDER <- as.character(customer_shopping$GENDER)
customer_shopping$GENDER <- ifelse(customer_shopping$GENDER=='1','Male','Female')
고객정보와 쇼핑외업종 merge
customer_nonshopping <- merge(customer, nonshopping, by="ID", all.y = TRUE)
customer_nonshopping$GENDER <- as.character(customer_nonshopping$GENDER)
customer_nonshopping$GENDER <- ifelse(customer_nonshopping$GENDER=='1','Male','Female')

5.2 파생변수 생성

## 영수증번호와 업종 합친 파생변수 생성
customer_shopping$RCT_BIZ <- paste(customer_shopping$RCT_NO, customer_shopping$BIZ_UNIT, sep='')

## 월 변수 생성
customer_shopping$MONTH <- substr(customer_shopping$DE_DT, 5,6)
customer_nonshopping$MONTH <- substr(customer_nonshopping$CRYM, 5,6)

## 요일 변수 생성
customer_shopping$DE_DT <- as.character(customer_shopping$DE_DT)
customer_shopping$DE_DT <- as.Date(customer_shopping$DE_DT, "%Y%m%d")

customer_shopping$DAY <- paste(format(as.Date(customer_shopping$DE_DT)-1, '%w'),
                               format(as.Date(customer_shopping$DE_DT), '%A'), sep='')

6. 연관 관계 시각화 (Relationship Visulization)

6.1 성별에 따른 쇼핑업종/쇼핑외업종 이용건수 분석

6.1.1 성별 + 쇼핑업종 + 월별 + 이용건수(영수증번호와 업종 합친 파생변수 생성)

customer_shopping%>%
  group_by(BIZ_UNIT, MONTH, GENDER)%>%
  summarise(count = length(RCT_BIZ))%>%
  ggplot(., aes(x=MONTH, y=count, group=GENDER, colour=GENDER))+
  geom_line()+
  facet_wrap(~BIZ_UNIT)

  • 롯데마트의 8월에서 10월까지 이용객 수 하락은 가습기 살균제 사건의 여파로 추정할 수 있다.

  • 여행사와 호텔만 따로 비교 실시

customer_nonshopping%>%
  filter(BIZ_UNIT %in% c('여행사','호텔'))%>%
  group_by(BIZ_UNIT, MONTH, GENDER)%>%
  summarise(count = length(ID))%>%
  ggplot(., aes(x=MONTH, y=count, group=GENDER, colour=GENDER))+
  geom_line()+
  facet_wrap(~BIZ_UNIT)

  • 여행사와 호텔의 관계를 보기 위해 따로 봤지만 둘 사이의 관계는 딱히 찾을 수 없었다.

  • 다만 호텔은 남자가 오히려 이용건수가 많다.

6.1.2 성별 + 쇼핑업종 + 월별 + 이용건수(영수증번호와 업종 합친 파생변수 생성)

연령대에 따른 쇼핑업종/쇼핑외업종 이용 분석
연령대 + 쇼핑업종 + 월별 + 이용건수(영수증번호와 업종 합친 파생변수 생성)
customer_shopping%>%
  group_by(BIZ_UNIT, MONTH, AGE_PRD)%>%
  summarise(count = length(RCT_BIZ))%>%
  ggplot(., aes(x=MONTH, y=count, group=AGE_PRD, colour=AGE_PRD))+
  geom_line()+
  facet_wrap(~BIZ_UNIT)

  • 대형마트와 슈퍼마켓은 40대 고객이 가장 많았으나 백화점은 50대가 가장 많았다.
반응형
Posted by JoeSung
,


## 폰트 설정 패키지 설치

install.packages("extrafont")

library(extrafont)


## 존재하는 모든 폰트 불러오기

font_import()


## 폰트 설정

theme_set(theme_gray(base_family='NanumGothic'))

## 혹은

theme_set(theme_gray(base_family='AppleMyungjo'))




참고 : http://www.mind-mining.co.kr/2016/05/using-r-mac.html

반응형
Posted by JoeSung
,