#author("2021-11-10T07:46:59+00:00","","") #author("2021-11-10T07:47:51+00:00","","") [[メモ]] #CONTENTS *ユーザーベース協調フィルタリング(UBCF)とは [#ya3eb525] **普通のUBCF [#zc098f66] ユーザーベース協調フィルタリングの流れとしてはこうです。~ ①ユーザーのアイテムに対する評価値をもとに、ユーザー同士の類似度を求める。~ ②類似度の高いユーザーを何名か抽出。~ ③対象ユーザの未評価アイテムについて②のユーザーの評価値から予測評価値を算出し、予測評価値の高いアイテムを対象ユーザーに推薦。~ ~ つまりは「ユーザーAに似た人ならユーザーAが好むものを好むであろう。」 という考えからユーザー同士が協調しあっているということでユーザーベース協調フィルタリングと呼ばれています。 **教学データにおけるUBCF [#le2a5f4d] 普通のUBCFは購買履歴からユーザーの類似度を求めて,それから対象ユーザーがまだ購買していない商品について予測評価値を出すというものです.~ ~ しかし,今回は教学データに対するUBCFということで,対象となるデータが学生の成績データになります. #ref(ss11.png) 例えば上記のようなデータがあったとしたら,まず対象となる学生Xとその他の学生の類似度を計算します.~ ~ この中で学生Xと類似度が高いのは学生Aになります.~ ~ そして,学生Aの理科の成績を見てみるとSを取得しています.学生Aと成績が類似している学生Xならば理科でいい成績をとれるのでは?と言う考えで学生Xに対して理科をおすすめします.~ ~ 以上が教学データのUBCFの考え方です. *実装 [#e4ca860d] **環境 [#b5f68ba8] ・Windows10~ ・Python 3.8.7 **データセット [#vb879ad8] [[デモデータの作成]]で作った学生データを使います. #ref(2017_02_kai.csv) #ref(2018_02_kai.csv) #ref(2019_02_kai.csv) 卒業済み想定の学生データ200人,在学中想定の学生データ100人の学生データです. import numpy as np import pandas as pd data2017 = pd.read_csv("C:/Users/takky/富山県立大学/研究室/卒業研究/RecommendSystem/New Demodata/2018_02_kai.csv",encoding = "cp932").drop([0,1,2]) data2018 = pd.read_csv("C:/Users/takky/富山県立大学/研究室/卒業研究/RecommendSystem/New Demodata/2017_02_kai.csv",encoding = "cp932").drop([0,1,2]) data2019 = pd.read_csv("C:/Users/takky/富山県立大学/研究室/卒業研究/RecommendSystem/New Demodata/2019_02_kai.csv",encoding = "cp932").drop([0,1,2]) data_kako = pd.concat([data2018,data2017],axis = 0) print('学籍番号を入力してください') StudentNumber = input('入力>>>') #学籍番号として指定された成績データをとってくる data_ima = pd.DataFrame(data2019.iloc[int(StudentNumber)-1915001]) data_ima_T = data_ima.T #結合 data_gutya = pd.concat([data_ima_T,data_kako],axis = 0)#学籍番号付きのデータ data_all = data_gutya.reset_index(drop=True).drop('学籍番号',axis = 1).fillna(-1)#学籍番号とってnanを-1埋めしたデータ #numpyに data_all_np = data_all.values 学籍番号として入力された番号の学生データを取得して過去の学生のデータと一つにします.~ ~ **類似度計算 [#i96349af] 類似度計算はピアソン相関係数で求めます.類似度結果は-1~1の間で出力され,1に近いほど類似度が高くなります. #Person関数で指定した学生とすべての学生の類似度を算出 def get_correlation_coefficents(data_all_np, target_user_index): similarities = [] target = data_all_np[target_user_index] for i, score in enumerate(data_all_np): # 共通の評価が少ない場合は除外 indices = np.where(((target + 1) * (score + 1)) != 0)[0] if len(indices) < 3 or i == target_user_index: continue similarity = np.corrcoef(target[indices], score[indices])[0, 1] if np.isnan(similarity): continue similarities.append((i, similarity)) return sorted(similarities, key=lambda s: s[1], reverse=True) target_user_index = 0 # 0番目のユーザ similarities = get_correlation_coefficents(data_all_np, target_user_index) #0番目の学生と他の学生の類似度.(学生の行番号,類似度).1に近いほど類似度が高い print('Similarities: {}'.format(similarities)) **予測 [#xbe2d7dc] 予測評価値の算出を行います.今回の場合予測評価値は0~4の間で計算されます.予測評価値は,類似度からの加重平均で求めます. #予測評価値を求める def predict(data_all_np, similarities, target_user_index, target_item_index): target = data_all_np[target_user_index] avg_target = np.mean(target[np.where(target >= 0)]) numerator = 0.0 denominator = 0.0 k = 0 for similarity in similarities: # 類似度の上位10人の評価値を使う if k > 10 or similarity[1] <= 0.0: break score = data_all_np[similarity[0]] if score[target_item_index] >= 0: denominator += similarity[1] numerator += similarity[1] * (score[target_item_index] - np.mean(score[np.where(score >= 0)])) k += 1 return avg_target + (numerator / denominator) if denominator > 0 else -1 #target_item_index = 25 print('Predict score: {:.3f}'.format(predict(data_all_np, similarities, target_user_index, target_item_index))) **ランキング [#l706387e] 予測評価値を元にランク付けします. #予測評価値をもとにランキング def rank_items(data_all_np, similarities, target_user_index): rankings = [] target = data_all_np[target_user_index] for i in range(127): # 既に取得済みの科目はスキップ if target[i] >= 0: continue rankings.append((i, predict(data_all_np, similarities, target_user_index, i))) return sorted(rankings, key=lambda r: r[1], reverse=True) target_user_index = 0 # 0番目のユーザ rank = rank_items(data_all_np, similarities, target_user_index)#予測評価値が高い科目のindex番号とその予測評価値 #print('Ranking: {}'.format(rank)) rank_df = pd.DataFrame(rank,columns=['index','predict']) for i in range(len(rank_df.index)): rank_df = rank_df.replace({'index':{rank_df.iloc[i,0]:data_all.columns[rank_df.iloc[i,0]]}}) print(rank_df) #ref(ss1.png) ランキングによりプログラミング演習2を推薦するのが良いとわかりました. *まとめ [#l835aeda] #ref(UBCF.py) 上記の説明をまとめたコードです.デモデータと同じディレクトリに入れれば動きます.~ 上記の説明をまとめたコードです.デモデータと同じディレクトリに入て python UBCF.py で動きます~ ~ 学籍番号は1915001~1915100までの範囲で入力してください🙏