LoginSignup
1
0

More than 1 year has passed since last update.

イシューからはじめるデータ分析②データ加工編

Posted at

はじめに

こちらイシューからはじめるデータ分析①イシュー編の続きとなります。
イシューからはじめるとは全く関係ないため読み飛ばして頂いて構いません!
リークなどに気をつけながらデータを加工していきます。

全体の流れ

2019年1月31日までを学習データ。2019年2月1日以降をテストデータとします。
そのため2019年2月に退会申請するかどうかを予測することを目的とし、データを加工していきます。
1. 顧客データを加工する
2. ログデータを加工する
3. コホート分析

データ加工

使用ライブラリ

# standard
import datetime as dt
from dateutil.relativedelta import relativedelta

# third-party
import numpy as np
import pandas as pd
pd.set_option("max_rows", 500, "max_colwidth", 500, "max_columns", 500)
pd.options.plotting.backend = "plotly"

顧客データを加工する

まず顧客データから読み込んでいきます。

customer = pd.read_csv("./customer_master.csv", parse_dates=["start_date", "end_date"])
# 退会を決めた月は退会前月の末日とする
customer["decide_end_date"] = customer.end_date.apply(lambda d: d.replace(day=1) - relativedelta(days=1) if not pd.isna(d) else d)
print("df_shape", customer.shape)
customer.head()

スクリーンショット 2021-06-17 8.26.57.png
日付のフォーマットが整っていて助かりました(笑)
ここで気になるのが2015年5月1日に入会して、未だに辞めていない人がいることですね。調べてみましょう。

# 2015年内に入会したユーザー
customers_2015 = customer.query("start_date < '2016-01-01'")
print(customers_2015.end_date.isnull().sum())
print(customers_2015.end_date.notnull().sum())

継続中 492
退会済み 0

調べてみると2015年に入会したユーザーは1人も退会していないようですね(驚き)
Prtimes: ON DIARYシステムによると一般的なフィットネスクラブでは、
入会から半年で約70%が退会、1年後には約90%が退会するそうです。
つまり2015年のデータは欠損(入力忘れ等)もしくはデータが人工的に作られている可能性が高いですね。
他の年も調べてみましょう。

# 年ごとに退会割合計算
customer["start_year"] = customer.start_date.dt.year
customer_year =  customer.groupby("start_year")[["is_deleted"]].apply(lambda group: group.sum() / group.count() *100) 
# 年ごとの退会率を棒グラフに
fig = customer_year.plot.bar(title="入会年ごとの退会率")
fig.update_xaxes(title="入会年")
fig.update_yaxes(ticksuffix="%", title="退会率")

退会プロット.png
2015年と2016年のデータが怪しいですね。。
(秀和システムさんに「このデータは実際のジムのデータでしょうか?」「入力漏れなどはありますか?」とお問い合わせしたところ返信が返って来ませんでした泣。そりゃそうですよね。。)
今回は真偽が分からないため、2017年1月1日以降に入会したユーザーを分析対象とし加工してきます。

# 2017年以降の顧客を分析する
customer = customer.query("start_year >= 2017")
# キャンペーンやクラスの情報を結合する
customer = customer.merge(pd.read_csv("./campaign_master.csv"), how="left", on="campaign_id")
customer = customer.merge(pd.read_csv("./class_master.csv"), how="left", on="class")
# 使わない列を消す
customer.drop(columns=["class", "campaign_id", "is_deleted", "start_year"], inplace=True)
customer.head()

スクリーンショット 2021-06-17 8.43.13.png
最後にリークしないよう2019年2月1日以降に知るの情報をMASKし、学習データとします。

# 2019年2月1日以降の知る情報をMASK
customer.loc[customer.decide_end_date >= "2019-02-01", ["end_date", "decide_end_date"]] = np.nan
# 学習データとして書き出し
customer.query("start_date < '2019-02-01'").to_csv("customer_train.csv", index=None)
# 読み込めるか確認
customer = pd.read_csv("./customer_train.csv", parse_dates=["start_date", "end_date", "decide_end_date"])
customer.head()

ログデータを加工する

ログデータを読み込んでいきます。

logs = pd.read_csv("./use_log.csv", parse_dates=["usedate"])
logs.rename(columns={"usedate": "use_date"}, inplace=True)
# 月の初日を抽出
logs["use_month"] = logs.use_date.apply(lambda d: d.replace(day=1))
print(logs.shape)
logs.head()


先ほど分析対象として指定したユーザー以外のログをドロップします。

# 分析対象以外のユーザーログをドロップする
logs = logs.loc[logs.customer_id.isin(customer.customer_id.unique())]
print("logs_shape", logs.shape)

logs_shape (125864, 4)

30%ほどログデータがドロップされました。
最後に2019年1月31日以前を学習データとして書き出します。

logs.query("use_date < '2019-02-01'").to_csv("./logs_train.csv", index=None)
# 読み込めるか確認
logs = pd.read_csv("./logs_train.csv", parse_dates=["use_date", "use_month"])

コホート分析

なんで急に?といった感じですが、
「もしかしたらデータが人工的に作られているのでは?」という仮設を検証していきます。
まずログデータを月毎にまとめ、顧客データと結合していきます。

# あとで会員期間を計算するために使う
def calc_period(s: pd.Series):
    return (s.use_month.year - s.start_month.year) * 12 + (s.use_month.month - s.start_month.month) + 1

monthly_logs = logs.groupby(["customer_id", "use_month"]).log_id.count().reset_index()
monthly_logs = monthly_logs.merge(customer[["customer_id", "start_date"]], how="left", on="customer_id")
monthly_logs["start_month"] = monthly_logs.start_date.apply(lambda d: d.replace(day=1))
monthly_logs["period"] = monthly_logs.apply(calc_period, axis=1)
monthly_logs.head()

sc.png
2018年4月1日からのログデータしかないため、それ以降に入会した顧客を対象にします。

cohort = monthly_logs.query("start_month >= '2018-04-01'")
cohort = cohort.pivot_table(index="start_month", columns="period", values="customer_id", aggfunc="count")
# 継続率を計算
cohort = cohort.divide(cohort.max(axis=1), axis=0).round(3) * 100
cohort

sc.png
最後にヒートマップで可視化します。

fig = px.imshow(cohort)
fig.update_xaxes(title="会員期間")
fig.update_yaxes(title="入会月")

newplot.png
入会月に関係なく綺麗に継続率が下がっていますね。
「似たような継続率になるようにデータが作られたのか?」
「入会月に関係なく共通した要因から顧客が退会しているのか?」
などいろいろ考えられますが、
データが人工的に作られている可能性が濃厚そうです。。
ただ断定はできないため、頭の片隅に入れて分析していきます。

まとめ

今回は分析する前のデータ加工を行なっていきました。
次回から加工した学習データを用いて分析をしていきます。
続き: イシューからはじめるデータ分析③データ分析編

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0