協調フィルタリングアルゴリズムの戦闘

1.協調フィルタリングのアイデア:

協調フィルタリングアルゴリズムは、比較的よく知られており、一般的に使用されている推奨アルゴリズムです。これは、ユーザーの履歴行動データのマイニングに基づいて、ユーザーの好みのバイアスを発見し、ユーザーが推奨する可能性のあるお気に入りの製品を予測します。つまり、「気に入ったと思います」「商品を購入した人も気に入った」などの共通機能です。その主な実現は次のとおりです。

●あなたの好みを共有する人に基づいてあなたに推薦する

●好きなアイテムに合わせて、似たようなアイテムをお勧めします

●上記の条件に基づく総合的な推奨事項

ユーザーブリッジを介してさまざまなアイテムの関連性を把握します。itemaにアクセスしている場合は、どのユーザーがitemaにアクセスしたかを確認し、形成されたアイテムB、C、Dなど、これらのユーザーが履歴で見たアイテムをさらに確認します。転置インデックスのアイデアitemA = itemB、itemC、itemDによって、データベースに直接注入します(単語のセグメンテーションによって取得されたテーブルをデータベースに反転することもできます)。

協調フィルタリングアルゴリズムの分類:

ここに画像の説明を挿入します
この記事では、次の2つの状況について説明します
。1。ユーザーベースのcf:ユーザーベースの協調フィルタリング:友人間の推奨
2.アイテムベースのcfに基づくアイテムベースの協調フィルタリング:過去に購入したアイテムのアイテムベースの協調フィルタリング
学位などの関連アイテムをお勧めします。数字が大きいほど、好きになります。

ユーザーベースのCF:友情の度合いは友達とは異なるため、最初にユーザーの類似度を計算してから、スコアを予測してスコアを推定します。
アイテムベースのcf:過去に購入したアイテムに関連するアイテムを推奨し、アイテムとアイテムの類似性のマトリックスを構築します

協調フィルタリングの実践:

コードのダウンロード:リンク:https://pan.baidu.com/s/1oIA5sPsBhtYfCpRYg1idyA抽出コード:1234

1. MRは、3つのステップのマップと削減に分割された協調フィルタリング(より多くの開発コード)を実装し
ます。1。UIマトリックスを正規化します

1_gen_ui_map.py
#!/ usr / local / bin / python

インポートシステム

sys.stdinの行の場合:
#ss = line.strip()。split( '\ t')
ss = line.strip()。split( '、')
if len(ss)!= 3:
続行
u、i 、s = ss
print“%s \ t%s \ t%s”%(i、u、s)

1_gen_ui_reduce
#!/ usr / local / bin / python

import sys
import math

cur_item =なし
user_score_list = []

sys.stdinの行の
場合item、user、score = line.strip()。split( "\ t")
if not cur_item:
cur_item = item
if item!= cur_item:
sum = 0.0
for tuple in user_score_list:
(u、 s)=タプルの
合計+ = pow(s、2)
sum = math.sqrt(sum)
for tuple in user_score_list:
(u、s)= tuple
print“%s \ t%s \ t%s”%(u、 cur_item、float(s / sum))

user_score_list = []
cur_item = item

user_score_list.append((user、float(score)))


user_score_listのタプルの合計= 0.0
(u、s)=タプルの
合計+ = pow(s、2)
sum = user_score_listの
タプルのmath.sqrt(sum):(
u、s)=タプルの出力
“%s \ t %s \ t%s”%(u、cur_item、float(s / sum))

2.ペアごとにペアリング

2_gen_ii_pair_map
#!/ usr / local / bin / python
import sys

sys.stdinの行の場合:
u、i、s = line.strip()。split( '\ t')
print“%s \ t%s \ t%s”%(u、i、s)

2_gen_ii_pair_reduce
#!/ usr / local / bin / python

インポートシステム

cur_user =なし
item_score_list = []

