Python/데이터분석 공부

[Python] 03장 _ 고객의 전체 모습을 파악하는 테크닉

dori_0 2022. 2. 16. 22:13

파이썬 데이터 분석 실무 테크닉 100

03장 _ 고객의 전체 모습을 파악하는 테크닉 [ 머신러닝 ]

 


1. 데이터 불러오고 확인하기

import pandas as pd

use_log = pd.read_csv("c:/data/use_log.csv")
customer_m = pd.read_csv("c:/data/customer_master.csv")
class_m = pd.read_csv("c:/data/class_master.csv")
campaign_m = pd.read_csv("c:/data/campaign_master.csv")

use_log.head()
customer_m.head()
class_m.head()
campaign_m.head()
use_log.head()
customer_m.head()
class_m.head()
 
campaign_m.head()

 

   

2. 고객 데이터 가공하기

customer_m에 class_m과 campaign_m을 결합하자
# customer_m에 class_m 결합
customer_join = pd.merge(customer_m, class_m, on="class", how="left")
# campaign_m 결합
customer_join = pd.merge(customer_join, campaign_m, on="campaign_id", how="left")

customer_join.head()

print(len(customer_m))  # 4192
print(len(customer_join))  # 4192

 

데이터 개수도 join 전후로 변화가 없는 것이 확인됩니다.

 

조인할 때 key가 없거나 join이 잘못되면 자동으로 결측치가 생긴다.

따라서 조인 후 결측치를 확인해야 한다.

# 결측치 확인
customer_join.isnull().sum()

 조인하며 추가한 열은 결측치가 0이므로 문제가 없어보입니다.

 

  

3. 고객 데이터를 집계하자

데이터 가공을 끝냈으니 고객 데이터를 집계해서 전체 모습을 살펴보자

 

1. class_name별로 집계

customer_join.groupby("class_name").count()["customer_id"]
  •  종일 반이 절반정도를 차지하고, 종일/야간/주간 순으로 회원이 많다.

 

 

2. campaign_name별로 집계

customer_join.groupby("campaign_name").count()["customer_id"]
  •  캠페인은 일반 입회가 가장 많다.

 

 

3. gender별로 집계

customer_join.groupby("gender").count()["customer_id"]
  • 여자보다 남자가 더 많다.

 

 

4. is_deleted별로 집계

customer_join.groupby("is_deleted").count()["customer_id"]
  •  2019년 3월 현재 가입된 회원은 2842명, 탈퇴한 유저는 1350명이다.

 

 

# 2018.04.01 ~ 2019.03.31에 가입한 인원은 몇 명일까? #

# 2018.04.01 ~ 2019.03.31 가입 인원 집계해보자
# 궁금한 부분 각자 해보기
customer_join["start_date"] = pd.to_datetime(customer_join["start_date"])
customer_start = customer_join.loc[customer_join["start_date"] > pd.to_datetime("20180401")]
len(customer_start)  # 1361

 

 

4. 최신 고객 데이터 집계하기

가장 최근 월 (2019년 3월)의 고객 데이터를 파악해보자

# end_date를 datetime형으로 변환
customer_join["end_date"] = pd.to_datetime(customer_join["end_date"])

# 2019.03.31에 탈퇴한 회원 & 재적 중인 고객 추출
customer_newer = customer_join.loc[
    (customer_join["end_date"] >= pd.to_datetime("20190331")) | 
    (customer_join["end_date"].isna())]
print(len(customer_newer))
customer_newer["end_date"].unique()

  • 2019.03.31에 탈퇴한 고객, 탈퇴하지 않은 고객은 총 2953명이다.

 

 

회원별, 캠페인별, 성별로 전체를 파악해보자

# 회원별
customer_newer.groupby("class_name").count()["customer_id"]

# 캠페인별
customer_newer.groupby("campaign_name").count()["customer_id"]

# 성별
customer_newer.groupby("gender").count()["customer_id"]

왼 : 전체 기간 / 오 : 2019년 3월

 

  • 회원별, 성별은 전체기간과 19년 03월의 비율 차이가 크지 않다.
  • 캠페인에서 일반이 차지하는 비율은 전체기간일 때 72%, 19년 03월은 81%이다.
  • 입회 캠페인이 회원 비율 변화에 영향을 미친다고 추측할 수 있다.

 

 

5. 이용 데이터 집계하기

고객 데이터와 달리 이용 데이터는 시간적인 요소를 분석할 수 있다.

이용 데이터를 이용해 고객을 파악해보자

 

1. 연월, 고객별 이용 횟수 집계

# usedate를 datetime형으로 바꾸기
use_log["usedate"] = pd.to_datetime(use_log["usedate"])
use_log["연월"] = use_log["usedate"].dt.strftime("%Y%m")
# 연월, id로 그룹화하기
use_log_months= use_log.groupby(["연월", "customer_id"], as_index = False).count()
# 컬럼 이름 바꾸기
use_log_months.rename(columns={"log_id":"count"}, inplace=True)

