❏ 参考書

Python実践データ分析100本ノック Kindle版
で勉強したときの備忘録

❏ 第1部 基礎編:データ加工


この章の目的

・ある企業のECサイトでの商品の注文数の推移を分析することによって、売上改善の方向性を探っていく

・ECサイトデータはウェブから得られるデータであることから、比較的「綺麗」なデータであることが多く、導入の練習問題として適している

第1章  ウェブからの注文数を分析する10本ノック


ノック1:データを読み込んでみよう

ポイント

・データ分析業務を行う際、「まず何をするのか」のイメージをつかむ

・実際の現場では、データをかき集めるところから始まり、データの概要を捉え、分析に適した形に加工することから始めることが多い

・どんな目的であろうと、データの全体像を把握することが重要。そのためなるべくデータの粒度が細かいデータに合わせてデータを作成

import pandas as pd
customer_master = pd.read_csv('customer_master.csv')  # pandasのデータフレーム型に格納
customer_master.head()
  customer_id customer_name registration_date customer_name_kana email gender age birth pref
0 IK152942 平田 裕次郎 2019-01-01 00:25:33 ひらた ゆうじろう hirata_yuujirou@example.com M 29 1990/6/10 石川県
1 TS808488 田村 詩織 2019-01-01 01:13:45 たむら しおり tamura_shiori@example.com F 33 1986/5/20 東京都
2 AS834628 久野 由樹 2019-01-01 02:00:14 ひさの ゆき hisano_yuki@example.com F 63 1956/1/2 茨城県
3 AS345469 鶴岡 薫 2019-01-01 04:48:22 つるおか かおる tsuruoka_kaoru@example.com M 74 1945/3/25 東京都
4 GD892565 大内 高史 2019-01-01 04:54:51 おおうち たかし oouchi_takashi@example.com M 54 1965/8/5 千葉県

ノック2:データを結合(ユニオン)してみよう

ポイント

・pd.concatは、列名をキーにして縦方向に結合する

・ignore_index=Trueは、結合した後にインデックス番号を振り直す

transaction_1 = pd.read_csv('transaction_1.csv')
transaction_2 = pd.read_csv('transaction_2.csv')
transaction = pd.concat([transaction_1, transaction_2], ignore_index=True) 
print(len(transaction_1))
print(len(transaction_2))
print(len(transaction))

5000

1786

6786


ノック3:売上データ同士を結合(ジョイン)そしみよう

ポイント

・pd.mergeで、ジョインを行っている

・主軸になるデータを考えつつ、どの列をキーにジョインするかを考える

・onでジョインキー、howでジョインの種類を指定

join_data = pd.merge(transaction_detail, transaction[["transaction_id", "payment_date", "customer_id"]], on="transaction_id", how="left") 
join_data.head()
  detail_id transaction_id item_id quantity payment_date customer_id
0 0 T0000000113 S005 1 2019-02-01 01:36:57 PL563502
1 1 T0000000114 S001 1 2019-02-01 01:37:23 HD678019
2 2 T0000000115 S003 1 2019-02-01 02:34:19 HD298120
3 3 T0000000116 S005 1 2019-02-01 02:47:23 IK452215
4 4 T0000000117 S002 2 2019-02-01 04:33:46 PL542865

ノック4:マスターデータを結合(ジョイン)してみよう

join_data = pd.merge(join_data, customer_master, on="customer_id", how="left")  # 全列ジョインする
join_data = pd.merge(join_data, item_master, on="item_id", how="left")  # 上記に加えさらに別ファイルをジョイン
  detail_id transaction_id item_id quantity payment_date customer_id customer_name registration_date customer_name_kana email gender age birth pref item_name item_price
