ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Recommendation] 유사도와 KNN을 활용한 예측값 계산 및 추천 목록 생성
    ML/Recommendation 2020. 3. 6. 18:46

     

     

     

     

    유사도를 구하는 것까지 구현을 해봤으니, 이제 추천 목록을 생성해보자!

     

     

     

    유사도와 KNN을 활용한 예측값 계산 및 추천 목록 생성 기법


    - 사용자들 간의 유사도를 이용하여 모든 아이템에 대한 예측 평점을 계산하고, 높은 값을 갖는 상위 N개의 추천 목록 생성

     

     

    - Nearest Neighbors(KNN) 가중치 예측 기법

    • 사용자(또는 아이템)와 유사도가 큰 k개의 사용자(또는 아이템) 벡터를 사용해 가중 평균을 구해서 가중치를 예측

     

     

     

     

    KNN Basic


    평점들을 단순히 가중 평균Nk는 유사도가 큰 벡터 상위 k개의 집합

     

     

     

    • Python 구현

     

     

     

     

    ratings_expand = {
        '마동석': {
            '택시운전사': 3.5,
            '남한산성': 1.5,
            '킹스맨:골든서클': 3.0,
            '범죄도시': 3.5,
            '아이 캔 스피크': 2.5,
            '꾼': 3.0,
        },
        '이정재': {
            '택시운전사': 5.0,
            '남한산성': 4.5,
            '킹스맨:골든서클': 0.5,
            '범죄도시': 1.5,
            '아이 캔 스피크': 4.5,
            '꾼': 5.0,
        },
        '윤계상': {
            '택시운전사': 3.0,
            '남한산성': 2.5,
            '킹스맨:골든서클': 1.5,
            '범죄도시': 3.0,
            '꾼': 3.0,
            '아이 캔 스피크': 3.5,
        },
        '설경구': {
            '택시운전사': 2.5,
            '남한산성': 3.0,
            '범죄도시': 4.5,
            '꾼': 4.0,
        },
        '최홍만': {
            '남한산성': 4.5,
            '킹스맨:골든서클': 3.0,
            '꾼': 4.5,
            '범죄도시': 3.0,
            '아이 캔 스피크': 2.5,
        },
        '홍수환': {
            '택시운전사': 3.0,
            '남한산성': 4.0,
            '킹스맨:골든서클': 1.0,
            '범죄도시': 3.0,
            '꾼': 3.5,
            '아이 캔 스피크': 2.0,
        },
        '나원탁': {
            '택시운전사': 3.0,
            '남한산성': 4.0,
            '꾼': 3.0,
            '범죄도시': 5.0,
            '아이 캔 스피크': 3.5,
        },
        '소이현': {
            '남한산성': 4.5, 
            '아이 캔 스피크': 1.0,
            '범죄도시': 4.0
        }
    }
    def get_KNN_recommend(data, name, n=3, sim_function=sim_pearson):
        
        result = top_match(data, name, n, sim_function)
        
        score_dic = dict()
        sim_dic = dict()
        li = []
        
        for sim, user in result:
            print(sim, user)
            if sim<0: continue
            for title in data[user]:
                if title not in data[name]:
                    score = sim * data[user][title]
                    score_dic.setdefault(title, 0)
                    score_dic[title] += score
                    
                    sim_dic.setdefault(title, 0)
                    sim_dic[title] += sim
                    
        for title in score_dic:
            score_dic[title] /= sim_dic[title]
            li.append((score_dic[title], title)) # (예측평점, 영화제목)
            
        li.sort(reverse=True)
        
        print('\n** Recommendation')
        for rating, score in enumerate(li):
            print(rating+1, '등: ', score[1], ', ', score[0], '점')
        
        return li
    get_KNN_recommend(ratings_expand, '소이현')
    Out:
    ...

    ** Recommendation
    1 등: 꾼 , 3.6903300787431923 점
    2 등: 택시운전사 , 3.0 점
    3 등: 킹스맨:골든서클 , 1.9168062051113846 점

     

     

     

     

    KNN with Means


    평점들을 평균값 기준으로 가중 평균

     

     

    • Python 구현
    sum = 0
    count = 0
    
    for name in ratings_expand:
        for title in ratings_expand[name]:
            sum += ratings_expand[name][title]
            count += 1
        
        ratings_expand[name]['avg'] = sum/count
        
    ratings_expand
    Out:
    {'마동석': {'택시운전사': 3.5,
                    '남한산성': 1.5,
                    '킹스맨:골든서클': 3.0,
                    '범죄도시': 3.5,
                    '아이 캔 스피크': 2.5,
                    '꾼': 3.0,
                    'avg': 2.8333333333333335},
    '이정재': {'택시운전사': 5.0,
                   '남한산성': 4.5,
                   '킹스맨:골든서클': 0.5,
                   '범죄도시': 1.5,
                   '아이 캔 스피크': 4.5,
                   '꾼': 5.0,
                   'avg': 3.1666666666666665},
    '윤계상': {'택시운전사': 3.0,
                   '남한산성': 2.5,
                   '킹스맨:골든서클': 1.5,
                   '범죄도시': 3.0,
                   '꾼': 3.0,
                   '아이 캔 스피크': 3.5,
                   'avg': 3.0277777777777777},
    '설경구': {'택시운전사': 2.5,
                   '남한산성': 3.0,
                   '범죄도시': 4.5,
                   '꾼': 4.0,
                   'avg': 3.1136363636363638},
    '최홍만': {'남한산성': 4.5,
                   '킹스맨:골든서클': 3.0,
                   '꾼': 4.5,
                   '범죄도시': 3.0,
                   '아이 캔 스피크': 2.5,
                   'avg': 3.185185185185185},
    '홍수환': {'택시운전사': 3.0,
                   '남한산성': 4.0,
                   '킹스맨:골든서클': 1.0,
                   '범죄도시': 3.0,
                   '꾼': 3.5,
                   '아이 캔 스피크': 2.0,
                   'avg': 3.106060606060606},
    '나원탁': {'택시운전사': 3.0,
                   '남한산성': 4.0,
                   '꾼': 3.0,
                   '범죄도시': 5.0,
                   '아이 캔 스피크': 3.5,
                   'avg': 3.1842105263157894},
    '소이현': {'남한산성': 4.5,
                   '아이 캔 스피크': 1.0,
                   '범죄도시': 4.0,
                   'avg': 3.182926829268293}}
    def get_KNNmeans_recommend(data, name, n=3, sim_function=sim_pearson):
        
        result = top_match(data, name, n, sim_function)
        
        score_dic = dict()
        sim_dic = dict()
        li = []
        
        for sim, user in result:
            print(sim, user)
            if sim<0: continue
            for title in data[user]:
                if title not in data[name]:
                    score = sim * (data[user][title]-data[user]['avg'])
                    score_dic.setdefault(title, 0)
                    score_dic[title] += score
                    
                    sim_dic.setdefault(title, 0)
                    sim_dic[title] += sim
                    
        for title in score_dic:
            score_dic[title] = data[name]['avg']+(score_dic[title]/sim_dic[title])
            li.append((score_dic[title], title)) # (예측평점, 영화제목)
            
        li.sort(reverse=True)
        
        print('\n** Recommendation')
        for rating, score in enumerate(li):
            print(rating+1, '등: ', score[1], ', ', score[0], '점')
        
        return li
    get_KNNmeans_recommend(ratings_expand, '소이현')
    Out:
    ...

    ** Recommendation
    1 등: 꾼 , 3.765320026911711 점
    2 등: 택시운전사 , 3.0487901210241017 점
    3 등: 킹스맨:골든서클 , 1.9561449029750133 점

     

     

     

     

     

     

     

     

    reference: https://www.fun-coding.org/recommend_basic2.html

    댓글

dokylee's Tech Blog