1. Qiita
  2. 投稿
  3. 機械学習

fastTextを使って単語じゃないものの分散表現を獲得する

  • 21
    いいね
  • 0
    コメント
に投稿

Retty Advent Calendarで穴が空きそうになったとき用に記事用意してたんですが、ちゃんとみんな埋めてくれたみたいです。良かった。
で、用意した記事が無駄になってももったいないので普通の記事として公開しちゃいます。

皆さんfastTextって知ってますか?
Facebookが公開している自然言語処理用のツールです。GPU使わないのに超速いのでありがたく使ってます。
単語の分散表現を学習させたり文章の分類とかができるんですが、分散表現の学習の仕組みって語彙にID振ってone-hot vectorにして、それを次元圧縮してるんですよね?(適当)
じゃあ、ID列で表せる何かならなんでも分散表現にできるんじゃね?って思いません?
思いついたらやってみましょう。

用意するもの

  • fastText
  • Rettyユーザーのお店詳細ページの閲覧履歴

やること

Rettyのお店詳細ページの閲覧履歴からお店の分散表現を獲得できるか試す。

やってみた

まずは1行に1ユーザーの閲覧したお店のIDが時系列順にスペース区切りに並んだファイルを用意します。
こんな感じです

visit_history.dat
100000742124 100000706532 100000733147 100000004915 100001262703 100001215921 ...
100000008314 100000699913 100000052680 100000798310 100001211986 ...
...
※内容は適当です。

で、これをそのままfastTextに渡すだけです。

fasttext skipgram -input visit_history.dat -output output  -epoch 300

こうすると、カレントディレクトリに

output.bin 
output.vec

ができます。output.vecが各お店の分散表現になってます。中身は

お店の数 ベクトルの次元数
<お店ID> <ベクトル値>,...
<お店ID> <ベクトル値>,...
...

て感じです。

ではこの結果を使って各お店に近い店を探してみましょう。

import numpy as np

n_result = 100

# read data
with open('output.vec', 'r') as f:
    ss = f.readline().split()
    n_vocab, n_units = int(ss[0]), int(ss[1])
    store2index = {}
    index2store = {}
    w = np.empty((n_vocab, n_units), dtype=np.float32)
    for i, line in enumerate(f):
        ss = line.split()
        store = ss[0]
        store2index[store] = i
        index2store[i] = store
        w[i] = np.array([float(s) for s in ss[1:]], dtype=np.float32)

# normalize
s = np.sqrt((w * w).sum(1))
w /= s.reshape((s.shape[0], 1))

# calc similarity
stores = store2index.keys()
try:
    for store in stores:
        v = w[store2index[store]]
        similarity = w.dot(v)
        count = 0
        for i in (-similarity).argsort():
            if np.isnan(similarity[i]):
                continue
            if index2store[i] == store:
                continue
            print 'https://retty.me/restaurant/{}'.format(store),"https://retty.me/restaurant/{}".format(index2store[i]), similarity[i]
            count += 1
            if count == n_result:
                break
except EOFError:
    pass

結果の一例を挙げると、

お店1 お店2 類似度
ミディ・アプレミディ 然花抄院 京都室町本店 0.999405

両方とも京都の烏丸御池あたりのスイーツなお店ですね。

お店1 お店2 類似度
Fish Market丸秀 サンパチキッチン 今泉店 0.996479

どっちも福岡市のイタリアンですね。

お店1 お店2 類似度
バー タツミ シャンパーニュバー ポンポンヌ 0.998517

広尾駅あたりのバーですね。

たまに小樽と東京の店が近かったりとか変なのも出ちゃいますが結構うまくいきそうです。

まとめ

これで口コミが少ない店でも分析できる!
いつからfastTextが自然言語処理用だと錯覚していた?

Comments Loading...