Python入門トップページ


目次

  1. 協調フィルタリングによる推薦システム
  2. 顧客間の類似度に基づいた手法
  3. 個別データを順にマージしてみる
  4. 個別データを一気にマージしてみる
  5. 行列分解
  6. サンプルコードのまとめ
  7. Surprise による顧客間類似度に基づいた手法
  8. Surprise による行列分解
  9. ユーザごとの推薦アイテムリストを作成する
  10. 推薦アルゴリズムの性能を評価する
  11. 適合率と再現率
  12. クロスバリデーション
  13. 学習済みモデルの保存と読み込み

協調フィルタリングによる推薦システムを作ってみよう

個別データを順にマージしてみる

前のページでは予め行列形式に集計された評価値データを読み込んで協調フィルタリングを行いました.しかしながら,実際は集計されていない生の評価値データから行列形式に変換する必要があります.ここでは,「商品データ」「顧客データ」「評価データ」の3つのデータを読み込んで順に行列形式に集計する方法を確認します.

目次に戻る

データを読み込む

まず,必要なライブラリをインポートします.


import pandas as pd
import numpy as np

商品のCSVデータを GitHub のリポジトリからデータフレームに読み込みます.


url_items = "https://github.com/rinsaka/sample-data-sets/blob/master/collaborative_filtering_items.csv?raw=true"
df_items = pd.read_csv(url_items)
print(df_items)
   id item
0   0    A
1   1    B
2   2    C
3   3    D
4   4    E

顧客のCSVデータを読み込みます.


url_customers = "https://github.com/rinsaka/sample-data-sets/blob/master/collaborative_filtering_customers.csv?raw=true"
df_customers = pd.read_csv(url_customers )
print(df_customers)
   id   name
0   0    Eto
1   1   Sato
2   2   Kato
3   3   Muto
4   4   Kito
5   5   Goto
6   6   Bito
7   7  Saito
8   8  Naito
9   9   Koto

次に,評価のCSVデータを読み込みます.例えば先頭行は,顧客ID = 8 の Naito さんが,商品ID = 3 の商品「D」について「2」という評価を行ったことを意味しています.


url_ratings = "https://github.com/rinsaka/sample-data-sets/blob/master/collaborative_filtering_ratings.csv?raw=true"
df_ratings = pd.read_csv(url_ratings)
print(df_ratings)
    customer  item  rating
0          8     3       2
1          1     1       2
2          6     1       3
3          9     2       2
4          6     0       3
5          2     2       4
6          1     2       4
7          4     2       3
8          3     2       2
9          8     0       5
10         0     0       5
11         2     1       3
12         4     0       4
13         5     4       3
14         7     2       5
15         8     4       1
16         5     3       2
17         6     4       1
18         0     1       4
19         1     3       2
20         5     0       2
21         7     1       4
22         0     2       3
23         5     1       5
24         3     1       3
25         8     1       5
26         3     4       2
27         8     2       4
28         9     3       2
29         1     4       3
30         6     2       2
31         2     0       2
32         3     0       2
33         9     4       2
34         7     4       5
35         7     0       4
36         9     0       3
37         4     3       4
38         4     1       3

目次に戻る

テーブルの結合

3つのテーブル(表のこと)を順に結合していきます.まず,「評価」と「商品」のテーブルを結合します.なお,テーブルの結合に関する詳細はここここで確認してください.


tbl_1 = pd.merge(
    df_ratings, df_items,
    left_on = 'item',
    right_on = 'id',
)
print(tbl_1)
    customer  item_x  rating  id item_y
0          8       3       2   3      D
1          5       3       2   3      D
2          1       3       2   3      D
...(中略)...
36         1       4       3   4      E
37         9       4       2   4      E
38         7       4       5   4      E

列名「item_y」を「item」に変更します.


tbl_1 = tbl_1.rename(columns={'item_y': 'item'})
print(tbl_1)
    customer  item_x  rating  id item
0          8       3       2   3    D
1          5       3       2   3    D
2          1       3       2   3    D
・・・(省略)

必要な列だけ残し,さらに順序も変更します.


tbl_1 = tbl_1.loc[:,['customer','item','rating']]
print(tbl_1)
    customer item  rating
0          8    D       2
1          5    D       2
2          1    D       2
...(省略)...

今出来上がったテーブルと「顧客」テーブルを結合します.


tbl_2 = pd.merge(
    tbl_1, df_customers,
    left_on = 'customer',
    right_on = 'id',
)
print(tbl_2)
    customer  item_x  rating  id_x item  id_y   name
