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

051

P-051: レシート明細データフレーム(df_receipt)の売上エポック秒(sales_epoch)を日付型(timestamp 型)に変換し、“日"だけ取り出してレシート番号(receipt_no)、レシートサブ番号(receipt_sub_no)とともに抽出せよ。なお、“日"は 0 埋め 2 桁で取り出すこと。データは 10 件を抽出すれば良い。

50 と同じようにしてもできるが、違う方法で解く

pd.concat(
    [pd.to_datetime(df_receipt.sales_epoch, unit='s').map(lambda x: "{:02d}".format(x.day)),
    df_receipt[["receipt_no", "receipt_sub_no"]]],
    axis=1
).head(10)
  sales_epoch  receipt_no  receipt_sub_no
0          03         112               1
1          18        1132               2
2          12        1102               1
3          05        1132               1
4          21        1102               2
5          05        1112               1
6          05        1102               2
7          22        1102               1
8          04        1112               2
9          10        1102               1

052

P-052: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計の上、売上金額合計に対して 2000 円以下を 0、2000 円超を 1 に 2 値化し、顧客 ID、売上金額合計とともに 10 件表示せよ。ただし、顧客 ID が"Z"から始まるのものは非会員を表すため、除外して計算すること。

tmp = df_receipt[~df_receipt.customer_id.str.startswith("Z")]\
  .groupby("customer_id").amount.sum()

pd.DataFrame(
  [tmp, tmp.map(lambda x: 0 if x <= 2000 else 1)],
  index=["amount", "flag"]
).T.head(10)
                amount  flag
customer_id
CS001113000004    1298     0
CS001114000005     626     0
CS001115000010    3044     1
CS001205000004    1988     0
CS001205000006    3337     1
CS001211000025     456     0
CS001212000027     448     0
CS001212000031     296     0
CS001212000046     228     0
CS001212000070     456     0

053

P-053: 顧客データフレーム(df_customer)の郵便番号(postal_cd)に対し、東京(先頭 3 桁が 100〜209 のもの)を 1、それ以外のものを 0 に2値化せよ。さらにレシート明細データフレーム(df_receipt)と結合し、全期間において買い物実績のある顧客数を、作成した 2 値ごとにカウントせよ。

pd.merge(
  pd.concat(
      [df_customer.customer_id, df_customer.postal_cd.str.match("1\d\d|20\d").map(lambda x: 1 if x else 0)],
      axis=1
  ),
  df_receipt.customer_id, how="inner", on="customer_id"
).groupby("postal_cd").agg({"customer_id":"nunique"})
           customer_id
postal_cd
0                 3906
1                 4400

別解

tmp = df_customer[["customer_id", "postal_cd"]].copy()
tmp["flag"] = tmp.postal_cd.str.match("1\d\d|20\d").map(lambda x: 1 if x else 0)
# tmp["flag"] = tmp.postal_cd.map(lambda x: 1 if 100<=int(x[:3])<=209 else 0)
pd.merge(
    tmp,
    pd.Series(df_receipt.customer_id.unique(), name="customer_id"),
    how="inner",
    on="customer_id"
).groupby("flag").customer_id.count()

054

P-054: 顧客データデータフレーム(df_customer)の住所(address)は、埼玉県、千葉県、東京都、神奈川県のいずれかとなっている。都道府県毎にコード値を作成し、顧客 ID、住所とともに抽出せよ。値は埼玉県を 11、千葉県を 12、東京都を 13、神奈川県を 14 とすること。結果は 10 件表示させれば良い。

pd.concat([df_customer[["customer_id", "address"]],
    pd.Series(
      df_customer.address.str[:3].map({"埼玉県":11, "千葉県":12, "東京都":13, "神奈川":14}),
      name="address_cd")],
    axis=1
).head(10)
      customer_id                 address  address_cd
0  CS021313000114    神奈川県伊勢原市粟窪**********          14
1  CS037613000071      東京都江東区南砂**********          13
2  CS031415000172     東京都渋谷区代々木**********          13
3  CS028811000001  神奈川県横浜市泉区和泉町**********          14
4  CS001215000145     東京都大田区仲六郷**********          13
5  CS020401000016      東京都板橋区若木**********          13
6  CS015414000103      東京都江東区北砂**********          13
7  CS029403000008      千葉県浦安市海楽**********          12
8  CS015804000004      東京都江東区北砂**********          13
9  CS033513000180  神奈川県横浜市旭区善部町**********          14

055

P-055: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計し、その合計金額の四分位点を求めよ。その上で、顧客ごとの売上金額合計に対して以下の基準でカテゴリ値を作成し、顧客 ID、売上金額と合計ともに表示せよ。カテゴリ値は上から順に 1〜4 とする。結果は 10 件表示させれば良い。

  • 最小値以上第一四分位未満
  • 第一四分位以上第二四分位未満
  • 第二四分位以上第三四分位未満
  • 第三四分位以上

32 でも使ったpandas.Series.quantileを使う

tmp = df_receipt.groupby("customer_id").agg({"amount":"sum"})
quarter = tmp.amount.quantile([i/100 for i in range(25, 76, 25)]).values

def f(x):
  if x < quarter[0]: return 1
  if quarter[0] <= x < quarter[1]: return 2
  if quarter[1] <= x < quarter[2]: return 3
  return 4

tmp["cat_cd"] = tmp.amount.map(f)
tmp.head(10)
                amount  cat_cd