0 0 T0000000113 S005 1 2019-02-01 01:36:57 PL563502 井本 芳正 2019-01-07 14:34:35 いもと よしまさ imoto_yoshimasa@example.com M 30 1989/7/15 熊本県 PC-E 210000
1 1 T0000000114 S001 1 2019-02-01 01:37:23 HD678019 三船 六郎 2019-01-27 18:00:11 みふね ろくろう mifune_rokurou@example.com M 73 1945/11/29 京都府 PC-A 50000
2 2 T0000000115 S003 1 2019-02-01 02:34:19 HD298120 山根 小雁 2019-01-11 08:16:02 やまね こがん yamane_kogan@example.com M 42 1977/5/17 茨城県 PC-C 120000
3 3 T0000000116 S005 1 2019-02-01 02:47:23 IK452215 池田 菜摘 2019-01-10 05:07:38 いけだ なつみ ikeda_natsumi@example.com F 47 1972/3/17 兵庫県 PC-E 210000
4 4 T0000000117 S002 2 2019-02-01 04:33:46 PL542865 栗田 憲一 2019-01-25 06:46:05 くりた けんいち kurita_kenichi@example.com M 74 1944/12/17 長崎県 PC-B 85000

 


ノック5:必要なデータ列を作ろう(売上列の作成)

ポイント

・データフレーム型の計算では、行ごとに計算が実行される

・データで語るデータサイエンティストが誤ったデータを出すというのは顧客からの信頼を失う。件数の確認等を行う事を心がける

・また、なるべくデータの検算(計算をしたあとで、間違いがないかどうか確かめるため、もう一度計算してみること)を行う

join_data["price"] = join_data["quantity"] * join_data["item_price"]
join_data[["quantity", "item_price", "price"]].head()
  quantity item_price price
0 1 210000 210000
1 1 50000 50000
2 1 120000 120000
3 1 210000 210000
4 2 85000 170000

ノック6:データ検算をしよう(列の合計)

ポイント

・データ加工前のpriceの合計と、データ加工後に計算したpriceの合計は同じ値になるはず

・'=='でTrue/Falseで確認してもよい

print(join_data["price"].sum())
print(transaction["price"].sum())

join_data["price"].sum() == transaction["price"].sum()

971135000

971135000

 

True


ノック7:各種統計量を把握しよう

ポイント

・データ分析を進めていく上で、まずは大きく2つの数値を知る必要がある

 ・欠損している値の状況(欠損があったら除去や補完が必要)⇒ isnull( ).sum( )で行なう

 ・全体の数値感 ⇒ describe( )で行う

・isnull( ).sum( )は、isnull( )でTrue(欠損値)/Falseを返し、sum( )でそのTrueの数をそれぞれ列毎に集計する 

join_data.isnull().sum()

detail_id                           0

transaction_id                 0

item_id                             0

quantity                            0

payment_date                 0

customer_id                     0

customer_name              0

registration_date             0

customer_name_kana    0

email                                 0

gender                              0

age                                    0

birth                                  0

pref                                   0

item_name                      0

item_price                       0

price                                 0

dtype:    int64

 

ポイント

 ・describe( )は、全体感を把握するため各種統計量を出力。デフォルトでは数値の列のみ選択される

  データ件数(count)

  平均値(mean)

  標準偏差(std)

  最小値(min)

  四分位数(25%、75%)

  中央値(50%)

  最大値(max)

join_data.describe()()
  detail_id quantity age item_price price
count 7144.000000 7144.000000 7144.000000 7144.000000 7144.000000
mean 3571.500000 1.199888 50.265677 121698.628219 135937.150056
std 2062.439494 0.513647 17.190314 64571.311830 68511.453297
min 0.000000 1.000000 20.000000 50000.000000 50000.000000
25% 1785.750000 1.000000 36.000000 50000.000000 85000.000000
50% 3571.500000 1.000000 50.000000 102500.000000 120000.000000
75% 5357.250000 1.000000 65.000000 187500.000000 210000.000000
max 7143.000000 4.000000 80.000000 210000.000000 420000.000000

ノック8:月別でデータを集計してみよう

ポイント

・半年程度なら影響ないが過去数年となるとビジネスモデルの変化等により一纏めに分析すると見誤るケースがある

・その場合、データ範囲を絞るケースもある

join_data.dtypes  # データ型の確認

detail_id                               int64

transaction_id                     object

item_id                                 object

quantity                               int64

payment_date                    object

customer_id                        object

customer_name                 object

registration_date               object

customer_name_kana      object

email                                    object

gender                                 object

age                                       int64

birth                                     object

pref                                      object

item_name                          object

item_price                           int64

price                                     int64

dtype:   object

 

ポイント

 

