github.com/abalabdev/axlcoin@v0.0.0-20191212060057-b2e55795b172/Dapps/python/recommendations.py (about) 1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 from math import sqrt 4 #영화 비평과 영화 평가 정보를 담는 딕셔너리 5 critics = { 6 'Lisa Rose': { 7 'Lady in the Water': 2.5, 8 'Snakes on a Plane': 3.5, 9 'Just My Luck': 3.0, 10 'Superman Returns': 3.5, 11 'You, Me and Dupree': 2.5, 12 'The Night Listener': 3.0, 13 }, 14 'Gene Seymour': { 15 'Lady in the Water': 3.0, 16 'Snakes on a Plane': 3.5, 17 'Just My Luck': 1.5, 18 'Superman Returns': 5.0, 19 'The Night Listener': 3.0, 20 'You, Me and Dupree': 3.5, 21 }, 22 'Michael Phillips': { 23 'Lady in the Water': 2.5, 24 'Snakes on a Plane': 3.0, 25 'Superman Returns': 3.5, 26 'The Night Listener': 4.0, 27 }, 28 'Claudia Puig': { 29 'Snakes on a Plane': 3.5, 30 'Just My Luck': 3.0, 31 'The Night Listener': 4.5, 32 'Superman Returns': 4.0, 33 'You, Me and Dupree': 2.5, 34 }, 35 'Mick LaSalle': { 36 'Lady in the Water': 3.0, 37 'Snakes on a Plane': 4.0, 38 'Just My Luck': 2.0, 39 'Superman Returns': 3.0, 40 'The Night Listener': 3.0, 41 'You, Me and Dupree': 2.0, 42 }, 43 'Jack Matthews': { 44 'Lady in the Water': 3.0, 45 'Snakes on a Plane': 4.0, 46 'The Night Listener': 3.0, 47 'Superman Returns': 5.0, 48 'You, Me and Dupree': 3.5, 49 }, 50 'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 51 'Superman Returns': 4.0}, 52 } 53 54 55 def sim_distance(prefs, p1, p2): 56 57 # person1과 person2의 거리 기반 유사도 점수리턴 58 59 60 #공통 항목 목록 추출 61 si = {} 62 for item in prefs[p1]: 63 if item in prefs[p2]: 64 si[item] = 1 65 #공통 평가 항목이없는 경우 0 리턴 66 if len(si) == 0: 67 return 0 68 #모든 값의 제곱을 더함 69 sum_of_squares = sum([pow(prefs[p1][item] - prefs[p2][item], 2) for item in 70 prefs[p1] if item in prefs[p2]]) 71 return 1 / (1 + sqrt(sum_of_squares)) 72 73 74 def sim_pearson(prefs, p1, p2): 75 76 #p1과p2에 대한 피어슨 상관계수를 리턴 77 78 79 #같이 평가한 항목들의 목록을 구함 80 si = {} 81 for item in prefs[p1]: 82 if item in prefs[p2]: 83 si[item] = 1 84 #공통 요소가 없으면 0을리턴 85 if len(si) == 0: 86 return 0 87 #요소들의 개수를 구함 88 n = len(si) 89 #모든 선호도를 합산 90 sum1 = sum([prefs[p1][it] for it in si]) 91 sum2 = sum([prefs[p2][it] for it in si]) 92 #제곱의 합을계산 93 sum1Sq = sum([pow(prefs[p1][it], 2) for it in si]) 94 sum2Sq = sum([pow(prefs[p2][it], 2) for it in si]) 95 #곱의 합을계산 96 pSum = sum([prefs[p1][it] * prefs[p2][it] for it in si]) 97 #피어슨 점수 계산 98 num = pSum - sum1 * sum2 / n 99 den = sqrt((sum1Sq - pow(sum1, 2) / n) * (sum2Sq - pow(sum2, 2) / n)) 100 if den == 0: 101 return 0 102 r = num / den 103 return r 104 105 def top_matches(prefs, person, n=5, similarity=sim_pearson): 106 scores = [(similarity(prefs, person, other), other) for other in prefs if other != person] 107 108 scores.sort() 109 scores.reverse() 110 111 return scores[0:n] 112 113 114 def get_recommataions(prefs, person, similarity=sim_pearson): 115 totals = {} 116 sim_sums = {} 117 118 for other in prefs: 119 # 나와 나는 비교하지않는다. 120 if other == person: 121 continue 122 123 sim = similarity(prefs, person, other) 124 125 # 0이하의 점수는 무시함 126 if sim <= 0: 127 continue 128 for item in prefs[other]: 129 # 내가 보지 못한 영화만 대상으로 한다. 130 if item not in prefs[person] or prefs[person][item] == 0: 131 # 유사도 * 점수 132 totals.setdefault(item, 0) 133 totals[item] += prefs[other][item] * sim 134 135 # 유사도 합계 136 sim_sums.setdefault(item, 0) 137 sim_sums[item] += sim 138 139 # 정규화된 목록 생성 140 rankings = [(total / sim_sums[item], item) for item, total in totals.items()] 141 142 # 정렬된 목록 리턴 143 rankings.sort() 144 rankings.reverse() 145 146 return rankings 147 148 149 def transform_prefs(prefs): 150 result = {} 151 for person in prefs: 152 for item in prefs[person]: 153 result.setdefault(item, {}) 154 result[item][person] = prefs[person][item] 155 156 return result 157 158 159 def calculate_similar_items(prefs, n=10): 160 # 가장 유사한항목들을가진 항목 딕셔너리를 생성 161 result = {} 162 163 # 선호도 행렬을 뒤집어 항목 중심 행렬로 변경 164 item_prefs = transform_prefs(prefs) 165 166 c = 0 167 for item in item_prefs: 168 # 큰 데이터 세트를 위해 진척 상태를 갱신 169 c += 1 170 if c % 100 == 0: 171 print("%d/%d", c, len(item_prefs)) 172 173 # 각항목과 가장 유사한 항목들을 구함 174 scores = top_matches(item_prefs, item, n, sim_distance) 175 result[item] = scores 176 177 return result 178 179 180 def get_recommended_items(prefs, itemMatch, user): 181 user_ratings = prefs[user] 182 scores = {} 183 total_sim = {} 184 # 이 사용자가 평가한 모든 항목마다 루프를 돈다. 185 for (item, rating) in user_ratings.items(): 186 187 # 이항목과 유사한 모든 항목마다 루프를 돈다. 188 for (similarity, item2) in itemMatch[item]: 189 190 # 이미사용자가 항목을 평가했다면 무시한다. 191 if item2 in user_ratings: 192 continue 193 # 유사도와 평가점수 곱의가중치 합을 계산 194 scores.setdefault(item2, 0) 195 scores[item2] += similarity * rating 196 # 모든 유사도 합을 계산 197 total_sim.setdefault(item2, 0) 198 total_sim[item2] += similarity 199 200 # 평균값을 얻기 위해 합계를 가중치 합계로 나눔 201 rankings = [(score / total_sim[item], item) for item, score in scores.items()] 202 203 # 최고값에서 최저값으로 랭킹을 리턴함. 204 rankings.sort() 205 rankings.reverse() 206 return rankings 207 208 # 영화제목을 얻음 209 def load_movie_lens(path='movielens/'): 210 movies = {} 211 for line in open(path + "item.data"): 212 (m_id, m_title) = line.split('|')[0:2] 213 movies[m_id] = m_title 214 #데이터를 로드 215 prefs = {} 216 for line in open(path + "rating.data"): 217 (user, m_id, rating, ts) = line.split('\t') 218 prefs.setdefault(user, {}) 219 prefs[user][movies[m_id]] = float(rating) 220 221 return prefs 222 223 224 # 유저 유사도 측정. 225 def calculate_similar_user(prefs, n=10): 226 # 가장 유사한항목들을가진 항목 딕셔너리를 생성 227 result = {} 228 c = 0 229 for user in prefs: 230 # 큰 데이터 세트를 위해 진척 상태를 갱신 231 c += 1 232 if c % 100 == 0: 233 print("%d/%d", c, len(prefs)) 234 235 # 각항목과 가장 유사한 항목들을 구함 236 scores = top_matches(prefs, user, n, sim_distance) 237 result[user] = scores 238 239 return result 240 241