読者です 読者をやめる 読者になる 読者になる

uyamazakのブログ

仕事中の問題と解決メモ。PythonとGoogle Cloudがメイン。bizoceanで新規事業の企画と開発担当。 BigQueryを使ったビッグデータ収集・解析・リアルタイム処理プロジェクト進行中 https://github.com/uyamazak/oceanus

Word2Vecを使って行動履歴から関連商品やおすすめ商品を出す

bizoceanで集めたデータを使って何かできないかを考えていたら、少し前に話題になったWord2Vecを使って書式のダウンロード履歴を文章として入力すれば、近いベクトルの書式、つまり関連性の高い書式が出せるのでは?と思い試してみた。

おすすめ、レコメンドにも使えそう。

Word2Vecについては下記がわかりやすい。
deepage.net

ただの単語の羅列をn次元のベクトル化してくれるのは、データの用意も簡単な上、いろいろ加工もしやすくて便利。


データのもととなるbizoceanは、請求書、履歴書、契約書などの書式のダウンロードサイト。
www.bizocean.jp

ほとんどが無料だけど、2016年から有料販売もできるようになった。

他のECサイトなどでは、ダウンロードではなく、購入になるだろう。



まず、文章のように、ユーザーごとのDL履歴を1行ずつ、スペース区切りで書き出す。

環境はoceanusを使って、BigQueyにぶち込んだアクセスログを、Google Cloud Datalab(Jupyter)で。

cloud.google.com


SQLは下記のような感じ。

SELECT doc_ids FROM
(
  SELECT
    sid,
    GROUP_CONCAT_UNQUOTED(doc_id, " ") as doc_ids,
    count(doc_id) as count
  FROM
  (
  SELECT
    sid,
    doc_id
  FROM
   ( SELECT 
      sid,
      dt,
      REGEXP_EXTRACT(url, r'/doc/download/complete/([0-9]+)/') as doc_id,
    FROM TABLE_DATE_RANGE(
      {TABLE_PREFIX},
      TIMESTAMP("{FROM}"), 
      TIMESTAMP("{TO}")
    )
    WHERE
      evt = "pageview" AND 
      url CONTAINS "/doc/download/complete/"
      ORDER BY dt ASC
    )
  GROUP BY
    sid,
    doc_id
  )
  GROUP BY
  sid
)
WHERE count > 1


これの実行結果をファイルに書き出す。to_fileで一発。

import datalab.bigquery as bq
query = bq.Query("""上記のSQL""")

query.to_file("donwload_relative_.csv")

csvは下記のようなファイルになる。1つだけでは意味が無いので、2DL以上した人のみを対象にした。3ヶ月程度で20万行弱、7MBのデータになった。

doc_ids
100454 103502 103002
104552 102249 102230 104526
108875 517686 516829 517682 108177 517680 517677 517679
520271 518137 104615 100956 516761 519367 519366 102746 519880 103574
520693 108875 521525 519565 521536 516128 109213 521490 521528 521445 521537 100550 521522 521677 520694 109042 517770 521696 521790 521208 521904 519006 521807 521686 109209 521275 101698 102384 520599 103661 103189 107848 521252 521768 518169
104443 109407 107643 521478 103113 519969 103428 103104 103177 515111 104487
104710 516744 516750 104712 104714
102728 109481 108971 105489 104446
103438 516191
516761 102763 516791
103101 106929 106932 100549 103141 102068 100556
500108 104449 519125 517878 519706 102724 500110
519467 517568 103601 518222 103114 517998 109407 519365 519737 515198 518201 103183 521047 100570 520320 515257 519250 102880
516741 520351
520351 104713
521206 521258 521270 521213 521217 521259 521481 521246
521256 521234 521534 521496 521538 521230 521267 521536 521229 521552 521411 521258 521246 521247 521461 521212 521532 521265 521537 521266 521522 521495 521255 521225 521447 521549 521525 521528 521213 521487 521444 521254 521541 521453 521553 521523 521242 521249 521251 521257 521542 521494 521530 521478
519250 520268 102901 518138
500418 104393 518306
518205 106898 101682 516772 103714 104761 100971
104570 102349
521537 521213 521536 521229 521252 521246 521443 521542 521218 521322 521517 521532 521247 521250 521214 521534 521237
104475 109362
516797 515042 516780 516486 516768
516744 104710 107846 519511 515633 520353 515644 104715
516268 515041 103127 104478 515040 109390 103126
521227 521252 521521 521487 521213 521524 521105 521537 521646 521231 521530 519982
519509 520358
104714 104712
518362 518354
104714 104710 104711

Word2Vecの実装には、gensimを使う。別途pipでインストール。今回はDatalabなので、Dockerfileを使ってインストールしておいた。
詳しいカスタマイズ方法は↓
uyamazak.hatenablog.com



gensim: models.word2vec – Deep learning with word2vec

from gensim.models import word2vec
#data = word2vec.Text8Corpus('donwload_relative_20170213-01.csv')
data = word2vec.LineSentence("donwload_relative_" + filename + ".csv")

ググって出て来る記事だとText8Corpusが使われてるけど、行ごとに処理してくれる?LineSentenceを使う。

モデルの作成。これが重い。

model = word2vec.Word2Vec(data, size=200, window=5, min_count=20, workers=8)

実行マシンは社内のサーバーマシンで
Intel(R) Xeon(R) CPU E3-1230 v5 @ 3.40GHz、メモリ32GBを兼ね備えているけど、20分ぐらいかかる。

モデル作成が終わったらmost_similarを使って、一番近いものを出す。
これは爆速、一瞬で帰ってくる。

200次元とはいえ、単純な行列の計算になるから早いのだと思ってる。

targetに書式IDを入れる。

out=model.most_similar(positive=[target], topn=15)

IDだけだとよくわからないので、書式名が入ってるテーブルから名前を取ってpandasでくっつけた。

一番人気の「請求書003 シンプルな請求書」を入れてみた
請求書003 シンプルな請求書|テンプレートのダウンロードは【書式の王様】

102693 請求書004 0.841390490532
517568 エクセル請求書(窓付封筒、長3対応) 0.830850958824
517868 請求書01 0.827962636948
519366 スタイリッシュな請求書(イエロー) 0.82549983263
102417 請求書006 0.825079739094
520271 自動計算付きの請求書(エクセル) 0.824660122395
102418 請求書012(サービス業用) 0.815610051155
104445 請求書008(サービス業用) 0.815160274506
102748 請求書05 0.814028024673
102419 請求書007 0.808267712593
519880 請求書&送付状 0.795116245747
104615 請求書001 0.793960869312
517422 請求書(窓付封筒、長3対応) 0.793055713177
518137 請求書010 0.787589609623
520984 シンプル請求書_スマホ入力用 0.785955011845


スケジュール表
スケジュール表|テンプレートのダウンロードは【書式の王様】

520286 スケジュール表:ガントチャート式【改】 0.960333704948
521092 工程管理表 スケジュール管理表 2016年3月~ 0.960129082203
521176 工程管理表 スケジュール管理表 2016年9月~ 0.946121633053
516756 Excelで作るA41枚の月間スケジュール管理 0.942580997944
104454 建築業用作業工程表(年間) 0.912206470966
500428 工程管理_04 0.912127077579
521111 2016年度カレンダー 一覧(2016年4月~) 0.886768221855
521186 課題管理表_2016年 0.879617512226
516786 Wordで作るA41枚の月間スケジュール管理 0.879371285439
517912 年間スケジュール2014 0.877403259277
500422 工程管理_02 0.875747382641
521100 2016年度カレンダー 0.862578749657
500426 工程管理_03_製造業 0.861161231995
517999 2014年 年間カレンダー 0.856253266335
104453 建築業用作業工程表(月間) 0.849661827087


ニワトリとカラフルな花飾りの年賀状
ニワトリとカラフルな花飾りの年賀状|テンプレートのダウンロードは【書式の王様】
当たり前だけど、年賀状でもポップなものを入れれば、ポップなものが返ってくる。

521915 富士山と門松の年賀状2017 酉・鳥 0.953142642975
521445 ニワトリと花の年賀状 0.952863097191
521416 ニワトリと富士山の年賀状 0.946253061295
521446 ひよこの年賀状 0.944137215614
521530 楽しい音楽隊 0.94397175312
521225 鶏の家族がかわいらしい年賀状 0.937339186668
521523 虹を渡って行こう! 0.934369027615
521533 お散歩 0.926785349846
521251 木にとまる鶏の年賀状 0.925209403038
521497 ニワトリとヒヨコの年賀状 0.92281216383
521542 (word)酉年をお花で彩る年賀状 0.917050004005
521913 (word)コマ回し名人(酉年) 0.913929462433
521520 ハートの仲良し一家 0.912433743477
521517 水引飾り・酉:jpg 0.910482287407
521524 パンダと体操 0.910432219505

作成したモデルはメモリ上にあるけど、ファイルに書き出しておくこともできる

model.save("donwload_relative.model")
model.load("donwload_relative.model")

モデル作成さえバッチなどで処理してしまえば、2万件近くあっても、瞬時にレスポンスできるのでAPI化も簡単にできそう。


ユーザーの購入履歴、行動履歴に基づいたレコメンドなどを考えていて、難しいものは避けたい方は、こんな感じで気軽にWord2Vecを使うのもありだと思う。


おまけ

networkxを使って、近いものをネットワーク表示してみた。読めない。
f:id:uyamazak:20170214163219p:plain