・全体的に売上が伸びているのか否か把握するのは分析の第一歩。まずは月別で集計して一覧表示してみる

join_data["payment_date"] = pd.to_datetime(join_data["payment_date"]) # object型をdatetime型に変換
join_data["payment_month"] = join_data["payment_date"].dt.strftime("%Y%m") # 年月に変換
join_data[["payment_date", "payment_month"]].head()
  payment_date payment_month
0 2019-02-01 01:36:57 201902
1 2019-02-01 01:37:23 201902
2 2019-02-01 02:34:19 201902
3 2019-02-01 02:47:23 201902
4 2019-02-01 04:33:46 201902

 

ポイント

・groupbyは、まとめたい列(payment_month)、集計方法(sum)、集計する列(price)を指定する

join_data.groupby("payment_month").sum()["price"]

payment_month

201902     160185000

201903     160370000

201904     160510000

201905     155420000

201906     164030000

201907     170620000

Name: price, dtype: int64


ノック9:月別、商品別でデータを集計(売上、数量)しよう

ポイント

・groupbyする列が複数ある場合、リスト型で指定する

join_data.groupby(["payment_month","item_name"]).sum()[["price", "quantity"]].head()
    price quantity
payment_month item_name    
201902 PC-A 24150000 483
PC-B 25245000 297
PC-C 19800000 165
PC-D 31140000 173
PC-E 59850000 285

 

ポイント

・pivot_tableは、行(index)と列(columns)を指定することができる。valuesでは集計したい数値列、aggfuncには集計方法を指定する

・groupbyよりpivot_tableの方が月別、商品別の推移が把握しやすい

pd.pivot_table(join_data, index='item_name', columns='payment_month', values=['price', 'quantity'], aggfunc='sum')
  price quantity
payment_month 201902 201903 201904 201905 201906 201907 201902 201903 201904 201905 201906 201907
item_name                        
PC-A 24150000 26000000 25900000 24850000 26000000 25250000 483 520 518 497 520 505
PC-B 25245000 25500000 23460000 25330000 23970000 28220000 297 300 276 298 282 332
PC-C 19800000 19080000 21960000 20520000 21840000 19440000 165 159 183 171 182 162
PC-D 31140000 25740000 24300000 25920000 28800000 26100000 173 143 135 144 160 145
PC-E 59850000 64050000 64890000 58800000 63420000 71610000 285 305 309 280 302 341

ノック10:商品別の売上推移を可視化(グラフ)してみよう

ポイント

・payment_monthはデータフレーム型のindexとして、商品名は列として作成

・グラフを作成する際には、横軸にpayment_monthを、縦軸にgraph_dataの該当商品名を渡すことで描画が可能になる

・Matplotlib(マットプロットリブ)

 Matplotlib は、Pythonのグラフ描画のためのライブラリ

 pyplotは、matplotlibパッケージ内のモジュールで、欲しいプロットを作るために暗黙的かつ自動的に図形や軸を作成するインターフェース

 プロットは、データを座標内の点として配置すること

 %matplotlib inlineを実行してプロットを作成すると、アウトプット行に図が出力される

 plt.plot(x,y)は、折れ線グラフ。第一引数はx軸(payment_monthを指定)に対応し、第二引数がy軸(priceを指定)にあたる

 

・参考先

 Matplotlib   :【初心者向け】Matplotlib入門 | Pythonを使ってデータを可視化してみよう!サイト

graph_data = pd.pivot_table(join_data, index='payment_month', columns='item_name', values='price', aggfunc='sum')
graph_data.head()

import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(list(graph_data.index), graph_data["PC-A"], label='PC-A') # 商品毎にグラフの描画
plt.plot(list(graph_data.index), graph_data["PC-B"], label='PC-B')
plt.plot(list(graph_data.index), graph_data["PC-C"], label='PC-C')
plt.plot(list(graph_data.index), graph_data["PC-D"], label='PC-D')
plt.plot(list(graph_data.index), graph_data["PC-E"], label='PC-E')
plt.legend() # 凡例の表示
item_name PC-A PC-B PC-C PC-D PC-E
payment_month          
201902 24150000 25245000 19800000 31140000 59850000
201903 26000000 25500000 19080000 25740000 64050000
201904 25900000 23460000 21960000 24300000 64890000
201905 24850000 25330000 20520000 25920000 58800000
201906 26000000 23970000 21840000 28800000 63420000

