推奨システム1)推奨システムの概要、コラボレーションフィルタリング


推奨システムとは?


ユーザの過去の行動データまたはその他のデータに基づいて、ユーザに必要な情報または製品を提供するシステム.
従来のビジネス推奨
:お客様を興味の近いグループ(マーケティングの細分化市場)、各グループに適した製品、サービス推薦に分ける
  • ビッグデータ、推奨アルゴリズムの発展
    グループのサイズを縮小し、グループのサイズを最小にすることができます.各グループ->一人
    ユーザーごとにカスタマイズされた推奨およびサービスを提供する->カスタマイズされた推奨システム
  • 1)連携フィルタリング


    購入・消費製品の各消費者に対する評価により,評価モデルが類似した消費者を集約する.
    消費者の興味を利用した技術
    Ex)Aの消費者や製品評価モデルに似ている人を選び,これらの人が共通に好む製品の中からAがまだ触れていない製品を選び,提案する技術.
    人々の好みを明確に区別する製品(映画、音楽、ファッション)などの推薦には高い精度がある
    限界:消費者の評価情報を入手するのは難しい
    消費者に製品を購入した後、評価情報の提供を要求すると、提供が困難になる.
    これらの制限を克服するために間接情報を使用する
    買い物かごの中の製品などのオンラインショッピング中のクリックフロー(Clickstream)を収集、分析することで、消費者の好みや好みを理解し、ex)アマゾン製品推薦、Netflix映画推薦システム

    2)コンテンツベースのフィルタリング


    製品の内容を分析し、推奨するテクノロジー
    消費者が消費する製品の中でテキスト情報の多い製品(ex)ニュース、書籍などを分析し、推薦する際によく使う
    テキスト中の形態素を抽出する->肝心なキーワードを抽出した後の消費者への興味の分析

    3)知識ベースのフィルタリング(知識ベースのフィルタリング)


    コラボレーションフィルタリング、コンテンツベースフィルタリングの共通の欠点:完全な画像がない
    つまり、どの消費者がどの製品が好きなのかを分析することができますが、「なぜどの製品が好きなのか」ということです.についての答え
    特定の分野(domain)の専門家の助けの下で、その分野の全体的な知識構造を作成し、利用する方法
    全体的な知識構造の多様な表現
    通常、ドメイン内の重要な概念に基づいてアーキテクチャ図(ontology)を作成します.
    このアーキテクチャ図に基づいて、購入した興味のある製品に関連する製品を推奨する場合は、このアーキテクチャ図を参照してください.

    4)深さ学習推奨技術


    異なるユーザとプロジェクトのフィーチャー値(feature)を使用し、得られた出力を各ユーザの各プロジェクトに対する予想されるプリファレンスとして使用する->各ユーザに対して複数のプロジェクトの予想されるプリファレンスを計算する->推奨されるプリファレンスの高い製品
    利点:複数の入力変数を使用可能
    Butは,連続値(ex)1~5と表示される項目の好みをユーザが深く学習する場合,他のアルゴリズムよりも精度が高くない.

    5)混合(Hybrid)


    以上の2つのアルゴリズムを組み合わせた形状
    各アルゴリズムには明らかな利点と欠点があるため,それらを適切に結合すると良好な効果が得られ,それらをどのように結合するかが重要な解決策である.

    1)連携フィルタリング


    2)コンテンツベースのフィルタリング
    3)知識ベースのフィルタリング(知識ベースのフィルタリング)
    4)深さ学習推奨技術
    5)混合(Hybrid)
  • 典型的なユーザベースのフィルタ推奨アルゴリズムコラボレーションフィルタ
  • コラボレーションフィルタとは?
    似たような人(隣人)の集団が存在すると仮定する
    この組織の人々が共に好む製品とサービスを推薦する.

    コラボレーションアルゴリズムの順序


    1)すべてのユーザ間の評価類似度の計算(適切な類似度評価式を使用)
    # train set의 모든 가능한 사용자 pair의 Cosine similarities 계산
    from sklearn.metrics.pairwise import cosine_similarity
    matrix_dummy = rating_matrix.copy().fillna(0)
    
    user_similarity = cosine_similarity(matrix_dummy, matrix_dummy)
    user_similarity = pd.DataFrame(user_similarity, index=rating_matrix.index, columns=rating_matrix.index)
    
    2)現在の推奨オブジェクトと他のユーザとの類似度の抽出
    def CF_simple(user_id, movie_id):
        if movie_id in rating_matrix:
            # 현재 사용자와 다른 사용자 간의 similarity 가져오기
            sim_scores = user_similarity[user_id].copy()
            # 현재 영화에 대한 모든 사용자의 rating값 가져오기
            movie_ratings = rating_matrix[movie_id].copy()
            # 현재 영화를 평가하지 않은 사용자의 index 가져오기
            none_rating_idx = movie_ratings[movie_ratings.isnull()].index
            # 현재 영화를 평가하지 않은 사용자의 rating (null) 제거
            movie_ratings = movie_ratings.dropna()
            # 현재 영화를 평가하지 않은 사용자의 similarity값 제거
            sim_scores = sim_scores.drop(none_rating_idx)
            # 현재 영화를 평가한 모든 사용자의 가중평균값 구하기
            mean_rating = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
        else:
            mean_rating = 3.0
        #print(movie_ratings)
        return mean_rating
        
    
    3)現在のユーザが評価していないすべての項目について、現在のユーザの推定評価値を導出する.
    ->現在のユーザーとの類似性に基づいて、他のユーザーの評価を加重平均する
    # 전체 데이터로 full matrix와 cosine similarity 구하기 
    rating_matrix = ratings.pivot_table(values='rating', index='user_id', columns='movie_id')
    from sklearn.metrics.pairwise import cosine_similarity
    matrix_dummy = rating_matrix.copy().fillna(0)
    user_similarity = cosine_similarity(matrix_dummy, matrix_dummy)
    user_similarity = pd.DataFrame(user_similarity, index=rating_matrix.index, columns=rating_matrix.index)
    4)推奨品のうち推定評価値が最も高いN個
    def recom_movie(user_id, n_items, neighbor_size=30):
        # 현 사용자가 평가한 영화 가져오기
        user_movie = rating_matrix.loc[user_id].copy()
        for movie in rating_matrix:
            # 현 사용자가 이미 평가한 영화는 제외 (평점을 0으로)        
            if pd.notnull(user_movie.loc[movie]):
                user_movie.loc[movie] = 0
            # 현 사용자가 평가하지 않은 영화의 예상 평점 계산
            else:
                user_movie.loc[movie] = cf_knn(user_id, movie, neighbor_size)
        # 영화를 예상 평점에 따라 정렬해서 제목을 뽑아서 돌려 줌
        movie_sort = user_movie.sort_values(ascending=False)[:n_items]
        recom_movies = movies.loc[movie_sort.index]
        recommendations = recom_movies['title']
        return recommendations
        
    recom_movie(user_id=2, n_items=5, neighbor_size=30)

    隣人のCFを考えると


    二つの注意事項
  • Neighborクラスタサイズ
  • Neighbor選考基準
    1) K Nearest Neighbor(KNN)
    2)Thresholding(類似度基準に適合するユーザを隣接者として選択)
  • # Neighbor size를 정해서 예측치를 계산하는 함수 
    def cf_knn(user_id, movie_id, neighbor_size=0):
        if movie_id in rating_matrix:
            # 현재 사용자와 다른 사용자 간의 similarity 가져오기
            sim_scores = user_similarity[user_id].copy()
            # 현재 영화에 대한 모든 사용자의 rating값 가져오기
            movie_ratings = rating_matrix[movie_id].copy()
            # 현재 영화를 평가하지 않은 사용자의 index 가져오기
            none_rating_idx = movie_ratings[movie_ratings.isnull()].index
            # 현재 영화를 평가하지 않은 사용자의 rating (null) 제거
            movie_ratings = movie_ratings.drop(none_rating_idx)
            # 현재 영화를 평가하지 않은 사용자의 similarity값 제거
            sim_scores = sim_scores.drop(none_rating_idx)
            
    ##### (2) Neighbor size가 지정되지 않은 경우        
            if neighbor_size == 0:          
                # 현재 영화를 평가한 모든 사용자의 가중평균값 구하기
                mean_rating = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
    ##### (3) Neighbor size가 지정된 경우
            else:                       
                # 해당 영화를 평가한 사용자가 최소 2명이 되는 경우에만 계산
                if len(sim_scores) > 1: 
                    # 지정된 neighbor size 값과 해당 영화를 평가한 총사용자 수 중 작은 것으로 결정
                    neighbor_size = min(neighbor_size, len(sim_scores))
                    # array로 바꾸기 (argsort를 사용하기 위함)
                    sim_scores = np.array(sim_scores)
                    movie_ratings = np.array(movie_ratings)
                    # 유사도를 순서대로 정렬
                    user_idx = np.argsort(sim_scores)
                    # 유사도를 neighbor size만큼 받기
                    sim_scores = sim_scores[user_idx][-neighbor_size:]
                    # 영화 rating을 neighbor size만큼 받기
                    movie_ratings = movie_ratings[user_idx][-neighbor_size:]
                    # 최종 예측값 계산 
                    mean_rating = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
                else:
                    mean_rating = 3.0
        else:
            mean_rating = 3.0
        return mean_rating

    評価傾向を考慮したCF



    2人のプレイヤーの映画採点ベクトル(5,5,5),(1,1)のコサイン類似度を算出すると,1
    プレイヤーの映画に対する評価は明確であるが,このような類似度では各プレイヤーの個人評価傾向を反映できないという欠点がある.
    ピルソン類似度(Pearson Simility)を用いてこれを補完する
    あるユーザのスコア基準が非常に低いか高すぎると、類似度に大きく影響するため、相関係数を使用してこのような状況の発生を阻止する.

    各ユーザの平均値を求め、その値を減算し、コサイン類似度を計算します.
    # train 데이터의 user의 rating 평균과 영화의 평점편차 계산 
    rating_mean = rating_matrix.mean(axis=1)
    rating_bias = (rating_matrix.T - rating_mean).T
    
    def CF_knn_bias(user_id, movie_id, neighbor_size=0):
        if movie_id in rating_bias:
            # 현 user와 다른 사용자 간의 유사도 가져오기
            sim_scores = user_similarity[user_id].copy()
            # 현 movie의 평점편차 가져오기
            movie_ratings = rating_bias[movie_id].copy()
            # 현 movie에 대한 rating이 없는 사용자 삭제
            none_rating_idx = movie_ratings[movie_ratings.isnull()].index
            movie_ratings = movie_ratings.drop(none_rating_idx)
            sim_scores = sim_scores.drop(none_rating_idx)
    ##### (2) Neighbor size가 지정되지 않은 경우        
            if neighbor_size == 0:
                # 편차로 예측값(편차 예측값) 계산
                prediction = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
                # 편차 예측값에 현 사용자의 평균 더하기
                prediction = prediction + rating_mean[user_id]
    ##### (3) Neighbor size가 지정된 경우            
            else:
                # 해당 영화를 평가한 사용자가 최소 2명이 되는 경우에만 계산            
                if len(sim_scores) > 1:
                    # 지정된 neighbor size 값과 해당 영화를 평가한 총사용자 수 중 작은 것으로 결정
                    neighbor_size = min(neighbor_size, len(sim_scores))
                    # array로 바꾸기 (argsort를 사용하기 위함)
                    sim_scores = np.array(sim_scores)
                    movie_ratings = np.array(movie_ratings)
                    # 유사도를 순서대로 정렬
                    user_idx = np.argsort(sim_scores)
                    # 유사도와 rating을 neighbor size만큼 받기
                    sim_scores = sim_scores[user_idx][-neighbor_size:]
                    movie_ratings = movie_ratings[user_idx][-neighbor_size:]
                    # 편차로 예측치 계산
                    prediction = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
                    # 예측값에 현 사용자의 평균 더하기
                    prediction = prediction + rating_mean[user_id]
                else:
                    prediction = rating_mean[user_id]
        else:
            prediction = rating_mean[user_id]
        return prediction

    類似度測定関数


    1) Euclidean distance



    2) Cosine distance



    Euclidean distanceとCosine distanceの違い



    Ex)本A:ゲーム、アクション各1語、2語、本B:ゲーム、アクション各1000語、2000語
    距離->(1,1)(2000,000)に基づく大きな違い->類似度が低い?
    角度基準->傾斜が同じで方向が同じなので類似度が高い

    3) Tanimoto coefficient



    データにバイナリ値がある場合に使用できます(特定の単語、フィーチャーが含まれているかどうか、アイテムを購入しているかどうかなど)
    simil(x,y) = c/a + b – c
    a:ユーザxが1を有する(購入またはクリック)物品の数
    b:ユーザyが1値(購入またはクリック)を有する物品の数
    c:ユーザx,yの合計1値の項目数

    4) Jaccard’s distance



    タニモト係数と提花係数の違いは?

    5)相関係数(相関係数)


  • の空分散を標準偏差に分ける、正規化-1~1の値で線形関係
  • を判断する.
    相関係数は分かりやすい類似性測定値であるが,連携フィルタリングに用いるとよい結果をもたらすことはできない.
    潜在変数(lurking variable):相関性が高いことは、2つの変数間の関連性が高いことを意味し、因果関係を意味しない->したがって、それらを正しく理解し、適用するために、この分野の専門的な解釈が必要である.
    2つのユーザーが重複するアイテムの数を考慮しない
    1)2人のユーザのアイテム嗜好のうち1つだけが重なる場合,計算方式をどのように定義するかわからないため,相関計算X
    2)好み値のすべての列が一致しても判断できない