0          8       3       2     3    D     8  Naito
1          8       1       5     1    B     8  Naito
2          8       2       4     2    C     8  Naito
3          8       0       5     0    A     8  Naito
4          8       4       1     4    E     8  Naito
5          5       3       2     3    D     5   Goto
6          5       1       5     1    B     5   Goto
・・・(中略)...
34         7       4       5     4    E     7  Saito
35         3       1       3     1    B     3   Muto
36         3       2       2     2    C     3   Muto
37         3       0       2     0    A     3   Muto
38         3       4       2     4    E     3   Muto

同様の方法で列名を変更した上で,列を選択し順序も変更します.


# 表示系列名の変更
tbl_2 = tbl_2.rename(columns={'id_y': 'id'})
# 列の選択と順序の変更
tbl_2 = tbl_2.loc[:,['id', 'name','item','rating']]
print(tbl_2)
    id   name item  rating
0    8  Naito    D       2
1    8  Naito    B       5
2    8  Naito    C       4
3    8  Naito    A       5
4    8  Naito    E       1
5    5   Goto    D       2
6    5   Goto    B       5
7    5   Goto    A       2
8    5   Goto    E       3
9    1   Sato    D       2
10   1   Sato    B       2
11   1   Sato    C       4
12   1   Sato    E       3
13   9   Koto    D       2
14   9   Koto    C       2
15   9   Koto    A       3
16   9   Koto    E       2
17   4   Kito    D       4
18   4   Kito    B       3
19   4   Kito    C       3
20   4   Kito    A       4
21   6   Bito    B       3
22   6   Bito    C       2
23   6   Bito    A       3
24   6   Bito    E       1
25   2   Kato    B       3
26   2   Kato    C       4
27   2   Kato    A       2
28   0    Eto    B       4
29   0    Eto    C       3
30   0    Eto    A       5
31   7  Saito    B       4
32   7  Saito    C       5
33   7  Saito    A       4
34   7  Saito    E       5
35   3   Muto    B       3
36   3   Muto    C       2
37   3   Muto    A       2
38   3   Muto    E       2

目次に戻る

評価の集計

評価の生データをピボットテーブルを利用して行列形式にまとめます.まず,念の為に顧客と商品ごとの評価数を確認します.つまり,同一顧客が同じ商品に複数回評価していないかを確認しておきます.この結果,1.0 より大きなデータがない,つまり,同じ商品を複数回評価しているデータはないことがわかりました.


df = tbl_2.pivot_table('rating', index=['id', 'name'], columns='item', aggfunc='count')
print(df)
item        A    B    C    D    E
id name
0  Eto    1.0  1.0  1.0  NaN  NaN
1  Sato   NaN  1.0  1.0  1.0  1.0
2  Kato   1.0  1.0  1.0  NaN  NaN
3  Muto   1.0  1.0  1.0  NaN  1.0
4  Kito   1.0  1.0  1.0  1.0  NaN
5  Goto   1.0  1.0  NaN  1.0  1.0
6  Bito   1.0  1.0  1.0  NaN  1.0
7  Saito  1.0  1.0  1.0  NaN  1.0
8  Naito  1.0  1.0  1.0  1.0  1.0
9  Koto   1.0  NaN  1.0  1.0  1.0

重複した評価がないことが確認できたので,合計を計算すると簡単に集計できます.


df = tbl_2.pivot_table('rating', index=['id', 'name'], columns='item', aggfunc='sum')
print(df)
item        A    B    C    D    E
id name
0  Eto    5.0  4.0  3.0  NaN  NaN
1  Sato   NaN  2.0  4.0  2.0  3.0
2  Kato   2.0  3.0  4.0  NaN  NaN
3  Muto   2.0  3.0  2.0  NaN  2.0
4  Kito   4.0  3.0  3.0  4.0  NaN
5  Goto   2.0  5.0  NaN  2.0  3.0
6  Bito   3.0  3.0  2.0  NaN  1.0
7  Saito  4.0  4.0  5.0  NaN  5.0
8  Naito  5.0  5.0  4.0  2.0  1.0
9  Koto   3.0  NaN  2.0  2.0  2.0

これで行列形式のデータフレームが完成したので,NumPy 配列に格納し,レイティング行列 y を生成します.


y = df.values
print(y)
[[ 5.  4.  3. nan nan]
 [nan  2.  4.  2.  3.]
 [ 2.  3.  4. nan nan]
 [ 2.  3.  2. nan  2.]
 [ 4.  3.  3.  4. nan]
 [ 2.  5. nan  2.  3.]
 [ 3.  3.  2. nan  1.]
 [ 4.  4.  5. nan  5.]
 [ 5.  5.  4.  2.  1.]
 [ 3. nan  2.  2.  2.]]

これは前のページの行列 y と全く同じ形式です.ここまでできれば,類似度の計算やスコアの計算は前のページと同じ方法で可能です.

目次に戻る