6 minutes
データサイエンス100本ノックをPythonでやってみた [41-50]
データサイエンス 100 本ノックとは
The-Japan-DataScientist-Society/100knocks-preprocess: データサイエンス 100 本ノック(構造化データ加工編)
Google Colab で データサイエンス 100 本ノックをするにあたって
以下の ipynb ファイルを使用させていただきました。
実行ファイル
データサイエンス 100 本ノック by tomowarkar
041
P-041: レシート明細データフレーム(df_receipt)の売上金額(amount)を日付(sales_ymd)ごとに集計し、前日からの売上金額増減を計算せよ。なお、計算結果は 10 件表示すればよい。
pandas.Series.diff
を使う
df_receipt.groupby("sales_ymd")\
.agg(diff_sum_amount=("amount", "sum"))\
.diff(periods=1).head(10)
diff_sum_amount
sales_ymd
20170101 NaN
20170102 -9558.0
20170103 3338.0
20170104 8662.0
20170105 1665.0
20170106 -5443.0
20170107 -8972.0
20170108 1322.0
20170109 1981.0
20170110 -6575.0
groupby で sales_ymd が昇順に並ぶので厳密に前日からかは確認していけど、前営業日からの売り上げ差分は保証できているしこれでいいと思う。
042
P-042: レシート明細データフレーム(df_receipt)の売上金額(amount)を日付(sales_ymd)ごとに集計し、各日付のデータに対し、1日前、2日前、3日前のデータを結合せよ。結果は 10 件表示すればよい。
tmp = df_receipt.groupby("sales_ymd").agg({"amount":"sum"})
pd.concat(
[tmp, pd.DataFrame({f"diff_{i}":tmp.amount.diff(i) for i in range(1, 4)})],
axis=1
).head(10)
amount diff_1 diff_2 diff_3
sales_ymd
20170101 33723 NaN NaN NaN
20170102 24165 -9558.0 NaN NaN
20170103 27503 3338.0 -6220.0 NaN
20170104 36165 8662.0 12000.0 2442.0
20170105 37830 1665.0 10327.0 13665.0
20170106 32387 -5443.0 -3778.0 4884.0
20170107 23415 -8972.0 -14415.0 -12750.0
20170108 24737 1322.0 -7650.0 -13093.0
20170109 26718 1981.0 3303.0 -5669.0
20170110 20143 -6575.0 -4594.0 -3272.0
043
P-043: レシート明細データフレーム(df_receipt)と顧客データフレーム(df_customer)を結合し、性別(gender)と年代(age から計算)ごとに売上金額(amount)を合計した売上サマリデータフレーム(df_sales_summary)を作成せよ。性別は 0 が男性、1 が女性、9 が不明を表すものとする。
ただし、項目構成は年代、女性の売上金額、男性の売上金額、性別不明の売上金額の 4 項目とすること(縦に年代、横に性別のクロス集計)。また、年代は 10 歳ごとの階級とすること。
tmp = pd.merge(
df_receipt[["customer_id", "amount"]],
df_customer[["customer_id", "gender", "age"]],
how="left",
on="customer_id"
)
tmp["gender"] = tmp.gender.map({"男性":0, "女性":1}).fillna(9)
tmp["age"] = tmp.age.fillna(-1).map(lambda x: x//10*10 if x != -1 else x)
df_sales_summary = pd.pivot_table(tmp, index='age', columns='gender', values='amount', aggfunc='sum').reset_index()
df_sales_summary.columns = ["gen", "male", "female", "unknown"]
df_sales_summary
gen male female unknown
0 -1.0 NaN NaN 12395003.0
1 10.0 1591.0 149836.0 4317.0
2 20.0 72940.0 1363724.0 44328.0
3 30.0 177322.0 693047.0 50441.0
4 40.0 19355.0 9320791.0 483512.0
5 50.0 54320.0 6685192.0 342923.0
6 60.0 272469.0 987741.0 71418.0
7 70.0 13435.0 29764.0 2427.0
8 80.0 46360.0 262923.0 5111.0
9 90.0 NaN 6260.0 NaN
044
P-044: 前設問で作成した売上サマリデータフレーム(df_sales_summary)は性別の売上を横持ちさせたものであった。このデータフレームから性別を縦持ちさせ、年代、性別コード、売上金額の 3 項目に変換せよ。ただし、性別コードは男性を’00’、女性を’01’、不明を’99'とする。
データのピボット処理
df_sales_summary = df_sales_summary.set_index('gen').stack().reset_index()
df_sales_summary.columns = ["gen", "gender_cd", "amount"]
df_sales_summary["gender_cd"] = df_sales_summary.gender_cd.map({"male":"00", "female":"01", "unknown":"99"})
df_sales_summary
gen gender_cd amount
0 -1.0 99 12395003.0
1 10.0 00 1591.0
2 10.0 01 149836.0
3 10.0 99 4317.0
4 20.0 00 72940.0
5 20.0 01 1363724.0
6 20.0 99 44328.0
7 30.0 00 177322.0
8 30.0 01 693047.0
9 30.0 99 50441.0
10 40.0 00 19355.0
11 40.0 01 9320791.0
12 40.0 99 483512.0
13 50.0 00 54320.0
14 50.0 01 6685192.0
15 50.0 99 342923.0
16 60.0 00 272469.0
17 60.0 01 987741.0
18 60.0 99 71418.0
19 70.0 00 13435.0
20 70.0 01 29764.0
21 70.0 99 2427.0
22 80.0 00 46360.0
23 80.0 01 262923.0
24 80.0 99 5111.0
25 90.0 01 6260.0
別解
最初から作る場合
tmp = pd.merge(
df_receipt[["customer_id", "amount"]],
df_customer[["customer_id", "gender", "age"]],
how="left",
on="customer_id"
)
tmp["gender"] = tmp.gender.map({"男性":"00", "女性":"01"}).fillna("99")
tmp["age"] = tmp.age.fillna(-1).map(lambda x: x//10*10 if x != -1 else x)
df_sales_summary = pd.pivot_table(tmp, index=['age', 'gender'], values='amount', aggfunc='sum').reset_index()
df_sales_summary.columns = ["gen", "gender_cd", "amount"]
df_sales_summary
045
P-045: 顧客データフレーム(df_customer)の生年月日(birth_day)は日付型(Date)でデータを保有している。これを YYYYMMDD 形式の文字列に変換し、顧客 ID(customer_id)とともに抽出せよ。データは 10 件を抽出すれば良い。
pandas.to_datetime
を使う
pd.concat(
[pd.to_datetime(df_customer.birth_day, format='%Y-%m-%d').dt.strftime('%Y%m%d'),
df_customer.customer_id],
axis=1
).head(10)
birth_day customer_id
0 19810429 CS021313000114
1 19520401 CS037613000071
2 19761004 CS031415000172
3 19330327 CS028811000001
4 19950329 CS001215000145
5 19740915 CS020401000016
6 19770809 CS015414000103
7 19730817 CS029403000008
8 19310502 CS015804000004
9 19620711 CS033513000180
046
P-046: 顧客データフレーム(df_customer)の申し込み日(application_date)は YYYYMMD 形式の文字列型でデータを保有している。これを日付型(date や datetime)に変換し、顧客 ID(customer_id)とともに抽出せよ。データは 10 件を抽出すれば良い。
pd.concat(
[pd.to_datetime(df_customer.application_date, format='%Y%m%d'),
df_customer.customer_id],
axis=1
).head(10)
application_date customer_id
0 2015-09-05 CS021313000114
1 2015-04-14 CS037613000071
2 2015-05-29 CS031415000172
3 2016-01-15 CS028811000001
4 2017-06-05 CS001215000145
5 2015-02-25 CS020401000016
6 2015-07-22 CS015414000103
7 2015-05-15 CS029403000008
8 2015-06-07 CS015804000004
9 2015-07-28 CS033513000180
047
P-047: レシート明細データフレーム(df_receipt)の売上日(sales_ymd)は YYYYMMDD 形式の数値型でデータを保有している。これを日付型(date や datetime)に変換し、レシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに抽出せよ。データは 10 件を抽出すれば良い。
pd.concat(
[pd.to_datetime(df_receipt.sales_ymd, format='%Y%m%d'),
df_receipt[["receipt_no", "receipt_sub_no"]]],
axis=1
).head(10)
sales_ymd receipt_no receipt_sub_no
0 2018-11-03 112 1
1 2018-11-18 1132 2
2 2017-07-12 1102 1
3 2019-02-05 1132 1
4 2018-08-21 1102 2
5 2019-06-05 1112 1
6 2018-12-05 1102 2
7 2019-09-22 1102 1
8 2017-05-04 1112 2
9 2019-10-10 1102 1
048
P-048: レシート明細データフレーム(df_receipt)の売上エポック秒(sales_epoch)は数値型の UNIX 秒でデータを保有している。これを日付型(date や datetime)に変換し、レシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに抽出せよ。データは 10 件を抽出すれば良い。
pd.concat(
[pd.to_datetime(df_receipt.sales_epoch, unit='s'),
df_receipt[["receipt_no", "receipt_sub_no"]]],
axis=1
).head(10)
sales_epoch receipt_no receipt_sub_no
0 2009-11-03 112 1
1 2009-11-18 1132 2
2 2008-07-12 1102 1
3 2010-02-05 1132 1
4 2009-08-21 1102 2
5 2010-06-05 1112 1
6 2009-12-05 1102 2
7 2010-09-22 1102 1
8 2008-05-04 1112 2
9 2010-10-10 1102 1
049
P-049: レシート明細データフレーム(df_receipt)の売上エポック秒(sales_epoch)を日付型(timestamp 型)に変換し、“年"だけ取り出してレシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに抽出せよ。データは 10 件を抽出すれば良い。
pd.concat(
[pd.to_datetime(df_receipt.sales_epoch, unit='s').dt.year,
df_receipt[["receipt_no", "receipt_sub_no"]]],
axis=1
).head(10)
sales_epoch receipt_no receipt_sub_no
0 2009 112 1
1 2009 1132 2
2 2008 1102 1
3 2010 1132 1
4 2009 1102 2
5 2010 1112 1
6 2009 1102 2
7 2010 1102 1
8 2008 1112 2
9 2010 1102 1
050
P-050: レシート明細データフレーム(df_receipt)の売上エポック秒(sales_epoch)を日付型(timestamp 型)に変換し、“月"だけ取り出してレシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに抽出せよ。なお、“月"は 0 埋め 2 桁で取り出すこと。データは 10 件を抽出すれば良い。
pd.concat(
[pd.to_datetime(df_receipt.sales_epoch, unit='s').dt.strftime('%m'),
df_receipt[["receipt_no", "receipt_sub_no"]]],
axis=1
).head(10)
sales_epoch receipt_no receipt_sub_no
0 11 112 1
1 11 1132 2
2 07 1102 1
3 02 1132 1
4 08 1102 2
5 06 1112 1
6 12 1102 2
7 09 1102 1
8 05 1112 2
9 10 1102 1