第2章  小売店のデータでデータ加工を行う10本ノック


この章の目的

・小売店の売上履歴と顧客台帳データを用いて、データの分析や予測を行うための重要なノウハウである「データ加工」を習得する

・本章を通して、より現場に近い「汚い」データを処理する経験を積むことで、ビジネス現場ならではの種々雑多な状況に対処できる力を身につける


ノック11:データを読み込んでみよう

ポイント

・データ等で顕在する入力ミスや表記方法の違い等が混在し、不整合を起こしている状態を「データの揺れ」という

import pandas as pd
uriage_data = pd.read_csv("uriage.csv")
uriage_data.head()
  purchase_date item_name item_price customer_name
0 2019-06-13 18:02:34 商品A 100.0 深井菜々美
1 2019-07-13 13:05:29 商 品 S NaN 浅田賢二
2 2019-05-11 19:42:07 商 品 a NaN 南部慶二
3 2019-02-12 23:40:45 商品Z 2600.0 麻生莉緒
4 2019-04-22 03:09:35 商品a NaN 平田鉄二
kokyaku_data= pd.read_excel("kokyaku_daicho.xlsx")
kokyaku_data.head()
  顧客名 かな 地域 メールアドレス 登録日
0 須賀ひとみ すが ひとみ H市 suga_hitomi@example.com 2018/01/04
1 岡田  敏也 おかだ としや E市 okada_toshiya@example.com 42782
2 芳賀 希 はが のぞみ A市 haga_nozomi@example.com 2018/01/07
3 荻野 愛 おぎの あい F市 ogino_ai@example.com 42872
4 栗田 憲一 くりた けんいち E市 kurita_kenichi@example.com 43127

ノック12:データの揺れを見てみよう

ポイント

データの揺れのパターン

 ・文字列内にスペースが含まれていたり

 ・アルファベットが大文字/小文字で統一されていない

 ・欠損値「NaN」が存在する

 



ノック13:データに揺れがあるまま集計してみよう

ポイント

・pivot_tableのaggfunc="size"は、行(purchase_month)・列(item_name)毎の重複件数を集計する

・fill_vakue=0は初期値。欠損値を補完する値を指定する

uriage_data["purchase_date"] = pd.to_datetime(uriage_data["purchase_date"])
uriage_data["purchase_month"] = uriage_data["purchase_date"].dt.strftime("%Y%m")
res = uriage_data.pivot_table(index="purchase_month", columns="item_name", aggfunc="size", fill_value=0)
item_name 商品W 商 品 n 商品E 商品M 商品P 商品S 商品W 商品X 商 品O 商 品Q ... 商品k 商品l 商品o 商品p 商品r 商品s 商品t 商品v 商品x 商品y
purchase_month                                          
201901 0 1400 0 0 0 0 0 0 0 0 ... 1100 1200 1500 0 0 0 0 0 0 0
201902 0 0 0 0 0 0 0 2400 0 0 ... 0 0 0 0 0 1900 2000 2200 0 0
201903 0 0 500 1300 1600 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
201904 2300 0 0 0 0 0 0 0 0 1700 ... 0 0 0 0 0 1900 0 0 0 0
201905 0 0 0 0 0 1900 0 0 0 0 ... 0 1200 0 0 0 0 0 0 0 2500
201906 0 0 0 0 0 0 2300 0 0 0 ... 0 0 0 1600 0 0 0 0 2400 0
201907 0 0 0 0 0 0 0 0 0 0 ... 0 0 1500 0 1800 0 0 0 0 0

ノック14:商品名の揺れを補正しよう

ポイント

・upper()は、小文字を大文字に変換

・replace()は、全角/半角のスペースを除外(置換)

・unique()は、重複を除外したユニーク件数

・sort_valuesは、byで指定されてたカラム「item_name」で昇順にソートし画面表示する。ascending=Falseで降順になる

・単一列のデータフレームの場合はsort_values()で問題ない 例:uriage_data["item_name"].sort_values()