customer_id
CS001113000004    1298       2
CS001114000005     626       2
CS001115000010    3044       3
CS001205000004    1988       3
CS001205000006    3337       3
CS001211000025     456       1
CS001212000027     448       1
CS001212000031     296       1
CS001212000046     228       1
CS001212000070     456       1

056

P-056: 顧客データフレーム(df_customer)の年齢(age)をもとに 10 歳刻みで年代を算出し、顧客 ID(customer_id)、生年月日(birth_day)とともに抽出せよ。ただし、60 歳以上は全て 60 歳代とすること。年代を表すカテゴリ名は任意とする。先頭 10 件を表示させればよい。

pd.concat(
    [df_customer[["customer_id", "birth_day"]],
     pd.Series(df_customer.age.map(lambda x: x//10*10 if x < 60 else 60), name="age_cd")],
    axis=1
).head(10)

      customer_id   birth_day  age_cd
0  CS021313000114  1981-04-29      30
1  CS037613000071  1952-04-01      60
2  CS031415000172  1976-10-04      40
3  CS028811000001  1933-03-27      60
4  CS001215000145  1995-03-29      20
5  CS020401000016  1974-09-15      40
6  CS015414000103  1977-08-09      40
7  CS029403000008  1973-08-17      40
8  CS015804000004  1931-05-02      60
9  CS033513000180  1962-07-11      50

057

P-057: 前問題の抽出結果と性別(gender)を組み合わせ、新たに性別 × 年代の組み合わせを表すカテゴリデータを作成せよ。組み合わせを表すカテゴリの値は任意とする。先頭 10 件を表示させればよい

pd.concat(
    [df_customer[["customer_id", "birth_day", "gender"]],
     pd.Series(
       ["{:02d}{:02d}".format(g, a) for g, a in zip(df_customer.gender_cd, df_customer.age.map(lambda x: x//10*10 if x < 60 else 60))], name="gen_age")],
    axis=1
).head(10)
      customer_id   birth_day gender gen_age
0  CS021313000114  1981-04-29     女性    0130
1  CS037613000071  1952-04-01     不明    0960
2  CS031415000172  1976-10-04     女性    0140
3  CS028811000001  1933-03-27     女性    0160
4  CS001215000145  1995-03-29     女性    0120
5  CS020401000016  1974-09-15     男性    0040
6  CS015414000103  1977-08-09     女性    0140
7  CS029403000008  1973-08-17     男性    0040
8  CS015804000004  1931-05-02     男性    0060
9  CS033513000180  1962-07-11     女性    0150

058

P-058: 顧客データフレーム(df_customer)の性別コード(gender_cd)をダミー変数化し、顧客 ID(customer_id)とともに抽出せよ。結果は 10 件表示させれば良い。

pandas.get_dummies を使う

pd.get_dummies(
  df_customer[["customer_id", "gender_cd"]],
  columns=["gender_cd"],
  prefix_sep='_'
).head(10)
      customer_id  gender_cd_0  gender_cd_1  gender_cd_9
0  CS021313000114            0            1            0
1  CS037613000071            0            0            1
2  CS031415000172            0            1            0
3  CS028811000001            0            1            0
4  CS001215000145            0            1            0
5  CS020401000016            1            0            0
6  CS015414000103            0            1            0
7  CS029403000008            1            0            0
8  CS015804000004            1            0            0
9  CS033513000180            0            1            0

059

P-059: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計し、合計した売上金額を平均 0、標準偏差 1 に標準化して顧客 ID、売上金額合計とともに表示せよ。標準化に使用する標準偏差は、不偏標準偏差と標本標準偏差のどちらでも良いものとする。ただし、顧客 ID が"Z"から始まるのものは非会員を表すため、除外して計算すること。結果は 10 件表示させれば良い。

tmp = df_receipt[~df_receipt.customer_id.str.startswith("Z")].groupby("customer_id").amount.sum()
pd.concat(
    [tmp,
     pd.Series((tmp - tmp.mean()) / tmp.std(), name="standardization")],
    axis=1
).head(10)
                amount  standardization
customer_id
CS001113000004    1298        -0.459350
CS001114000005     626        -0.706348
CS001115000010    3044         0.182403
CS001205000004    1988        -0.205737
CS001205000006    3337         0.290096
CS001211000025     456        -0.768832
CS001212000027     448        -0.771773
CS001212000031     296        -0.827641
CS001212000046     228        -0.852635
CS001212000070     456        -0.768832

060

P-060: レシート明細データフレーム(df_receipt)の売上金額(amount)を顧客 ID(customer_id)ごとに合計し、合計した売上金額を最小値 0、最大値 1 に正規化して顧客 ID、売上金額合計とともに表示せよ。ただし、顧客 ID が"Z"から始まるのものは非会員を表すため、除外して計算すること。結果は 10 件表示させれば良い。

tmp = df_receipt[~df_receipt.customer_id.str.startswith("Z")].groupby("customer_id").amount.sum()
pd.concat(
    [tmp,
     pd.Series((tmp - tmp.min()) / (tmp.max() - tmp.min()), name="normalization")],
    axis=1
).head(10)
                amount  normalization
customer_id
CS001113000004    1298       0.053354
CS001114000005     626       0.024157
CS001115000010    3044       0.129214
CS001205000004    1988       0.083333
CS001205000006    3337       0.141945
CS001211000025     456       0.016771
CS001212000027     448       0.016423
CS001212000031     296       0.009819
CS001212000046     228       0.006865
CS001212000070     456       0.016771