Advertisement
glavinova

[СНЗ] Табела на слични корисници - Системи за препорака

Jul 5th, 2020
1,803
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.34 KB | None | 0 0
  1. """ Табела на слични корисници Problem 1 (1 / 1)
  2. Дадено е множество кое е претставено како речник чиј клуч е името на корисникот и вредност како речник чиј клуч е филмот, а вредност е оцената која корисникот ја дал за филмот. Да се напише функција која ќе генерира табела на слични корисници претставена како речник од речници (клучеви се имињата на корисниците), така што за секој пар корисници ќе чува торка од сличност базирана на Пеарсонова корелација, сличност базирана на Евклидово растојание, и број на заеднички оцени (оцени дадени за исти филмови). Вредностите да бидат заокружени на 3 децимали. За прочитани имиња на двајца корисници да се испечати торката која се чува во генерираната табела."""
  3.  
  4.  
  5. movie_reviews = {
  6.     'Lisa Rose': {'Catch Me If You Can': 3.0, 'Snakes on a Plane': 3.5, 'Superman Returns': 3.5,
  7.                   'You, Me and Dupree': 2.5, 'The Night Listener': 3.0, 'Snitch': 3.0},
  8.     'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5, 'Just My Luck': 1.5, 'The Night Listener': 3.0,
  9.                      'You, Me and Dupree': 3.5},
  10.     'Michael Phillips': {'Catch Me If You Can': 2.5, 'Lady in the Water': 2.5, 'Superman Returns': 3.5,
  11.                          'The Night Listener': 4.0, 'Snitch': 2.0},
  12.     'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0, 'The Night Listener': 4.5, 'Superman Returns': 4.0,
  13.                      'You, Me and Dupree': 2.5},
  14.     'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 'Just My Luck': 2.0, 'Superman Returns': 3.0,
  15.                      'You, Me and Dupree': 2.0},
  16.     'Jack Matthews': {'Catch Me If You Can': 4.5, 'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
  17.                       'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5, 'Snitch': 4.5},
  18.     'Toby': {'Snakes on a Plane': 4.5, 'Snitch': 5.0},
  19.     'Michelle Nichols': {'Just My Luck': 1.0, 'The Night Listener': 4.5, 'You, Me and Dupree': 3.5,
  20.                          'Catch Me If You Can': 2.5, 'Snakes on a Plane': 3.0},
  21.     'Gary Coleman': {'Lady in the Water': 1.0, 'Catch Me If You Can': 1.5, 'Superman Returns': 1.5,
  22.                      'You, Me and Dupree': 2.0},
  23.     'Larry': {'Lady in the Water': 3.0, 'Just My Luck': 3.5, 'Snitch': 1.5, 'The Night Listener': 3.5}
  24. }
  25.  
  26. from math import sqrt
  27.  
  28.  
  29. def sim_distance(prefs, person1, person2):
  30.     """
  31.    Враќа мерка за сличност базирана на растојание помеѓу person1 и person2
  32.    :param prefs: речник со оцени од корисници
  33.    :param person1: име на корисник1
  34.    :param person2: име на корисник2
  35.    :return: сличност помеѓу корисник1 и корисник2
  36.    """
  37.     # Се прави листа на заеднички предмети
  38.     si = {}
  39.     for item in prefs[person1]:
  40.         if item in prefs[person2]:
  41.             si[item] = 1
  42.     # Ако немаат заеднички рејтинзи, врати 0
  43.     if len(si) == 0:
  44.         return 0
  45.     # Собери ги квадратите на сите разлики
  46.     sum_of_squares = sum([pow(prefs[person1][item] - prefs[person2][item], 2)
  47.                           for item in prefs[person1] if item in prefs[person2]])
  48.     return 1 / (1 + sqrt(sum_of_squares))
  49.  
  50.  
  51. def sim_pearson(prefs, p1, p2):
  52.     """
  53.    Го враќа коефициентот на Пирсонова корелација помеѓу p1 и p2 (личност1 и личност 2).
  54.    Вредностите се помеѓу -1 и 1
  55.    :param prefs: речник со оцени од корисници
  56.    :param p1: име на корисник1
  57.    :param p2: име на корисник2
  58.    :return: сличност помеѓу корисник1 и корисник2
  59.    """
  60.     # Се креира речник во кој ќе се чуваат предметите кои се оценети од двајцата
  61.     # Во речникот ни се важни само клучевите за да ги чуваме имињата на филмовите
  62.     # кои се заеднички, а вредностите не ни се важни
  63.     si = {}
  64.     for item in prefs[p1]:
  65.         if item in prefs[p2]:
  66.             si[item] = 1
  67.  
  68.     # Се пресметува бројот на предмети оценети од двајцата
  69.     n = len(si)
  70.  
  71.     # Ако немаат заеднички предмети, врати корелација 0
  72.     if n == 0:
  73.         return 0
  74.  
  75.     # Собери ги сите оцени за секоја личност посебно
  76.     sum1 = sum([prefs[p1][it] for it in si])
  77.     sum2 = sum([prefs[p2][it] for it in si])
  78.     # Собери ги квадратите од сите оцени за секоја личност посебно
  79.     sum1Sq = sum([pow(prefs[p1][it], 2) for it in si])
  80.     sum2Sq = sum([pow(prefs[p2][it], 2) for it in si])
  81.     # Собери ги производите од оцените на двете личности
  82.     pSum = sum([prefs[p1][it] * prefs[p2][it] for it in si])
  83.  
  84.     # Пресметај го коефициентот на корелација
  85.     num = pSum - (sum1 * sum2 / n)
  86.     den = sqrt((sum1Sq - pow(sum1, 2) / n) * (sum2Sq - pow(sum2, 2) / n))
  87.     if den == 0:
  88.         return 0
  89.     r = num / den
  90.     return r
  91.  
  92.  
  93. def top_matches(prefs, person, n=5, similarity=sim_pearson):
  94.     """
  95.    Ги враќа најсличните n корисници за даден корисник.
  96.    :param prefs: речник со оцени од корисници
  97.    :param person: име на корисник
  98.    :param n: број на слични корисници
  99.    :param similarity: метрика за сличност
  100.    :return: листа со најслични n корисници
  101.    """
  102.     scores = [(similarity(prefs, person, other), other)
  103.               for other in prefs if other != person]
  104.     # Се сортира листата во растечки редослед
  105.     scores.sort()
  106.     # Се превртува за најсличните (со најголема вредност) да бидат први
  107.     scores.reverse()
  108.     return scores[0:n]
  109.  
  110.  
  111. def get_recommendations(prefs, person, similarity=sim_pearson):
  112.     """
  113.    Ги враќа препораките за даден корисник со користење на тежински просек
  114.    со оцените од другите корисници
  115.    :param prefs: речник со оцени од корисници
  116.    :param person: име на корисник
  117.    :param similarity: метрика за сличност
  118.    :return: препораки за даден корисник
  119.    """
  120.     totals = {}
  121.     simSums = {}
  122.     for other in prefs:
  123.         # За да не се споредува со самиот себе
  124.         if other == person:
  125.             continue
  126.         sim = similarity(prefs, person, other)
  127.         # не се земаат предвид резултати <= 0
  128.         if sim <= 0:
  129.             continue
  130.         for item in prefs[other]:
  131.             # за тековниот корисник ги земаме само филмовите што ги нема гледано
  132.             if item not in prefs[person] or prefs[person][item] == 0:
  133.                 # Similarity * Score
  134.                 totals.setdefault(item, 0)
  135.                 totals[item] += prefs[other][item] * sim
  136.  
  137.                 # Сума на сличности
  138.                 simSums.setdefault(item, 0)
  139.                 simSums[item] += sim
  140.  
  141.     # Креирање на нормализирана листа со рејтинзи
  142.     rankings = [(total / simSums[item], item) for item, total in totals.items()]
  143.  
  144.     # Сортирање на листата во растечки редослед. Превртување на листата за најголемите вредности да бидат први
  145.     rankings.sort(reverse=True)
  146.  
  147.     return rankings
  148.  
  149.  
  150. def get_recommendations_item_based(inverted_prefs, person):
  151.     """
  152.    Ги враќа препораките за даден корисник со користење на тежински просек
  153.    со оцените од предметите
  154.    :param inverted_prefs: инвертиран речник со оцени од корисници, item-based
  155.    :param person: име на корисник
  156.    :return: препораки за даден корисник
  157.    """
  158.     similarity_per_item = {}
  159.     person_items = [item for item, values in inverted_prefs.items() if person in values.keys()]
  160.     for item in person_items:
  161.         similar_items = top_matches(inverted_prefs, item, n=None)
  162.         my_rating = inverted_prefs[item][person]
  163.         for similarity, item in similar_items:
  164.             if person in inverted_prefs[item] or similarity <= 0:
  165.                 continue
  166.             similarity_per_item.setdefault(item, [])
  167.             similarity_per_item[item].append(similarity * my_rating)
  168.  
  169.     # Креирање на нормализирана листа со рејтинзи
  170.     similarity_per_item_avg = [(sum(similarity_per_item[item]) / len(similarity_per_item[item]), item) for item in
  171.                                similarity_per_item]
  172.     similarity_per_item_avg.sort(reverse=True)
  173.  
  174.     return similarity_per_item_avg
  175.  
  176.  
  177. def transform_prefs(prefs):
  178.     """
  179.    Ги трансформира рејтинзите така што клучеви ќе бидат филмовите,
  180.    а вредност ќе биде листа со рејтинзи од секој корисник
  181.    :param prefs: речник со оцени од корисници
  182.    :return: инвертиран речник со оцени од корисници
  183.    """
  184.     result = {}
  185.     for person in prefs:
  186.         for item in prefs[person]:
  187.             result.setdefault(item, {})
  188.             # Замени ги местата на корисникот и предметот
  189.             result[item][person] = prefs[person][item]
  190.     return result
  191. #oceni dadeni za isti filmovi
  192. def zaednicki(oceni, p1, p2):
  193.     zaednicki=set()
  194.     for i in oceni[p1]:
  195.         if i in oceni[p2]:
  196.             zaednicki.add(i)
  197.     return len(zaednicki)
  198. #generiranje na tabela na slicni korisnici
  199. def generate_table(oceni):
  200.     slicnosti ={}
  201.     for i in oceni:
  202.         slicnosti[i]={}
  203.         for j in oceni:
  204.             if i != j:
  205.                 sim1 = sim_distance(oceni,i,j)
  206.                 sim2 = sim_pearson(oceni,i,j)
  207.                 slicnosti[i][j] = (round(sim1,2), round(sim2,2), zaednicki(oceni,i,j))
  208.  
  209.     return slicnosti
  210.  
  211.  
  212. if __name__ == "__main__":
  213.     korisnik1 = input()
  214.     korisnik2 = input()
  215.     tabela = generate_table(movie_reviews)
  216.     print(tabela[korisnik1][korisnik2])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement