見出し画像

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

ちなみに機械学習の出力はこんな感じ↓

スクリーンショット 2020-08-24 22.36.47

・・・

・・

画像2

機械学習モデルによりユーザーに対して予測を行う

# 機械学習モデル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

・・・

・・

画像2

(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の間を取り値が高いほど精度が高いそう

結果は↓

スクリーンショット 2020-08-24 23.01.23

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行で終わるのでなんか拍子抜け
むしろデータの確認や、分割結合に時間がかかった感

まあそんなものなのでしょう。
他のもやってみたい。




いつもサポートありがとうございます。 難しい方は感想をコメントでいただけると嬉しいです。