100日後にプロになるワシ12日目(python)
やったこと
pythonで機械学習。
ECサイトにおける購買率の最適化をAIで行う
参考
https://quest.signate.jp/quests/10028
前回は機械学習前の前段階。
今回は前回より作成した学習用データと予想データを使って
モデリングを作成する。
機械学習モデルへ入力するためのデータの作成する
# クエリリスト作成
query_list = train_all['user_id'].value_counts()
# user_id, product_idをインデックス化
train_all = train_all.set_index(['user_id', 'product_id'])
# クエリリストをインデックスでソート
query_list = query_list.sort_index()
# 特徴量と目的変数データをインデックスでソート
train_all = train_all.sort_index()
# 特徴量(['p_u', 'p_pv', 'p_ca', 'p_cl', 'p_cv', 'u_p', 'u_d', 'u_pv', 'u_p_pv', 'u_p_ca', 'u_p_cl', 'u_p_cv'])のみ抽出
X_train = train_all[['p_u', 'p_pv', 'p_ca', 'p_cl', 'p_cv', 'u_p', 'u_d', 'u_pv', 'u_p_pv', 'u_p_ca', 'u_p_cl', 'u_p_cv']]
# 目的変数('y')を抽出
y_train = train_all['y']
ポイント:クエリリストとは
クエリリストの前にまずはクエリについて調べた
クエリ(英:query)とは
データベースさんに対する「おい!これやれよ」な命令文のこと。
あるいは
調べ物をするときに検索エンジンさんに入力する検索キーワードのことです。 by https://wa3.i-3-i.info/word11290.html
とのことなので
つまり命令リストですね。
機械に学習させるリストってとこかな
ポイント:インデックス化について
これはuser_id,product_idというラベル自体が、
このままだと機械学習の学習情報として読み込まれてしまうので
これはラベルですよ(インデックス)と分ける作業
で、そのインデックスでソート。
特徴量(学習用情報)と目的変数(解答)で分ける。
機械学習モデルを学習させる
# lightgbmをlgbとしてインポート
import lightgbm as lgb
# LGBMRankerのモデルを作成
model = lgb.LGBMRanker()
# LGBMRankerを作成して学習
model.fit(X_train, y_train, group=query_list, eval_set=[(X_val, y_val)], eval_group=[list(query_list_val)])
(ライブラリを利用するとわずか3行で学習が終わる)
ポイント:lightgbm
機械学習にもその学習方法が色々あって
わかりやすくいうと暗記系とか計算系とかそんな感じ
もっと機械学習的に言えば分類問題や回帰問題がある。
今回はランク学習というのが向いているそうで、
そのランク学習をパッケージ化したのがlightgbm
これを動かすだけで学習できる
ちなみに公式サイトはここ
日本語でおk
ちなみに機械学習の出力はこんな感じ↓
・・・
・・
機械学習モデルによりユーザーに対して予測を行う
# 機械学習モデルmodelのユーザーID'0000018_B'に対する出力結果
pred = model.predict(X_val.loc['0000018_B'])
# 商品IDとの紐づけ
pred_products = pd.Series(pred, index = X_val.loc['0000018_B'].index)
# 商品を関連度順に並べ替え
products = pred_products.sort_values(ascending=False).index
# 上位5件を出力
output = list(products)[:5]
print(output)
ようわからんのでテストする(検証ですね)
ポイント:model, predict
今学習したAIがmodelという変数に入っているので、このmodelを使ってテストする。そのテストするメソッドがpredict
モデルでテストするときはmode.predict!!
早速ユーザーidを入れてテストだ。
pred = model.predict(X_val.loc['0000018_B'])
> [-0.31933539 -0.28224029 -0.08723626 -0.28224029]
この配列だけだと意味わかんないんでproduct_idとひもづける。
(この配列のインデックスはproduct_idなので)
ポイント: その紐付けがpd.Series
結果こう↓
product_id
00001352_b -0.319335
00003021_b -0.282240
00005909_b -0.087236
00008500_b -0.282240
・・・
・・
(00001352_bが-0.319335とか言われても意味わからん!!)
一応この数値は先ほど入力したユーザーID(0000018_B)に対する
関連度ということになるらしい
まあこれはあくまでモデル(今回のAI)が出した予想ということになる
これを先ほど分割した解答と合わせて比較する
予測結果に対する精度評価
# ユーザーID'0000018_B'の予測結果outputに対するnDCG
print(ndcg(output, y_val.loc['0000018_B']))
# 予測結果の確認
print('\nprediction:')
print(output)
# 正解の確認
print('\nground truth:')
print(list(y_val.loc['0000018_B'].sort_values(ascending=False).index))
ポイント:nDCG
outputというのが機械の予想
y_valというのが解答(説明変数)になります。
それを比較するのがnDCG
nDCGは0〜1の間を取り値が高いほど精度が高いそう
結果は↓
1.0。つまり100%当たってる!
predictionが、予想した関連度の順番で
ground truthが、解答何ですが
4つの並び順なら紛れ当たりもありそうですよね。。。
複数のユーザーに対する予測結果を出力する
とにかく(?)結果がよかったので全ユーザーに適応してそのリストをexcelに書き出します
# ユーザー一覧取得
users = pd.read_csv('users.tsv', sep='\t', header=None)
# ユーザー一覧に対する予測結果
user_ids = []
product_ids = []
ranks = []
for user in users[0]:
pred = model.predict(X_val.loc[user])
pred_products = pd.Series(pred, index=X_val.loc[user].index)
products = pred_products.sort_values(ascending = False).index
output = list(products)[:20]
user_ids += [user]*len(output)
product_ids += output
ranks += list(range(1,len(output)+1))
# 結果を連結
results = pd.DataFrame({'user_id':user_ids, 'product_id':product_ids, 'rank': ranks})
# 結果の確認
print(results.head())
# 'results.tsv'として保存
results.to_csv('results.tsv', sep='\t', header=False, index=None)
一応こんなふうに出力されます
user_id product_id rank
0 0000015_B 00000744_b 1
1 0000018_B 00005909_b 1
2 0000018_B 00008500_b 2
3 0000018_B 00003021_b 3
4 0000018_B 00001352_b 4
要するに0000015_Bは00000744_bに関連があり
0000018_Bは00005909_bに関連があるということ
この表を元にレコメンドを表示させればいい
要するにおすすめ商品ですね。
次回はこれをさらに改良するそうな
感想
なんか機械学習自体が3行で終わるのでなんか拍子抜け
むしろデータの確認や、分割結合に時間がかかった感
まあそんなものなのでしょう。
他のもやってみたい。