Python
自然言語処理
時系列解析
Keras
LSTM

kerasのLSTMでアイテム購入履歴からロイヤルカスタマーになるか予測

アイテムの買い方のパターンから、この顧客がロイヤルカスタマーになりそうか判定したいというニーズがあると仮定します。
そこで、自然言語処理で単語の出現順に時系列扱いで学習させて感情判定するのを応用し、最初の10個までの購入アイテム履歴から、このユーザーが101個目まで購入しているか予測してみました。

データとスクリプト

元データ
UCI Online Retail Data Set

  • アイテムをインデックス化する(単なる識別子のため順不同)
  • 1顧客1行とし、アイテムを購入された順に当該アイテムのインデックス番号を若いカラムに格納
  • 購入されていないカラムはNull

jupyterで見れるスクリプトと加工後のデータはこちら
https://github.com/tizuo/keras/blob/master/is_future_purchase.ipynb
https://github.com/tizuo/keras/blob/master/purchacedata_base.csv

注意点

以下の理由から、今回のデータは本来的に適していないので注意。あくまでも手法の覚書になります。
サンプルにちょうど良いデータがあったら教えてください。

  • 1回の購入アイテム数の最頻値は2となり、最大749と幅広く歪度の高い分布
  • ホールセール業者への販売記録になるため、総購入回数の75%点でも5回と少ない(つまり、101個目を買っているか予測してもあまり意味がない。。)

必要なパラメタの説明

最大index:アイテム数でなく、インデックスがとりうる最大の数に1を足した数を入れる
履歴の枠数:1顧客につき、データセット内に格納したアイテム履歴の数

今回はアイテムに振られたインデックスの最大値が4213、渡す履歴の数が10なので以下のように記述。

top_words = 4214 # insert max index of items + 1
max_length = 10 # length of sequential data

データの読み込みと加工

Yの値がソートされているので、学習用データとテスト用データをランダム抽出します。
抽出したらkerasに投入するためにndarrayに変換します。

df = pd.read_csv("purchacedata_base.csv", header=0)
df = df[df.columns[0:(max_length + 2)]].dropna().astype(int)

train_X, test_X, train_Y, test_Y = cross_validation.train_test_split(df[df.columns[2:(max_length + 2)]], df["Y"])

train_X = train_X.values
train_Y = train_Y.values
test_X = test_X.values
test_Y = test_Y.values

モデルの構築

embedding_vector_length に出力数を代入します。LSTMのステップ数は最頻値の2より1足して3にしました。増やしてもあまり変わらないので、やはりこのデータだとあまり意味がなさそうです。

embedding_vector_length = 5
model = Sequential()
model.add(Embedding(top_words, embedding_vector_length, input_length=max_length))
model.add(LSTM(3))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model.summary())
model.fit(train_X, train_Y, validation_data=(test_X, test_Y), epochs=3, batch_size=64)

検証

scores = model.evaluate(test_X, test_Y, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))

テストデータの正答率は72.41%でした。

今後の展望

一回あたりに購入する数が異なるので、畳込み的に圧縮して購入毎のシーケンスが作れないものかと考えています。