sys.stdinの行の
場合user、item、score = line.strip()。split( "\ t")
if not cur_user:
cur_user = user
if user!= cur_user:
for i in range(0、len(item_score_list) -1):
範囲内のjの場合(i + 1、len(item_score_list)):
item_a、score_a = item_score_list [i]
item_b、score_b = item_score_list [j]
print“%s \ t%s \ t%s”%( item_a、item_b、score_a * score_b)
print“%s \ t%s \ t%s”%(item_b、item_a、score_a * score_b)

item_score_list = []
cur_user = user

item_score_list.append((item、float(score)))

for i in range(0、len(item_score_list)-1):
for j in range(i + 1、len(item_score_list)):
item_a、score_a = item_score_list [i]
item_b、score_b = item_score_list [j]
print“%s \ t%s \ t%s”%(item_a、item_b、score_a * score_b)
print“%s \ t%s \ t%s”%(item_b、item_a、score_a * score_b)

3.ワードカウントに相当する合計計算

cat 3_sum_map.py
#!/ usr / local / bin / python

インポートシステム

sys.stdinの行の場合:
i_a、i_b、s = line.strip()。split( '\ t')
print“%s \ t%s”%(i_a +“” + i_b、s)

cat 3_sum_reduce.py
#!/ usr / local / bin / python

インポートシステム

cur_ii_pair =なし
スコア= 0.0

sys.stdinの行の場合:
ii_pair、s = line.strip()。split( "\ t")
if not cur_ii_pair:
cur_ii_pair = ii_pair
if ii_pair!= cur_ii_pair:
#item_a、item_b = cur_ii_pair.split( '')
ss = cur_ii_pair.split( '')
if len(ss)!= 2:
続行
item_a、item_b = ss
print“%s \ t%s \ t%s”%(item_a、item_b、score)
cur_ii_pair = ii_pair
スコア= 0.0

スコア+ =フロート

ss = cur_ii_pair.split( '')
if len(ss)!= 2:
sys.exit()
item_a、item_b = ss
print“%s \ t%s \ t%s”%(item_a、item_b、score)

2.
Spark協調フィルタリング(コードは簡単に実装できます)import org.apache.spark。{SparkConf、SparkContext}
import scala.collection.mutable.ArrayBuffer
import scala.math._

object cf { def main(args:Array [String]):Unit = { val conf = new SparkConf()conf.setMaster(“ local [2]”)conf.setAppName(“ CF Spark”)



val sc = new SparkContext(conf)
val lines = sc.textFile(args(0))
val output_path = args(1).toString

val max_prefs_per_user = 20
val topn = 5

//ステップ1.正規化
valui_rdd = lines.map {x =>
val ss = x.split( "\ t")
val userid = ss(0).toString
val itemid = ss(1).toString
val score = ss (2).toDouble

(userid、(itemid、score))
} .groupByKey()。flatMap {x =>
val userid = x._1
val is_list = x._2

#is_arr是アイテムID、スコア

val is_arr = is_list.toArray
var is_arr_len = is_arr.length
if(is_arr_len> max_prefs_per_user){ is_arr_len = max_prefs_per_user }

var i_us_arr = new ArrayBuffer [(String、(String、Double))]
for(i <-0 until is_arr_len){ val itemid = is_arr(i)._ 1 val score = is_arr(i)._ 2 i_us_arr + =((itemid 、(userid、score)))} i_us_arr } .groupByKey()。flatMap {x => val itemid = x._1 val us_list = x._2 val us_arr = us_list.toArray var sum:Double = 0.0 for(i <- 0からus_arr.length){ 合計+ = pow(us_arr(i)._ 2、2)}合計= sqrt(合計)













var u_is_arr = new ArrayBuffer [(String、(String、Double))]
for(i <-0 until us_arr.length){ val userid = us_arr(i)._ 1 val score = us_arr(i)._ 2 / sum u_is_arr + =((userid、(itemid、score)))} u_is_arr } .groupByKey()





//ステップ2.ペア
valpairs_rdd = ui_rdd.flatMap {x =>
val is_arr = x._2.toArray

var ii_s_arr = new ArrayBuffer ((String、String)、Double)
for(i <-0 until is_arr.length-1){ for(j <-i + 1 until is_arr.length){ val item_a = is_arr(i)。 _1 val item_b = is_arr(j)._ 1 val score_a = is_arr(i)._ 2 val score_b = is_arr(j)._ 2




ii_s_arr + =(((item_a、item_b)、score_a * score_b))
ii_s_arr + =(((item_b、item_a)、score_a * score_b))
}
}
ii_s_arr
} .groupByKey()

//ステップ3。合計と出力の
pairs_rdd.map {x =>
val ii_pair = x._1
val s_list = x._2
val s_arr = s_list.toArray
val len = s_arr.length
var score:Double = 0.0

for(i <-0 until len){ score + = s_arr(i)} val item_a = ii_pair._1 val item_b = ii_pair._2 (item_a、(item_b、score))} .groupByKey()。map {x => val item_a = x._1 val rec_list = x。2 val rec_arr = rec_list.toArray.sortWith( ._ 2> _._ 2)








var len = rec_arr.length
取前5
if(len> topn){ len = topn }

val s = new StringBuilder
for(i <-0 until len){ val item = rec_arr(i)._ 1 val score =“%1.3f” format rec_arr(i)._ 2 s.append(item +“:” +スコア.toString)if(i!= len -1){ s.append( "、")} }






item_a +“ \ t” + s
} .saveAsTextFile(output_path)
}
}
3. Pythonの実装(sklearnライブラリを使用)

pdとしてパンダを
インポートnpとしてnumpyを
インポートインポート警告tqdmから
ランダム、数学、OS
をインポートsklearn.model_selection
からtqdmをインポートimport train_test_split
warnings.filterwarnings( 'ignore')

評価指標

レコメンデーションシステムによって推奨された正しい製品の数は、ユーザーが実際にクリックした製品の数を考慮しています。

def Recall(Rec_dict、Val_dict):
'' '
Rec_dict:レコメンデーションアルゴリズムによって返されるレコメンデーションリスト、フォーム:{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
Val_dict:ユーザーが実際にクリックした次の形式の製品のリスト:{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
'' '
hit_items = 0
all_items = 0
for uid、items in Val_dict.items( ):
rel_set = items
rec_set = Rec_dict [uid]
for item in rec_set:
if item in rel_set:
hit_items + = 1
all_items + = len(rel_set)

リターンラウンド(hit_items / all_items * 100、2)

#Recommendationシステムが推奨する製品の数は、ユーザーに実際に推奨される製品の数を示しています。

def Precision(Rec_dict、Val_dict):
'' '
Rec_dict:レコメンデーションアルゴリズムによって返されるレコメンデーションリスト、形式:{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
Val_dict:ユーザーが実際にクリックした次の形式の製品のリスト:{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
'' '
hit_items = 0
all_items = 0
for uid、items in Val_dict.items( ):
rel_set = items
rec_set = Rec_dict [uid]
for item in rec_set:
if item in rel_set:
hit_items + = 1
all_items + = len(rec_set)

リターンラウンド(hit_items / all_items * 100、2)

#すべての推奨ユーザーのうち、推奨製品の数は、これらのユーザーが実際にクリックした製品の数を占めています。

def Coverage(Rec_dict、Trn_dict):
'' '
Rec_dict:レコメンデーションアルゴリズムによって返されるレコメンデーションリスト、フォーム:{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
Trn_dict:トレーニングセットユーザー実際にクリックされたアイテムのリスト。次の形式で表示されます。{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
'' '
rec_items = set()
all_items = set()
for uid in Rec_dict:
Trn_dict [uid]の
アイテムの場合all_items.add(item)
Rec_dict [uid]の
アイテムの場合rec_items.add(item)
return round(len(rec_items)/ len(all_items)* 100、2)

#平均人気度を使用して新規性を測定します。平均人気度が高い(つまり、推奨製品の人気が高い)場合は、推奨新規性が比較的低いことを意味します。

def Popular(Rec_dict、Trn_dict):
'' '
Rec_dict:レコメンデーションアルゴリズムによって返されるレコメンデーションリスト、フォーム:{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
Trn_dict:トレーニングセットユーザー実際にクリックされたアイテムのリスト。形式は次のとおりです。{uid:{item1、item2、…}、uid:{item1、item2、…}、…}
'' '
pop_items = {}
for uid in Trn_dict:
for item in Trn_dict [uid]:
アイテムがpop_itemsにない場合:
pop_items [item] = 0
pop_items [item] + = 1

pop、num = 0、0
Rec_dictのuidの場合:
Rec_dict [uid]のアイテムの場合:
pop + = math.log(pop_items [item] + 1)#アイテムの人気分布はロングテール分布を満たし、対数は次のようになります。平均値はより安定しています
num + = 1
return round(pop / num、3)

#複数の評価インデックス関数を一緒に呼び出す

def rec_eval(val_rec_items、val_user_items、trn_user_items):
print( 'recall:'、Recall(val_rec_items、val_user_items))
print( 'precision'、Precision(val_rec_items、val_user_items))
print( 'coverage'、Coverage(val
print( 'Popularity'、Popularity(val_rec_items、trn_user_items))

def get_data(root_path):

#データの読み取り

rnames = ['user_id'、 'movie_id'、 'rating'、 'timestamp']
Ratings = pd.read_csv(os.path.join(root_path、 'ratings.dat')、sep = '::'、engine = ' python '、names = rnames)

#Splitトレーニングと検証セット

trn_data、val_data、_、_ = train_test_split(ratings、ratings、test_size = 0.2)

trn_data = trn_data.groupby( 'user_id')['movie_id']。apply(list).reset_index()
val_data = val_data.groupby( 'user_id')['movie_id']。apply(list).reset_index()

trn_user_items = {}
val_user_items = {}

#配列を辞書の形式に構築します{user_id:[item_id1、item_id2、…、item_idn]}

ユーザーの場合、zip内の映画(*(list(trn_data ['user_id'])、list(trn_data ['movie_id']))):
trn_user_items [user] = set(movies)

ユーザーの場合、zip内の映画(*(list(val_data ['user_id'])、list(val_data ['movie_id']))):
val_user_items [user] = set(movies)

trn_user_items、val_user_itemsを返します

def User_CF_Rec(trn_user_items、val_user_items、K、N):
'' '
trn_user_items:トレーニングデータを表し、形式は次のとおりです:{user_id1:[item_id1、item_id2、…、item_idn]、user_id2…}
val_user_items:検証データを表します。形式は次のとおりです。{user_id1:[item_id1、item_id2、…、item_idn]、user_id2…}
K:Kは類似ユーザーの数を表し、各ユーザーは最も類似したKユーザーを選択します
。N:Nは推奨される製品の数を表します。ユーザー、各ユーザーと
類似性が最も高いN個の製品を推奨します'' '

#item-> users反転テーブルを確立します。反転テーブルの形式は次のとおりです。{item_id1:{user_id1、user_id2、…、user_idn}、item_id2:…}つまり、各アイテムは、ユーザーがクリックしたものに対応します。

#反転テーブルを確立する目的は、ユーザーとやり取りする製品の数をより正確にカウントすることです

print( '反転リストを作成...')
item_users =()
for uid、items in tqdm(trn_user_items.items()):#各ユーザーのデータをトラバースします。これには、items
のアイテムのすべてのインタラクティブアイテムが含まれます:#トラバース
item_usersにアイテムがない場合は、ユーザーのすべてのアイテムと、これらのアイテムに対応するユーザーリストに対応するuidを追加します
。item_users[item] = set()
item_users [item] .add(uid)

#算ユーザー協調フィルタリングマトリックス
#つまり、item-users反転テーブルを使用してユーザー間でやり取りされた製品の数をカウントすると、ユーザー協調フィルタリングマトリックスの表現は次のようになります。sim= {user_id1:{user_id2:num1}、user_id3: {user_id4:num2}、…}
#協調フィルタリングマトリックスは、ユーザーが相互作用する製品の数を示すために使用される2層の辞書です。
#ユーザーの協調フィルタリングマトリックスを計算するときは、各ユーザーが操作する製品の数、その表現For:num = {user_id1:num1、user_id2:num2、…}
sim = {}
num = {}
print( '協調フィルタリングマトリックスの構築...')
for item、users in tqdm(item_users.items()):#すべてのアイテムを統計にトラバースします。ユーザー内の
uのユーザーのアイテム番号間の2つの一般的な相互作用
IF u not in num:#ユーザーが辞書にない場合num u inディクショナリで0に初期化するように進めます。そうしないと、操作が元に戻ります。キーエラーの報告
num [u] = 0
num [u] + = 1#
uがsimにない場合、各ユーザーが操作したアイテムの総数をカウントします。ユーザーuが辞書simにない場合は、事前に辞書に入れてください。新しい辞書に初期化してください。そうしないと、後続の操作で、ユーザーのvに対してキーエラー
sim [u] = {}が報告されます。ifu != v: #ユーザー間の類似性は、vがsim [u]にない場合、uがvと等しくない場合にのみ計算されます



sim [u] [v] = 0
sim [u] [v] + = 1

#算数ユーザー類似性マトリックス#
ユーザー協調フィルタリングマトリックスは、実際にはコサイン類似性の分子部分と同等であり、分母、つまり2人のユーザーが対話するアイテムの数の積で除算する必要がありますお互い
2人のユーザーが相互作用するアイテムの数の積は次のとおりです。uの上記のnum辞書
print( '類似度の計算...')
、tqdm(sim.items())のユーザー:
vの場合、スコアin users.items():
sim [u] [v] = score / math .sqrt(num [u] * num [v])#コサイン類似度分母部分

#各ユーザーの検証データをtopNに推奨#ユーザーを推奨する
前に、類似性マトリックスを通じて現在のユーザーに最も好色な上位K人のユーザーを取得する必要があります。#次に
、現在のK人のユーザーインタラクション積を除算します。最終的な類似性スコアを計算します。テストユーザートレーニングセットで相互作用した製品以外の製品の場合。
#最終的に推奨される候補製品の類似性スコアは、複数のユーザーによる製品スコアの累積であり、
print( 'テストユーザーに推奨...' )
items_rank = {}
Uため、_ tqdmに(val_user_items.items()):#トラバーステストセットのユーザおよびテストセットの各ユーザを推薦
ユーザの辞書を[U] = {}#初期Uの候補項目items_rank
ためにv、sorted(sim [u] .items()、key = lambda x:x [1]、reverse = True)[:K]の
スコア:#trn_user_items [vのアイテムに対してユーザーuを最も愛するk人のユーザーを選択します]:#
アイテムがtrn_user_items [u]にない場合、類似ユーザーがインタラクションした製品をトラバースします:#類似ユーザーがインタラクションした製品で、テストユーザーがトレーニングセットに表示されている場合、推奨する必要はありません。
アイテムがitems_rank [u]にない場合はスキップします
。items_rank[u] [item] = 0#ユーザーuのアイテム0への類似性スコアを初期化します
items_rank [u] [item] + = score#すべてのスコアを累積します同じアイテムの類似ユーザー

print( '各ユーザーの類似度スコアが最も高いN個のアイテムを
選択...')items_rank = {k:sorted(v.items()、key = lambda x:x [1]、reverse = True)[:N ] for k、v in items_rank.items()}
items_rank = {k:set([x [0] for x in v])for k、v in items_rank.items()}#出力を適切な形式に統合し、出力

items_rankを返す

if name ==“ main ”:
root_path = '。/ data /
ml -1m /' trn_user_items、val_user_items = get_data(root_path)
rec_items = User_CF_Rec(trn_user_items、val_user_items、
80、10 rec_eval(rec_items、val_user_items、

おすすめ

転載: blog.csdn.net/qq_36816848/article/details/114013653