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