【必見】PythonでECサイト推薦エンジン構築!初心者が知るべき特徴量作成の秘訣

PR表記

※アフィリエイト広告を利用しています

どうもニコイチです。以下の手順では、ECサイトのユーザー行動データから、ユーザーや商品の特徴、そしてユーザー×商品の組み合わせごとの特徴量を抽出し、最終的に推薦エンジンの学習データとしてまとめる方法を解説しています。
なお、この記事は全5回のシリーズの第3回「モデリングするための特徴量作成」に相当します。

目次

データの読み込みと時系列による分割

まず、pandasを用いてファイル「sate_demo_train.tsv」を読み込みます。
ファイルはタブ区切りになっているので、sep='\t'を指定します。また、時系列の扱いを容易にするため、time_stampカラムをdatetime型に変換します。

import pandas as pd

# sate_demo_train.tsvファイルを読み込む(タブ区切り)
data = pd.read_csv('sate_demo_train.tsv', sep='\t')

# time_stampカラムをdatetime型に変換
data['time_stamp'] = pd.to_datetime(data['time_stamp'])

# 全体の最も古い時刻と最新の時刻を取得
start = min(data['time_stamp'])
end = max(data['time_stamp'])

# 全期間の半分を学習期間とする
interval = (end - start) / 2

# 前半を学習用、後半を検証用に分割
data_train = data[data['time_stamp'] <= start + interval]
data_val   = data[data['time_stamp'] > start + interval]

解説
ここでは、時系列に沿った分割を行うことで、未来の未知データを検証用として確保しています。


学習用データの前半・後半で説明変数と目的変数を作成

学習用データ(data_train)をさらに、前半を特徴量(説明変数用)、後半を目的変数用に分割します。
※後半のデータを使って、将来のユーザー行動(例えば、購入など)を予測するモデルを構築することを想定しています。

# 学習用データ内で最も古い時刻と最新時刻を取得
start_train = min(data_train['time_stamp'])
end_train   = max(data_train['time_stamp'])

# 学習期間の半分の期間を特徴量作成用とする
interval_train = (end_train - start_train) / 2

# 特徴量(説明変数)データ:学習用データの前半
data_train_X = data_train[data_train['time_stamp'] <= start_train + interval_train]

# 目的変数データ:学習用データの後半
data_train_y = data_train[data_train['time_stamp'] > start_train + interval_train]

解説
この分割により、過去のデータから抽出した特徴量と、未来の行動を示す目的変数を別々に作成できます。


ユーザーに関する特徴量の作成

ここでは、data_train_Xを用いて、各ユーザーごとに以下の特徴量を作成します。

  • ユニーク商品数(u_p)
    そのユーザーが触れた異なる商品数
  • 行動日数(u_d)
    ユーザーが実際に何日間行動したか(重複を除く日付の数)
  • 詳細ページ閲覧回数(u_pv)
    event_typeが1(詳細ページ閲覧)の回数
# 各ユーザーが関わったユニーク商品数
u_p = data_train_X.groupby('user_id').apply(lambda x: len(x['product_id'].unique()))

# 各ユーザーが何日間行動したか(日付のみ抽出してカウント)
u_d = data_train_X.groupby('user_id').apply(
    lambda x: len(x['time_stamp'].apply(lambda t: t.date()).unique())
)

# 各ユーザーの詳細ページ閲覧回数(event_type==1)
u_pv = data_train_X.groupby('user_id').apply(lambda x: (x['event_type'] == 1).sum())

解説
groupbyapplyを活用して、各ユーザーごとに集計処理を行っています。


ユーザー特徴量の連結

作成した3つのシリーズを横方向に連結し、カラム名を分かりやすく変更します。

# 3つのシリーズを連結
u = pd.concat([u_p, u_d, u_pv], axis=1)

# カラム名を設定
u.columns = ['u_p', 'u_d', 'u_pv']

# 結果を確認
print(u.head())

解説
これにより、各ユーザーの特徴が1つのDataFrameとしてまとまります。


商品に関する特徴量の作成

次に、各商品ごとに以下の特徴量を作成します。

  • ユニークユーザー数(p_u)
    その商品に対して行動したユニークなユーザー数
  • カート投入回数(p_ca)
    event_typeが0(カート投入)の回数
  • 詳細ページ閲覧回数(p_pv)
    event_typeが1(詳細閲覧)の回数
  • クリック回数(p_cl)
    event_typeが2(広告クリック)の回数
  • 購入回数(p_cv)
    event_typeが3(購入)の回数
# 各商品に対するユニークユーザー数
p_u = data_train_X.groupby('product_id').apply(lambda x: len(x['user_id'].unique()))

# カート投入回数(event_type==0)
p_ca = data_train_X.groupby('product_id').apply(lambda x: (x['event_type'] == 0).sum())

# 詳細閲覧回数(event_type==1)
p_pv = data_train_X.groupby('product_id').apply(lambda x: (x['event_type'] == 1).sum())

# 広告クリック回数(event_type==2)
p_cl = data_train_X.groupby('product_id').apply(lambda x: (x['event_type'] == 2).sum())

# 購入回数(event_type==3)
p_cv = data_train_X.groupby('product_id').apply(lambda x: (x['event_type'] == 3).sum())

解説
商品ごとにユーザーの行動を集計し、商品の人気度や注目度を示す指標として活用します。


商品特徴量の連結

上記の各商品特徴量を連結して、カラム名を変更します。

# 5つのシリーズを横方向に連結
p = pd.concat([p_u, p_pv, p_ca, p_cl, p_cv], axis=1)

# カラム名を設定
p.columns = ['p_u', 'p_pv', 'p_ca', 'p_cl', 'p_cv']

