pythonで機械学習のコードを書いているときに、pandasやmatplotlibの使い方やデータの加工の流れがよく分からず、どうせなら実践的なデータを用いてデータ分析の流れを理解したいと思い、本書を手に取った。
一章で学んだこと
- データの全体像を把握する
- 顧客の目的は何か
- そもそもどんなデータがあるか
- 最も粒度の大きなデータファイルはどれか
- 欠損値はあるか
- 各データファイルで共通するデータ列はあるか
- 使用するデータを作成する
- 何を主軸にデータ同士を結合させるか
- 結合後に集計ミスは無いか→検算
- 各種統計量(平均、中央値など)を把握する
- 更に詳しくデータの全体像を把握する
- 目的に沿って、必要なデータを集計する
- グラフ化して解決策をデータから読み取る
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
customer_master = pd.read_csv('customer_master.csv')
customer_master.head()#顧客の性別、名前などの顧客それぞれの情報
customer_id | customer_name | registration_date | customer_name_kana | 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 | 千葉県 |
item_master = pd.read_csv('item_master.csv')
item_master.head()#商品の情報
item_id | item_name | item_price | |
---|---|---|---|
0 | S001 | PC-A | 50000 |
1 | S002 | PC-B | 85000 |
2 | S003 | PC-C | 120000 |
3 | S004 | PC-D | 180000 |
4 | S005 | PC-E | 210000 |
transaction_1 = pd.read_csv('transaction_1.csv')#いつ、誰が、いくら買ったのか
transaction_2 = pd.read_csv('transaction_2.csv')#いつ、誰が、いくら買ったのか
transaction_detail_1 = pd.read_csv('transaction_detail_1.csv')#誰が、何を、いくつ買ったのか
transaction_detail_2 = pd.read_csv('transaction_detail_2.csv')#誰が、何を、いくつ買ったのか
transaction_1
transaction_id | price | payment_date | customer_id | |
---|---|---|---|---|
0 | T0000000113 | 210000 | 2019-02-01 01:36:57 | PL563502 |
1 | T0000000114 | 50000 | 2019-02-01 01:37:23 | HD678019 |
2 | T0000000115 | 120000 | 2019-02-01 02:34:19 | HD298120 |
3 | T0000000116 | 210000 | 2019-02-01 02:47:23 | IK452215 |
4 | T0000000117 | 170000 | 2019-02-01 04:33:46 | PL542865 |
... | ... | ... | ... | ... |
4995 | T0000005108 | 210000 | 2019-06-15 02:42:41 | HD315748 |
4996 | T0000005109 | 150000 | 2019-06-15 03:36:16 | HI215420 |
4997 | T0000005110 | 50000 | 2019-06-15 03:44:06 | IK880102 |
4998 | T0000005111 | 210000 | 2019-06-15 04:14:06 | IK074758 |
4999 | T0000005112 | 50000 | 2019-06-15 04:42:38 | HD444151 |
5000 rows × 4 columns
transaction_2
transaction_id | price | payment_date | customer_id | |
---|---|---|---|---|
0 | T0000005113 | 295000 | 2019-06-15 07:20:27 | TS169261 |
1 | T0000005114 | 50000 | 2019-06-15 07:35:47 | HI599892 |
2 | T0000005115 | 85000 | 2019-06-15 07:56:36 | HI421757 |
3 | T0000005116 | 50000 | 2019-06-15 08:40:55 | OA386378 |
4 | T0000005117 | 120000 | 2019-06-15 08:44:23 | TS506913 |
... | ... | ... | ... | ... |
1781 | T0000006894 | 180000 | 2019-07-31 21:20:44 | HI400734 |
1782 | T0000006895 | 85000 | 2019-07-31 21:52:48 | AS339451 |
1783 | T0000006896 | 100000 | 2019-07-31 23:35:25 | OA027325 |
1784 | T0000006897 | 85000 | 2019-07-31 23:39:35 | TS624738 |
1785 | T0000006898 | 85000 | 2019-07-31 23:41:38 | AS834214 |
1786 rows × 4 columns
transaction_detail_1
detail_id | transaction_id | item_id | quantity | |
---|---|---|---|---|
0 | 0 | T0000000113 | S005 | 1 |
1 | 1 | T0000000114 | S001 | 1 |
2 | 2 | T0000000115 | S003 | 1 |
3 | 3 | T0000000116 | S005 | 1 |
4 | 4 | T0000000117 | S002 | 2 |
... | ... | ... | ... | ... |
4995 | 4995 | T0000004865 | S003 | 1 |
4996 | 4996 | T0000004866 | S001 | 3 |
4997 | 4997 | T0000004867 | S001 | 3 |
4998 | 4998 | T0000004868 | S005 | 1 |
4999 | 4999 | T0000004869 | S003 | 1 |
5000 rows × 4 columns
transaction_detail_2
detail_id | transaction_id | item_id | quantity | |
---|---|---|---|---|
0 | 5000 | T0000004870 | S002 | 3 |
1 | 5001 | T0000004871 | S003 | 1 |
2 | 5002 | T0000004872 | S001 | 2 |
3 | 5003 | T0000004873 | S004 | 1 |
4 | 5004 | T0000004874 | S003 | 2 |
... | ... | ... | ... | ... |
2139 | 7139 | T0000006894 | S004 | 1 |
2140 | 7140 | T0000006895 | S002 | 1 |
2141 | 7141 | T0000006896 | S001 | 2 |
2142 | 7142 | T0000006897 | S002 | 1 |
2143 | 7143 | T0000006898 | S002 | 1 |
2144 rows × 4 columns
縦方向ユニオン
transaction = pd.concat([transaction_1, transaction_2], ignore_index = True)
transaction
# print(transaction['transaction_id'].duplicated())
transaction_id | price | payment_date | customer_id | |
---|---|---|---|---|
0 | T0000000113 | 210000 | 2019-02-01 01:36:57 | PL563502 |
1 | T0000000114 | 50000 | 2019-02-01 01:37:23 | HD678019 |
2 | T0000000115 | 120000 | 2019-02-01 02:34:19 | HD298120 |
3 | T0000000116 | 210000 | 2019-02-01 02:47:23 | IK452215 |
4 | T0000000117 | 170000 | 2019-02-01 04:33:46 | PL542865 |
... | ... | ... | ... | ... |
6781 | T0000006894 | 180000 | 2019-07-31 21:20:44 | HI400734 |
6782 | T0000006895 | 85000 | 2019-07-31 21:52:48 | AS339451 |
6783 | T0000006896 | 100000 | 2019-07-31 23:35:25 | OA027325 |
6784 | T0000006897 | 85000 | 2019-07-31 23:39:35 | TS624738 |
6785 | T0000006898 | 85000 | 2019-07-31 23:41:38 | AS834214 |
6786 rows × 4 columns
transaction_detail = pd.concat([transaction_detail_1, transaction_detail_2], ignore_index = True)
transaction_detail
detail_id | transaction_id | item_id | quantity | |
---|---|---|---|---|
0 | 0 | T0000000113 | S005 | 1 |
1 | 1 | T0000000114 | S001 | 1 |
2 | 2 | T0000000115 | S003 | 1 |
3 | 3 | T0000000116 | S005 | 1 |
4 | 4 | T0000000117 | S002 | 2 |
... | ... | ... | ... | ... |
7139 | 7139 | T0000006894 | S004 | 1 |
7140 | 7140 | T0000006895 | S002 | 1 |
7141 | 7141 | T0000006896 | S001 | 2 |
7142 | 7142 | T0000006897 | S002 | 1 |
7143 | 7143 | T0000006898 | S002 | 1 |
7144 rows × 4 columns
横方向ジョイン
join_data = pd.merge(transaction_detail, transaction[['transaction_id', 'payment_date', 'customer_id']], on='transaction_id', how='left')
join_data
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 |
... | ... | ... | ... | ... | ... | ... |
7139 | 7139 | T0000006894 | S004 | 1 | 2019-07-31 21:20:44 | HI400734 |
7140 | 7140 | T0000006895 | S002 | 1 | 2019-07-31 21:52:48 | AS339451 |
7141 | 7141 | T0000006896 | S001 | 2 | 2019-07-31 23:35:25 | OA027325 |
7142 | 7142 | T0000006897 | S002 | 1 | 2019-07-31 23:39:35 | TS624738 |
7143 | 7143 | T0000006898 | S002 | 1 | 2019-07-31 23:41:38 | AS834214 |
7144 rows × 6 columns
print(len(transaction))
6786
print(len(transaction_detail))
7144
print(len(join_data))
7144
マスターデータをジョイン
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')
join_data.head()
detail_id | transaction_id | item_id | quantity | payment_date | customer_id | customer_name | registration_date | customer_name_kana | 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 |
len(customer_master)
5000
len(item_master)
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 |
join_data
detail_id | transaction_id | item_id | quantity | payment_date | customer_id | customer_name | registration_date | customer_name_kana | gender | age | birth | pref | item_name | item_price | 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 | 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 | 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 | 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 | 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 | 170000 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
7139 | 7139 | T0000006894 | S004 | 1 | 2019-07-31 21:20:44 | HI400734 | 宍戸 明 | 2019-01-04 13:24:40 | ししど あきら | shishido_akira@example.com | M | 64 | 1955/1/13 | 福井県 | PC-D | 180000 | 180000 |
7140 | 7140 | T0000006895 | S002 | 1 | 2019-07-31 21:52:48 | AS339451 | 相原 みき | 2019-02-11 19:34:02 | あいはら みき | aihara_miki@example.com | F | 74 | 1945/2/3 | 北海道 | PC-B | 85000 | 85000 |
7141 | 7141 | T0000006896 | S001 | 2 | 2019-07-31 23:35:25 | OA027325 | 松田 早紀 | 2019-04-17 09:23:50 | まつだ さき | matsuda_saki@example.com | F | 40 | 1979/5/25 | 福島県 | PC-A | 50000 | 100000 |
7142 | 7142 | T0000006897 | S002 | 1 | 2019-07-31 23:39:35 | TS624738 | 進藤 正敏 | 2019-02-20 18:15:56 | しんどう まさとし | shinndou_masatoshi@example.com | M | 56 | 1963/2/21 | 東京都 | PC-B | 85000 | 85000 |
7143 | 7143 | T0000006898 | S002 | 1 | 2019-07-31 23:41:38 | AS834214 | 田原 結子 | 2019-04-07 03:20:19 | たはら ゆうこ | tahara_yuuko@example.com | F | 74 | 1944/12/18 | 愛知県 | PC-B | 85000 | 85000 |
7144 rows × 17 columns
データの検算
print(join_data['price'].sum())
print(transaction['price'].sum())
971135000
971135000
join_data['price'].sum() == transaction['price'].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
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 |
print(join_data['payment_date'].min())
2019-02-01 01:36:57
print(join_data['payment_date'].max())
2019-07-31 23:41:38
月別でデータを集計
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'])
join_data['payment_month'] = join_data['payment_date'].dt.strftime('%Y%m')
join_data[['payment_date', 'payment_month']]
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 |
... | ... | ... |
7139 | 2019-07-31 21:20:44 | 201907 |
7140 | 2019-07-31 21:52:48 | 201907 |
7141 | 2019-07-31 23:35:25 | 201907 |
7142 | 2019-07-31 23:39:35 | 201907 |
7143 | 2019-07-31 23:41:38 | 201907 |
7144 rows × 2 columns
join_data.dtypes
detail_id int64
transaction_id object
item_id object
quantity int64
payment_date datetime64[ns]
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
payment_month object
dtype: object
join_data.groupby('payment_month').sum()
detail_id | quantity | age | item_price | price | |
---|---|---|---|---|---|
payment_month | |||||
201902 | 676866 | 1403 | 59279 | 142805000 | 160185000 |
201903 | 2071474 | 1427 | 58996 | 142980000 | 160370000 |
201904 | 3476816 | 1421 | 59246 | 143670000 | 160510000 |
201905 | 4812795 | 1390 | 58195 | 139655000 | 155420000 |
201906 | 6369999 | 1446 | 61070 | 147090000 | 164030000 |
201907 | 8106846 | 1485 | 62312 | 153215000 | 170620000 |
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
join_data.head()
detail_id | transaction_id | item_id | quantity | payment_date | customer_id | customer_name | registration_date | customer_name_kana | gender | age | birth | pref | item_name | item_price | price | payment_month | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 | 210000 | 201902 |
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 | 50000 | 201902 |
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 | 120000 | 201902 |
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 | 210000 | 201902 |
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 | 170000 | 201902 |
月別、商品別でデータを集計
join_data.groupby(['payment_month', 'item_name']).sum()#2つの要素を軸にしてデータを集計
detail_id | quantity | age | item_price | price | ||
---|---|---|---|---|---|---|
payment_month | item_name | |||||
201902 | PC-A | 192357 | 483 | 17274 | 16700000 | 24150000 |
PC-B | 138010 | 297 | 11928 | 20145000 | 25245000 | |
PC-C | 81497 | 165 | 7727 | 18240000 | 19800000 | |
PC-D | 91435 | 173 | 8377 | 29340000 | 31140000 | |
PC-E | 173567 | 285 | 13973 | 58380000 | 59850000 | |
201903 | PC-A | 635721 | 520 | 18300 | 18200000 | 26000000 |
PC-B | 413971 | 300 | 12084 | 20230000 | 25500000 | |
PC-C | 245842 | 159 | 7178 | 17160000 | 19080000 | |
PC-D | 247832 | 143 | 6719 | 25020000 | 25740000 | |
PC-E | 528108 | 305 | 14715 | 62370000 | 64050000 | |
201904 | PC-A | 1076125 | 518 | 18198 | 18450000 | 25900000 |
PC-B | 638789 | 276 | 10926 | 18360000 | 23460000 | |
PC-C | 496212 | 183 | 8203 | 20160000 | 21960000 | |
PC-D | 368204 | 135 | 6340 | 22860000 | 24300000 | |
PC-E | 897486 | 309 | 15579 | 63840000 | 64890000 | |
201905 | PC-A | 1487314 | 497 | 18040 | 18100000 | 24850000 |
PC-B | 990251 | 298 | 12080 | 20485000 | 25330000 | |
PC-C | 631230 | 171 | 7466 | 18480000 | 20520000 | |
PC-D | 567773 | 144 | 6913 | 24840000 | 25920000 | |
PC-E | 1136227 | 280 | 13696 | 57750000 | 58800000 | |
201906 | PC-A | 1874692 | 520 | 18426 | 17750000 | 26000000 |
PC-B | 1229074 | 282 | 11613 | 19720000 | 23970000 | |
PC-C | 891651 | 182 | 8644 | 20040000 | 21840000 | |
PC-D | 792209 | 160 | 7195 | 27000000 | 28800000 | |
PC-E | 1582373 | 302 | 15192 | 62580000 | 63420000 | |
201907 | PC-A | 2339702 | 505 | 17941 | 17950000 | 25250000 |
PC-B | 1727205 | 332 | 13591 | 22525000 | 28220000 | |
PC-C | 946483 | 162 | 7060 | 17400000 | 19440000 | |
PC-D | 912353 | 145 | 6851 | 25200000 | 26100000 | |
PC-E | 2181103 | 341 | 16869 | 70140000 | 71610000 |
join_data.groupby(['payment_month', 'item_name']).sum()[['price', 'quantity']]#2つの要素を軸にしてデータを集計
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 | |
201903 | PC-A | 26000000 | 520 |
PC-B | 25500000 | 300 | |
PC-C | 19080000 | 159 | |
PC-D | 25740000 | 143 | |
PC-E | 64050000 | 305 | |
201904 | PC-A | 25900000 | 518 |
PC-B | 23460000 | 276 | |
PC-C | 21960000 | 183 | |
PC-D | 24300000 | 135 | |
PC-E | 64890000 | 309 | |
201905 | PC-A | 24850000 | 497 |
PC-B | 25330000 | 298 | |
PC-C | 20520000 | 171 | |
PC-D | 25920000 | 144 | |
PC-E | 58800000 | 280 | |
201906 | PC-A | 26000000 | 520 |
PC-B | 23970000 | 282 | |
PC-C | 21840000 | 182 | |
PC-D | 28800000 | 160 | |
PC-E | 63420000 | 302 | |
201907 | PC-A | 25250000 | 505 |
PC-B | 28220000 | 332 | |
PC-C | 19440000 | 162 | |
PC-D | 26100000 | 145 | |
PC-E | 71610000 | 341 |
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 |
graph_data = pd.pivot_table(join_data, index = 'payment_month', columns='item_name', values = 'price', aggfunc='sum')
graph_data
# index: 行見出し
# columns: 列見出し
# 第一引数: 元データのpandas.DataFrameオブジェクト
# values: 元データの列名指定→その列に対する結果のみが算出される
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 |
201907 | 25250000 | 28220000 | 19440000 | 26100000 | 71610000 |
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()
<matplotlib.legend.Legend at 0x7fd7cfd302e0>
学んだこと
- データの全体像を把握する
- 顧客の目的は何か
- そもそもどんなデータがあるか
- 最も粒度の大きなデータファイルはどれか
- 欠損値はあるか
- 各データファイルで共通するデータ列はあるか
- 使用するデータを作成する
- 何を主軸にデータ同士を結合させるか
- 結合後に集計ミスは無いか→検算
- 各種統計量(平均、中央値など)を把握する
- 更に詳しくデータの全体像を把握する
- 目的に沿って、必要なデータを集計する
- グラフ化して解決策をデータから読み取る
二章で学んだこと
- データ加工など前処理を行わないと、間違った結果や解釈を抽出してしまう
- 丁寧に欠損値や半角全角部分を加工してあげれば、正しい結果や解釈が出来るようになる
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 |
データの揺れを見てみる
- データの揺れ:データに混在する入力ミスや表記方法の違いなど、不整合を起こしている状態
uriage_data['item_name'].head()
0 商品A
1 商 品 S
2 商 品 a
3 商品Z
4 商品a
Name: item_name, dtype: object
uriage_data['item_price'].head()
0 100.0
1 NaN
2 NaN
3 2600.0
4 NaN
Name: item_price, dtype: float64
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)
res
# データの揺れのため、列数が26→99になってしまっている
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 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
201902 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
201903 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
201904 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
201905 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
201906 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
201907 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 1 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
7 rows × 99 columns
res = uriage_data.pivot_table(values='item_price', index='purchase_month', columns='item_name', aggfunc='sum', fill_value=0)
res
## 横軸をpriceだけにしたところで、列数は変わらず
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 |
7 rows × 99 columns
データの揺れを補正
商品名を補正
# 重複しないデータの数を表示
print(len(pd.unique(uriage_data.item_name)))
99
# csvファイルの各列にアクセスする方法は、csvファイル名['列名'] or csvファイル名.列名
uriage_data.item_name
0 商品A
1 商 品 S
2 商 品 a
3 商品Z
4 商品a
...
2994 商品Y
2995 商品M
2996 商品Q
2997 商品H
2998 商品D
Name: item_name, Length: 2999, dtype: object
uriage_data['item_name']
0 商品A
1 商 品 S
2 商 品 a
3 商品Z
4 商品a
...
2994 商品Y
2995 商品M
2996 商品Q
2997 商品H
2998 商品D
Name: item_name, Length: 2999, dtype: object
uriage_data['item_name'] = uriage_data['item_name'].str.upper()#文字列を大文字に変更
uriage_data['item_name']
0 商品A
1 商 品 S
2 商 品 A
3 商品Z
4 商品A
...
2994 商品Y
2995 商品M
2996 商品Q
2997 商品H
2998 商品D
Name: item_name, Length: 2999, dtype: object
uriage_data['item_name'] = uriage_data['item_name'].str.replace(' ', '') # 半角スペースを削除
uriage_data.item_name
0 商品A
1 商品S
2 商品A
3 商品Z
4 商品A
...
2994 商品Y
2995 商品M
2996 商品Q
2997 商品H
2998 商品D
Name: item_name, Length: 2999, dtype: object
uriage_data['item_name'] = uriage_data['item_name'].str.replace(' ', '') # 全角スペースを削除
uriage_data.item_name
0 商品A
1 商品S
2 商品A
3 商品Z
4 商品A
...
2994 商品Y
2995 商品M
2996 商品Q
2997 商品H
2998 商品D
Name: item_name, Length: 2999, dtype: object
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)))
26
pd.unique(uriage_data.item_name)
array(['商品A', '商品S', '商品Z', '商品V', '商品O', '商品U', '商品L', '商品C', '商品I',
'商品R', '商品X', '商品G', '商品P', '商品Q', '商品Y', '商品N', '商品W', '商品E',
'商品K', '商品B', '商品F', '商品D', '商品M', '商品H', '商品T', '商品J'],
dtype=object)
金額欠損値を補完
uriage_data.head()
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 | NaN | 浅田賢二 | 201907 |
2 | 2019-05-11 19:42:07 | 商品A | NaN | 南部慶二 | 201905 |
3 | 2019-02-12 23:40:45 | 商品Z | 2600.0 | 麻生莉緒 | 201902 |
4 | 2019-04-22 03:09:35 | 商品A | NaN | 平田鉄二 | 201904 |
uriage_data.isnull().any(axis=0)
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() # 欠損値の場所を特定
flg_is_null
0 False
1 True
2 True
3 False
4 True
...
2994 False
2995 False
2996 True
2997 True
2998 False
Name: item_price, Length: 2999, dtype: bool
for trg in list(uriage_data.loc[flg_is_null, 'item_name'].unique()):
File "<ipython-input-63-ae47c7fde99c>", line 3
^
SyntaxError: unexpected EOF while parsing
uriage_data.loc[flg_is_null, 'item_name'].unique()
array(['商品S', '商品A', '商品P', '商品N', '商品W', '商品R', '商品I', '商品L', '商品F',
'商品O', '商品B', '商品C', '商品V', '商品Q', '商品U', '商品K', '商品T', '商品X',
'商品E', '商品M', '商品G', '商品J', '商品D', '商品H', '商品Y'], dtype=object)