uriage_data["item_name"] = uriage_data["item_name"].str.upper()
uriage_data["item_name"] = uriage_data["item_name"].str.replace(" ", "")
uriage_data["item_name"] = uriage_data["item_name"].str.replace(" ", "")
uriage_data.sort_values(by=["item_name"], ascending=True)
  purchase_date item_name item_price customer_name purchase_month
0 2019-06-13 18:02:34 商品A 100.0 深井菜々美 201906
1748 2019-05-19 20:22:22 商品A 100.0 松川綾女 201905
223 2019-06-25 08:13:20 商品A 100.0 板橋隆 201906
1742 2019-06-13 16:03:17 商品A 100.0 小平陽子 201906
1738 2019-02-10 00:28:43 商品A 100.0 松田浩正 201902
... ... ... ... ... ...
2880 2019-04-22 00:36:52 商品Y NaN 田辺光洋 201904
2881 2019-04-30 14:21:09 商品Y NaN 高原充則 201904
1525 2019-01-24 10:27:23 商品Y 2500.0 五十嵐春樹 201901
1361 2019-05-28 13:45:32 商品Y 2500.0 大崎ヒカル 201905
3 2019-02-12 23:40:45 商品Z 2600.0 麻生莉緒 201902

2999 rows × 5 columns

# 補正後の件数
print(len(pd.unique(uriage_data.item_name)))
# 上記は以下でも同じ
len(uriage_data["item_name"].unique())
26

ノック15:金額欠損値の補完をしよう

ポイント

・isnull()は、欠損値の有無を確認。欠損値を含むカラムはTrue、含まない場合はFalseが出力される

uriage_data.isnull().any(axis=0)  # 欠損値が含まれている(True)か確認 

purchase_date      False

item_name             False

item_price              True

customer_name    False

purchase_month  False

dtype: bool

 

ポイント

flg_is_null = uriage_data["item_price"].isnull()

 ・item_priceの中で欠損値のある箇所を特定。flg_is_null変数にどの行に欠損値が存在するかが保存される

list(uriage_data.loc[flg_is_null, "item_name"].unique())

  ・flg_is_nullによりデータが欠損している商品名の一覧を作成する処理になっている。以下に分解して説明

 ・list()は、変数の値をリスト形式に変換

 ・loc()は、条件を付与し、それに合致するデータを抽出する。ここでは「金額が欠損している行のitem_name列」の値を取得している

 ・unique()は、重複をなくす

price = uriage_data.loc[(~flg_is_null) & (uriage_data["item_name"] == trg), "item_price"].max()

 ・ループ変数:trg(欠損値がある商品名)を用いて、同じ商品で金額が正しく記載されている行をloc()で探し、その金額を取得している

 ・~flg_is_nullは、否定演算子。flg_is_null == Falseと同義

uriage_data["item_price"].loc[(flg_is_null) & (uriage_data["item_name"] == trg)] = price

 ・売上履歴のitem_price列に対してloc()を行い欠損を起こしている対象データを抽出し、取得したpriceを欠損値に代入

 

・loc()は行ラベルだけを指定することも、条件式だけを指定することも可能

flg_is_null = uriage_data["item_price"].isnull()
for trg in list(uriage_data.loc[flg_is_null, "item_name"].unique()):
    price = uriage_data.loc[(~flg_is_null) & (uriage_data["item_name"] == trg), "item_price"].max()
    uriage_data["item_price"].loc[(flg_is_null) & (uriage_data["item_name"] == trg)] = price
uriage_data
  purchase_date item_name item_price customer_name purchase_month
0 2019-06-13 18:02:34 商品A 100.0 深井菜々美 201906
1 2019-07-13 13:05:29 商品S 1900.0 浅田賢二 201907
2 2019-05-11 19:42:07 商品A 100.0 南部慶二 201905
3 2019-02-12 23:40:45 商品Z 2600.0 麻生莉緒 201902
4 2019-04-22 03:09:35 商品A 100.0 平田鉄二 201904
... ... ... ... ... ...
2994 2019-02-15 02:56:39 商品Y 2500.0 福島友也 201902
2995 2019-06-22 04:03:43 商品M 1300.0 大倉晃司 201906
2996 2019-03-29 11:14:05 商品Q 1700.0 尾形小雁 201903
2997 2019-07-14 12:56:49 商品H 800.0 芦田博之 201907
2998 2019-07-21 00:31:36 商品D 400.0 石田郁恵 201907

 

