django로 회원가입 기능 구현을 하게되면 로그인시에 username으로 로그인을 해야되는 번거로움을 만나게 된다. 요즘의 상용서비스들이라면 대개 email을 회원가입 구분자로 사용하는 경우가 많기 때문에 기본 세팅을 변경해줘야만 한다. 아래의 레퍼런스를 통해서 해결해보자

 

*레퍼런스

 

https://wsvincent.com/django-login-with-email-not-username/

 

Django Log In with Email not Username - Will Vincent

Django was first released in 2005 and since then a lot has changed in web development, notably the predominant pattern at the time of using username/email/password has been simplified to just email/password. However due to legacy reasons around the built-i

wsvincent.com

 

https://kamang-it.tistory.com/entry/Django-10login-logout

 

[Django-10]login, logout

참고: [Web Applicateion]서버 사이드와 클라이언트 사이드,백앤드와 프론트앤드 pip install django로 반드시 장고를 설치하여야한다. 또한 장고의 버전은 2이므로 1을 사용하는 사람들의 경우 서로 많이 차이날..

kamang-it.tistory.com

 

반응형
Posted by JoeSung
,

생각보다 구글 다큐먼트도 숨겨져 있어서...
Url을 생성하라는데 도대체 뭘 보고 생성해여 하는지 모르겠어서 한참보다가 찾은 도큐멘트다.

https://cloud.google.com/firestore/docs/manage-data/export-import

Bucket을 생성하는건 gsutil이라는 명령어를 쓰면 되나본데 그 생성된 bucket에 데이터를 넣기 위해서는 gclould 명령어 상의 export 기능을 써야하는듯
반응형
Posted by JoeSung
,

그냥 우분투에서 하세요 (제발)

 

 

래퍼런스

http://sacharya.com/crawling-anonymously-with-tor-in-python/

 

Crawling anonymously with Tor in Python – S Acharya

There are a lot of valid usecases when you need to protect your identity while communicating over the public internet. It is 2013 and so you probably already know about Tor. Most people use Tor through the browser. The cool thing is that you can get access

sacharya.com

https://gist.github.com/KhepryQuixote/46cf4f3b999d7f658853

 

Python script to connect to Tor via Stem and Privoxy, requesting a new connection (hence a new IP as well) as desired.

Python script to connect to Tor via Stem and Privoxy, requesting a new connection (hence a new IP as well) as desired. - PyTorStemPrivoxy.md

gist.github.com

 

ip우회를 통한 크롤링을 하려고 할 때 tor를 주로 사용하게 되는데, 대부분의 가이드는 우분투 환경에 맞추어 작성되어있는 것 같다. (apt-get 명령어라던지)

 

우분투 환경을 설치하기에는 너무 오래걸리는 관계로..  아래는 맥북에서 해보는 tor를 활용한 크롤링 과정이다.

 

TOR 소개

 

https://2019.www.torproject.org/index.html.en

 

윈도우에는 apt관련 명령어로 설치를 하는 것 같은데, 맥에서는 apt대신 brew를 쓴다.

home brew를 설치하자

 

>>brew update

>>brew install tor

>>netstat -anp tcp | grep -i "LISTEN"

 

 

-mac내에서 tor가 설치되는 루트를 확인하면서 진행해야 하는데, 루트는 /usr/local/etc/tor/torrc.sample에 해당한다.