del use_log_months["usedate"]
use_log_months.head()

 

 

2. 고객별 월 이용 횟수 집계 (평균값, 중앙값, 최댓값, 최솟값)

use_log_customer = use_log_months.groupby("customer_id").agg(["mean", "median", "max", "min"])["count"]
use_log_customer = use_log_customer.reset_index(drop=False) # 칼럼 정리
use_log_customer.head()

 

 

6. 이용 이력 데이터로부터 정기 이용 플래그 작성하기

정기적으로 센터를 이용하는 고객을 특정해보자 (매주 같은 요일에 왔는지 아닌지로 판단)

 

1. 고객별 월/요일 집계

# 요일을 숫자로 변환
use_log["weekday"] = use_log["usedate"].dt.weekday

use_log_weekday = use_log.groupby(["customer_id", "연월", "weekday"]
                                  , as_index=False).count()[["customer_id", "연월", "weekday", "log_id"]]
use_log_weekday.rename(columns={"log_id":"count"}, inplace=True)
use_log_weekday.head()

  • AS002855 회원은 2018년 4월, 2018년 5월 모두 토요일에 4번 방문한 것으로 보아 매주 토요일에 정기적으로 방문하는 것으로 보입니다.

 

 

2. 고객별 최댓값 구하고, 최댓값이 4 이상인 경우 플래그 지정

use_log_weekday = use_log_weekday.groupby("customer_id", as_index=False).max()[["customer_id", "count"]]
# routine_flg 컬럼 만들고 플래그 지정
use_log_weekday["routine_flg"] = 0
use_log_weekday["routine_flg"] = use_log_weekday["routine_flg"].where(use_log_weekday["count"]<4, 1)
use_log_weekday.head()

 

 

7. 고객 데이터와 이용 이력 데이터 결합하기

customer_join에 use_log_customer과 use_log_weekday를 결합하자

customer_join = pd.merge(customer_join, use_log_customer, on="customer_id", how="left")
customer_join = pd.merge(customer_join, use_log_weekday[["customer_id", "routine_flg"]],
                        on="customer_id", how="left")
customer_join.head()

 

 

8. 회원 기간 계산하기

이용 이력(시간적인 변화 데이터)를 추가했기 때문에 회원 기가 칼럼을 하나 더 추가해두자

# 날짜 비교 함수 relativedelta 사용하기 위해 import
from dateutil.relativedelta import relativedelta

# 날짜 계산용 칼럼 생성
customer_join["calc_date"] = customer_join["end_date"]
customer_join["calc_date"] = customer_join["calc_date"].fillna(pd.to_datetime("20190430"))

# 기간 컬럼 
customer_join["membership_period"] = 0
for i in range(len(customer_join)):
    delta = relativedelta(customer_join["calc_date"].iloc[i],
                         customer_join["start_date"].iloc[i])
    customer_join["membership_period"].iloc[i] = delta.years*12 + delta.months
customer_join.head()

회원 기간 칼럼이 잘 추가된 것을 확인할 수 있다.

 

 

9. 고객 행동의 각종 통계량 파악하기

1. mean, median, max, min의 통계량 파악하기

customer_join[["mean", "median", "max", "min"]].describe()

 

2. 정기적/비정기적인 회원수 집계

# 정기적/비정기적인 회원수 집계
customer_join.groupby("routine_flg").count()["customer_id"]

  • 정기적으로 이용하는 회원의 수가 훨씬 많다.

 

3. 회원 기간의 분포 파악

# 회원 기간의 분포 파악
import matplotlib.pyplot as plt
%matplotlib inline
plt.hist(customer_join["membership_period"])

  • 회원 기간이 10개월 이내인 고객이 많다.
  • 10개월 이상의 회원 수는 거의 일정하다.

 

 

10. 탈퇴 회원과 지속 회원의 차이 파악하기

1. 탈퇴 회원

# 탈퇴 회원
customer_end = customer_join.loc[customer_join["is_deleted"]==1]
customer_end.describe()

 

2. 지속 회원

# 지속 회원
customer_stay = customer_join.loc[customer_join["is_deleted"]==0]
customer_stay.describe()

 

  • 평균, 중앙값, 최댓값, 최솟값 모두 지속 회원보다 탈퇴 회원이 작다.
  • 평균값과 중앙값은 1.5배 정도 차이가 난다.
  • 지속 회원은 0.98로 정기적으로 이용하는 것을 알 수 있지만, 탈퇴 회원은 0.45로 절반정도는 랜덤하게 이용하고 있다.

 

# csv로 출력하기
customer_join.to_csv("customer_join.csv", index=False)