データサイエンス 100 本ノックとは

The-Japan-DataScientist-Society/100knocks-preprocess: データサイエンス 100 本ノック(構造化データ加工編)

Google Colab で データサイエンス 100 本ノックをするにあたって

以下の ipynb ファイルを使用させていただきました。

noguhiro2002/100knocks-preprocess_ForColab-AzureNotebook: データサイエンス 100 本ノック(構造化データ加工編)For Azure_Notebook/Google_Colabo

実行ファイル

データサイエンス 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