(https://2019.www.torproject.org/docs/tor-doc-osx.html.en) 에서 설치루트를 확인할 수 있다.

-gedit기능이 역시 없으므로, 쓰고 싶다면 .bash_profile 내에 넣어두어야 하는 것 같다.

 

>> cd ~/

>> touch .bash_profile

>> open -e .bash_profile 

>> . .bash_profile

 

>>sudo gedit /usr/local/etc/tor/torrc.sample

 

>> tor --hash-password [비밀번호를 적는곳]

16:2CEA35E6D1F3544F607FAA55812020A11908D2C5FB3DC9406F58A27DFF

 

 

 

ControlPort 9051 # hashed password below is obtained via `tor --hash-password my_password` HashedControlPassword 

16:2CEA35E6D1F3544F607FAA55812020A11908D2C5FB3DC9406F58A27DFF

CookieAuthentication 1

 

 

>> brew install python-stem

>> brew install privoxy

 

and enable forward-socks5 as follows:

>> forward-socks5 / localhost:9050

Restart privoxy after making the change to the configuration file.

>> sudo /etc/init.d/privoxy restart

 

privoxy의 bash 파일을 수정해주고 적용해주려고 하는데.. mac에서는 restart가 안된다. OTL  아니 뭐이리 안되는게 많아 스티브잡스개새끼 윈도우만세 내가 왜 맥북을 쓰고있을까?

 

하지만 여기서 좌절할 내가 아니지.

 

mac에서의 privoxy 사용법을 다시 확인해서 진행해봅니다. 

 

[privoxy 사용법]

https://www.andrewwatters.com/privoxy/

반응형
Posted by JoeSung
,


Group by Count

data4_dt[, ':=' (COUNT = .N, temp = "justTest" ) , by = job_id]



Order By

data4_dt[order(-COUNT), ]



Delete Column

data4_dt$cnt <- NULL

data4_dt[ , cnt := NULL]

data4_dt

반응형
Posted by JoeSung
,



한줄평은 음악 하고 싶게 만드는 영화..


중학교 때 봤던 노다메 칸타빌레의 여주인공 우에노 주리를 보는 재미만으로도 1시간 반이 충분히 즐겁다.

반응형
Posted by JoeSung
,

조금 현실적인 얘기지만 나는 살면서 자유를 얻기 위해서는 돈이 중요하다고 생각했다. 평생 근로소득으로 사는 것 보다는 조금 더 많은 돈이 필요하다고 생각했다.

책의 필자 제현주씨에게 돈은 그런 존재다. 남들 버는 것 보다는 훨씬 많이 벌어본 사람에게 있어서의 돈이 주는 그런 정도의 존재. 돈을 그렇게 많이 가질 수 있다면 우리의 기대대로 걱정도 고민도 없어야 하지 않았을까. 하지만 그렇지 않았던거 같다.


내리막 세상에서 일하는 노마드 제현주씨에게는 벌어들이는 돈이 주는 자유보다, 소비로 부터의 자유를 얻고 스스로 원하는 일이 직업이 아닌 놀이와의 그 어떤 경계선 즈음에 있기를 바랐나보다.


경제적 수준에서 자유로워질 수 있다면, 일은 수익을 추구하는 굴레에서 벗어날 수 있다. 그 방법은 일견 두 가지 같아 보인다. 돈을 너무나도 많이 벌 수 있거나, 그 욕망에서 자유로워 지거나. 하지만, 제현주씨의 경험을 살짝 엿본다면 어쩌면 그 방법은 하나뿐인지도 모르겠다.

내 일의 특성상 10시 이후에 퇴근할 때면 회사의 계산으로 택시를 타곤 하는데, 이 버릇 때문인가 평소에도 내 돈으로 택시를 타게되곤 한다. 소비수준이 올라갔다는 걸 느낄 때 즈음엔 택시가 주는 편안함에 이미 녹아버렸다. 하지만 택시에서 혼자 심심하게 가는것보다는 지하철을 타고 사람들 구경하고 돌아다녀도 충분히 행복했었던 것을 떠올리면, 지금 경제수준이 꼭 필요한건가 물어보게 된다. 지금의 경제 수준이 꼭 필요하지 않다는 결론에 이르게 된다면, 조금은 더 미련없이 적은 돈이더라도 조금 더 가슴 뛰는 일을 향해 박차일어날 수 있게될까.

정말 그저 일일 뿐인데, 먹고사는 것 이상의 의미를 부여하기에는 별 것 아닌 그저 일일 뿐인 것에 나를 투영하고, 욕망을 투여하려는 마음이 비집고 들어온다. 
반응형

'마구적는 일상관' 카테고리의 다른 글

그룹 내의 포지셔닝 :: 이 구역의 미친년은 나야  (0) 2019.06.22
스윙걸스 (2004)  (0) 2018.12.16
Mamas Gun - Pots Of Gold  (0) 2016.12.28
3.4  (0) 2016.03.28
12.12 포이너를 어렵게 만드는 것?!  (0) 2015.12.12
Posted by JoeSung
,



 [ 신경망에 대한 이론 설명 ]


 로센블레트 ( 1958년 퍼셉트론 제안 )


  사람의 뇌 ---------->  컴퓨터를 이용한 지능처리


              ↓                 ↓


  생물학적 신경망내에                     인공신경망에서는

  반복적인 시그널이 발생할 때          가중치라는 것으로

  그 시그널을 기억하는 일종의          기억의 효과를 대체할 수 있음을

  학습효과 있다.                             설명했다.



  1958년 로젠블라트의  퍼셉트론  


                         반복

                          ↓

          1. 뇌 :  신호 ----->  암기



                                가중치

                                  ↓     1 (신호가 흐른다.)

          2. 인공신경망  : 신호 -----> 

                                         0 (신호가 안흐른다.)


인공신경망 기본 그림





컴퓨터            vs               뇌

          ↓                               ↓

     정보를 메모리의                    정보를 저장하는 공간이 

     특정위치에 저장                    따로 없음

                                          ↓

                                     신경세포(뉴런)의 연결관계를

                                     변경하는 방식으로 저장한다.

                                          ↓

                                     신경세포(뉴런)은 그저 다른 

                                     신경세포에서 오는 신호를 받아서

                                     자신의 신호를 내보내는 역할만 한다.



 * 뉴런의 갯수


  1. 사람 : 850억개 

  2. 고양이 ; 10억개

  3. 쥐  : 7500만개

  4. 바퀴벌레 : 몇백만개

  5. 하루살이 : 지금 현재까지 나온 최첨단 인공지능의 

                뉴런수보다 많다.




[코드]  -- > R 스크립트에 복붙 !


# 라이브러리

install.packages("neuralnet")

library(neuralnet)


# Step 1. 

# 먼저 아래의 행렬식을 R로 구현해보세요.

x <- matrix(c(1,2), nrow = 1, ncol = 2)

y <- matrix(c(1:6), nrow = 2 , ncol = 3, byrow = F)

res <- x %*% y

res



# Step 2.

x <- matrix(c(1:6), nrow = 2, ncol = 3, byrow = T)

y <- matrix(c(1:6), nrow = 3, ncol = 2, byrow = T)

res <- x %*% y

res



# Step 3.

x <- matrix(c(5, 11, 17), nrow = 1 , byrow = T)

y <- matrix(c(1:6), nrow = 3, ncol = 2)

z <- x %*% y

a <- matrix(c(1:4), nrow = 2)

z <- z %*% a

z



# Step 4. '순'전파

  # 2nd layer에서 3rd layer로 이동할 때

x <- matrix(c(5, 11, 17), nrow = 1 , byrow = T)

x <- x + c(1,2,3) # Bias 발생 각각 1, 2, 3

y <- matrix(c(1:6), nrow = 3, ncol = 2)

z <- x %*% y

z # 3nd layer의 value


  # 3nd layer에서 4th layer로 이동할 때

z <- z + c(1,2) # Bias 발생

a <- matrix(c(1:4), nrow = 2)

z <- z %*% a

z <- z + c(1,2) # Bias 발생 

z



 

#아래의 공식을 이용해서 시그모이드 함수를 R로 구현하시오

#                             1

# h(x) = ----------------------------- (비선형 함수)

#                      1 + exp(-x)




sigmoid <- function(x){

  return(1 / (1+ exp(-x)))

}


x <- c(1,2,3,4,5,6,7,8,9,10)

sigmoid(x)




반응형
Posted by JoeSung
,




출처 - KB 지식비타민


반응형
Posted by JoeSung
,


분포란? 

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


 - 연속형확률 분포 : 지수분포, 로그정규분포, 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
,