# 結果を確認
print(p.head())

ユーザー×商品に関する特徴量の作成

各ユーザーと商品のペアごとに、以下の特徴量を作成します。

  • カート投入回数(u_p_ca)
  • 詳細ページ閲覧回数(u_p_pv)
  • クリック回数(u_p_cl)
  • 購入回数(u_p_cv)
# ユーザー×商品ペアごとにカート投入回数(event_type==0)
u_p_ca = data_train_X.groupby(['user_id', 'product_id']).apply(lambda x: (x['event_type'] == 0).sum())

# 詳細閲覧回数(event_type==1)
u_p_pv = data_train_X.groupby(['user_id', 'product_id']).apply(lambda x: (x['event_type'] == 1).sum())

# 広告クリック回数(event_type==2)
u_p_cl = data_train_X.groupby(['user_id', 'product_id']).apply(lambda x: (x['event_type'] == 2).sum())

# 購入回数(event_type==3)
u_p_cv = data_train_X.groupby(['user_id', 'product_id']).apply(lambda x: (x['event_type'] == 3).sum())

解説
ユーザーと商品の組み合わせごとに行動を集計し、個々の相性や過去の相互作用を示す特徴量として利用します。


ユーザー×商品特徴量の連結

上記のペアごとの特徴量を連結し、カラム名を設定します。

# 4つのシリーズを横方向に連結
u_p_features = pd.concat([u_p_pv, u_p_ca, u_p_cl, u_p_cv], axis=1)

# カラム名を設定
u_p_features.columns = ['u_p_pv', 'u_p_ca', 'u_p_cl', 'u_p_cv']

# 結果を確認
print(u_p_features.head())

各特徴量データの統合

これまで作成したユーザー特徴量(u)、商品特徴量(p)、ユーザー×商品特徴量(u_p_features)を統合して、1つのデータにまとめます。
各DataFrameでは元々user_idproduct_idがインデックスになっているため、reset_index()を使ってカラムに戻します。

# ユーザー特徴量のuser_idをカラムに変換
u = u.reset_index()

# 商品特徴量のproduct_idをカラムに変換
p = p.reset_index()

# ユーザー×商品特徴量のインデックス(user_id, product_id)をカラムに変換
u_p_features = u_p_features.reset_index()

# u_p_featuresとuをuser_idでマージ
merged = pd.merge(u_p_features, u, on='user_id', how='inner')

# mergedとpをproduct_idでマージ
merged = pd.merge(merged, p, on='product_id', how='inner')

# 結果を確認
print(merged.head())

解説
ここで得られるDataFrameは、各ユーザー×商品のペアごとにユーザー、商品、双方の特徴量がまとめられたものとなります。


目的変数(関連度)の作成

目的変数は、未来の行動(ここでは学習用データ後半のdata_train_y)から、各ユーザー×商品のペアに対して付与します。
ここでは、各グループ内で最大のevent_typeに1を足した値を「関連度」と定義します(例:行動がなければ0、何らかの行動があれば1以上)。

# ユーザー×商品ごとに、未来の行動の最大値に1を足して関連度を定義
rel = data_train_y.groupby(['user_id', 'product_id']).apply(lambda x: max(x['event_type']) + 1)

# インデックスをカラムに戻す
rel = rel.reset_index()

# 目的変数のカラム名を'y'に変更
rel = rel.rename(columns={0: 'y'})

# 結果確認
print(rel.head())

解説
これにより、各ユーザー×商品のペアごとに、将来の行動(購入等)の度合いを数値で表現できます。


特徴量データと目的変数データのマージ

最後に、特徴量データ(merged)と目的変数データ(rel)をマージします。
ここでは、両期間に共通するユーザーのみ対象とし、outer joinで統合後、欠損値は0で補完、さらに目的変数yを整数型に変換します。

# 特徴量データ中のユーザー一覧を抽出
user_x = set(merged['user_id'])
# 目的変数データ中のユーザー一覧を抽出
user_y = set(rel['user_id'])
# 両方に共通するユーザー
user_xy = user_x.intersection(user_y)

# 特徴量データから共通ユーザーのみ抽出
merged = merged[merged['user_id'].isin(user_xy)]

# 目的変数データから、特徴量データに存在するユーザー×商品のペアのみ抽出
rel = pd.merge(merged[['user_id', 'product_id']], rel, on=['user_id', 'product_id'])

# 特徴量データと目的変数データをouter joinでマージ
train_all = pd.merge(merged, rel, on=['user_id', 'product_id'], how='outer')

# 欠損値を0で補完
train_all = train_all.fillna(0)

# 目的変数'y'を整数型に変換
train_all['y'] = train_all['y'].astype(int)

# 最終的な学習データの確認
print(train_all.head())

解説
これで、最終的な学習用データ「train_all」が完成し、各ユーザー×商品のペアごとに特徴量と未来の行動(関連度)が結合された状態になります。

まとめ

今回の記事では、データファイル「sate_demo_train.tsv」を用い、以下の一連の工程を実装しました。

  1. データの読み込みと時系列に沿った学習/検証データの分割
  2. 学習用データの前半・後半による説明変数と目的変数の作成
  3. ユーザー、商品の各特徴量の作成と連結
  4. ユーザー×商品ペアごとの特徴量作成
  5. 各特徴量データと目的変数データの統合(マージ)

これらのステップを実践することで、推薦エンジン構築に必要な前処理と特徴量エンジニアリングの基礎を学ぶことができます。実際に手を動かしてコードを動かすことで、pandasの使い方やデータの分割・統合の考え方が身に付くでしょう。

ぜひ、実データで試してみてください!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次