ポイント

・ループの中で商品に設定されている金額の最大値と最小値を出力

・min(skipna=False)におけるskipnaは、NaNデータを無視するかの設定。Falseの場合はNaNが存在する場合、最小値はNaNと表示される

for trg in list(uriage_data["item_name"].sort_values().unique()):
    print(trg + 
          "の最大額:" + str(uriage_data.loc[uriage_data["item_name"]==trg]["item_price"].max()) + 
          "の最小額:" + str(uriage_data.loc[uriage_data["item_name"]==trg]["item_price"].min(skipna=False))
         ) 

商品Aの最大額:100.0の最小額:100.0

商品Bの最大額:200.0の最小額:200.0

商品Cの最大額:300.0の最小額:300.0

(以下省略)


ノック16:顧客名の揺れを補正しよう

ポイント

ノック14と同様

kokyaku_data["顧客名"] = kokyaku_data["顧客名"].str.replace(" ","")
kokyaku_data["顧客名"] = kokyaku_data["顧客名"].str.replace(" ","")
kokyaku_data["顧客名"].head()

ノック17:日付の揺れを補正しよう

ポイント

・Excelデータを取り扱う際、注意すべき点として「書式が違うデータが混在する」事が挙げられる

 2018/01/04

 2017年2月16日

・astype("str")で、str型に変化

・str.isdigit( )で、顧客台帳の登録日が数値かどうかを判定している。すべての文字が数字ならTrue、そうでないならFalseを返す

・astype("str").str.isdigit()で一組

・sum()で数値(True)として取り込まれている件数を取得

flg_is_serial = kokyaku_data["登録日"].astype("str").str.isdigit()
flg_is_serial.sum()
22

 

ポイント

・pd.to_timedelta( )は、数値(シリアル値)から日付に変換する。unitは、単位を表し「D」は日単位

・シリアル値は、Excelで日時を計算するための数値

・pd.to_datetime("1900/01/01")で、基準になる日付('1900-01-01')と足し合わせている

・「- 2」は、Excelの日付シリアル値を単純にPythonで計算すると2日ずれるので2を引く

fromserial = pd.to_timedelta(kokyaku_data.loc[flg_is_serial, "登録日"].astype("float") - 2, unit="D") + pd.to_datetime("1900/01/01")

1  2017-02-16

3  2017-05-17

4  2018-01-27

(以下省略)

 

ポイント

・日付として取り込まれているデータも、書式統一する。これでdatetime64型(標準フォーマと:yyyy-mm-dd)に変換される

fromString = pd.to_datetime(kokyaku_data.loc[~flg_is_serial, "登録日"])
fromString

0  2018-01-04

2  2018-01-07

5  2017-06-20

(以下省略)

 

ポイント

・pd.concatで、数値から日付に変換されたデータと、書式を変換したデータを統合して、元の「登録日」に代入

kokyaku_data["登録日"] = pd.concat([fromserial, fromString])
kokyaku_data
  顧客名 かな 地域 メールアドレス 登録日
0 須賀ひとみ すが ひとみ H市 suga_hitomi@example.com 2018-01-04
1 岡田敏也 おかだ としや E市 okada_toshiya@example.com 2017-02-18
2 芳賀希 はが のぞみ A市 haga_nozomi@example.com 2018-01-07
3 荻野愛 おぎの あい F市 ogino_ai@example.com 2017-05-19
4 栗田憲一 くりた けんいち E市 kurita_kenichi@example.com 2018-01-29
... ... ... ... ... ...
195 川上りえ かわかみ りえ G市 kawakami_rie@example.com 2017-06-20

(以下省略)

 

ポイント

・年月単位での集計結果を足し算すると、顧客台帳の総データ件数と一致するので、日付の補正が正しく行われた事が確認できる

kokyaku_data["登録年月"] = kokyaku_data["登録日"].dt.strftime("%Y%m")
rslt = kokyaku_data.groupby("登録年月").count()["顧客名"]
print(rslt)
print(len(kokyaku_data))

登録年月

201701  15

201702  11

201703  14

201704  15

201705  13

201706  14

201707  17

201801  13

201802  15

201803  17

201804    5

201805  19

201806  13

201807  17

201904    2

Name: 顧客名, dtype: int64

200


ノック18:顧客名をキーに2つのデータを結合(ジョイン)しよう

ポイント

・left_on、right_onで、結合するキーとなるデータを指定

・howは、結合方法で「left」を指定した場合はleft側を主として、right側を副として結合することを意味する

・データの加工により、分析に適したデータの形にすることをクレンジングと呼ぶ

join_data = pd.merge(uriage_data, kokyaku_data, left_on="customer_name", right_on="顧客名", how="left")
join_data = join_data.drop("customer_name", axis=1)
join_data
  purchase_date item_name item_price purchase_month 顧客名 かな 地域 メールアドレス 登録日 登録年月
0 2019-06-13 18:02:34 商品A 100.0 201906 深井菜々美 ふかい ななみ C市 fukai_nanami@example.com 2017-01-26 201701
1 2019-07-13 13:05:29 商品S 1900.0 201907 浅田賢二 あさだ けんじ C市 asada_kenji@example.com 2018-04-07 201804
2 2019-05-11 19:42:07 商品A 100.0 201905 南部慶二 なんぶ けいじ A市 nannbu_keiji@example.com 2018-06-19 201806
3 2019-02-12 23:40:45 商品Z 2600.0 201902 麻生莉緒 あそう りお D市 asou_rio@example.com 2018-07-22 201807

(以下省略)


ノック19:クレンジングしたデータをダンプしよう

ポイント

・クレンジングしたデータをファイル出力(ダンプ)し、分析する際は出力ファイルから読み込む事でクレジングのやり直しを省略する事ができる

・ファイル出力する際は、列の配置を調整(整形)して直感的に分かりやすくする

dump_data = join_data[["purchase_date", "purchase_month", "item_name", "item_price", "顧客名", "かな", "地域", "メールアドレス", "登録日"]]
dump_data
  purchase_date purchase_month item_name item_price 顧客名 かな 地域 メールアドレス 登録日
0 2019-06-13 18:02:34 201906 商品A 100.0 深井菜々美 ふかい ななみ C市 fukai_nanami@example.com 2017-01-26
1 2019-07-13 13:05:29 201907 商品S 1900.0 浅田賢二 あさだ けんじ C市 asada_kenji@example.com 2018-04-07

(以下省略)

 

ポイント

・to_csv( )は、整形したdump_dataをファイル出力する。実行すると、同じ階層に出力される

・index=Falseは、行名無しを意味する

dump_data.to_csv("dump_data.csv", index=False)

ノック20:データを集計しよう

ポイント

・ノック13と同様

・1行目:ダンプデータを読み込む

・2行目:purchase_monthを縦軸に、商品毎の集計(重複件数)

・3行目:purchase_monthを縦軸に、売上金額の集計(合計)

import_data = pd.read_csv("dump_data.csv")
byItem = import_data.pivot_table(index="purchase_month", columns="item_name", aggfunc="size", fill_value=0)
byPrice = import_data.pivot_table(index="purchase_month", columns="item_name",values="item_price" ,aggfunc="sum", fill_value=0)

 

ポイント

・顧客台帳を主体に結合。集計期間内に購買を行っていない顧客は「購買日」等がNaNで結合される

・away_data["purchase_date"].isnull()では、True(NaNである)/False(NaNでない)の結果を全行出力される

・away_data[away_data["purchase_date"].isnull()]では、True(NaNである=購買してない)の行だけ出力する

away_data = pd.merge(uriage_data, kokyaku_data, left_on="customer_name", right_on="顧客名", how="right")
away_data[away_data["purchase_date"].isnull()]
  purchase_date item_name item_price customer_name purchase_month 顧客名 かな 地域 メールアドレス 登録日 登録年月
2999 NaT NaN NaN NaN NaN 福井美希 ふくい みき D市 fukui_miki1@example.com 2019-04-23 201904

 

ポイント

・購買日がNaNの行を列名を指定して出力

away_data[away_data["purchase_date"].isnull()][["顧客名", "メールアドレス", "登録日"]]
  顧客名 メールアドレス 登録日
2999 福井美希 fukui_miki1@example.com 2019-04-23