<jupyter_start><jupyter_text>Примеры составлены по мотивам главы 2 книги Т.Сегаран "Программируем коллективный разум" http://www.symbol.ru/alphabet/613828.html  Словарь с предпочтениями пользователи-фильмы<jupyter_code># Словарь кинокритиков и выставленных ими оценок для небольшого набора
# данных о фильмах
critics={'<NAME>': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
 'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5, 
 'The Night Listener': 3.0},
'<NAME>': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5, 
 'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0, 
 'You, Me and Dupree': 3.5}, 
'<NAME>': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
 'Superman Returns': 3.5, 'The Night Listener': 4.0},
'<NAME>': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
 'The Night Listener': 4.5, 'Superman Returns': 4.0, 
 'You, Me and Dupree': 2.5},
'<NAME>': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 
 'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
 'You, Me and Dupree': 2.0}, 
'<NAME>': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
 'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane':4.5,'You, Me and Dupree':1.0,'Superman Returns':4.0}}
import numpy as np
A=np.array(critics)
import pandas as pd
pd.DataFrame(critics)
critics['Toby']
critics['Lisa Rose']['Lady in the Water']

#вычисление расстояния Евклида
from math import sqrt
sqrt(pow(5-4,2)+pow(4-1,2))<jupyter_output><empty_output><jupyter_text>расстояние между (5,4) и (4, 1)<jupyter_code>#вычисление сходства
1/(1+sqrt(pow(5-4,2)+pow(4-1,2)))<jupyter_output><empty_output><jupyter_text>$sim(x,y) = \frac{1}{1+d(x,y)}$<jupyter_code>from numpy import exp
exp(-0.3*sqrt(pow(5-4,2)+pow(4-1,2)))<jupyter_output><empty_output><jupyter_text>$sim(x,y) = e^{-d(x,y)*\alpha}$<jupyter_code>from math import sqrt
# Возвращает сходство person1 и person2 на основе расстояния
def sim_distance(prefs,person1,person2):
# Получить список предметов, оцененных обоими
    si={}
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item]=1
# Если нет ни одной общей оценки, вернуть 0
    if len(si)==0: return 0
# Сложить квадраты разностей/
    sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2)
    for item in prefs[person1] if item in prefs[person2]])
    return 1/(1+sum_of_squares)

from math import sqrt
# Возвращает сходство person1 и person2 на основе расстояния
def sim_kernel(prefs,person1,person2,alpha=0.3):
# Получить список предметов, оцененных обоими
    si={}
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item]=1
# Если нет ни одной общей оценки, вернуть 0
    if len(si)==0: return 0
# Сложить квадраты разностей
    sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2)
    for item in prefs[person1] if item in prefs[person2]])
    return exp(-alpha*sum_of_squares)
sim_kernel(critics, '<NAME>','Toby')
sim_kernel(critics, '<NAME>','<NAME>')
sim_distance(critics, '<NAME>ose','Toby')
# Возвращает коэффициент корреляции Пирсона между p1 и p2
def sim_pearson(prefs,p1,p2):
# Получить список предметов, оцененных обоими
    si={}
    for item in prefs[p1]: 
        if item in prefs[p2]: si[item]=1

    # Если нет ни одной общей оценки, вернуть 0
    if len(si)==0: return 0

    # Количество соместно оцененных фильм
    n=len(si)
  
    # Вычислить сумму всех предпочтений
    sum1=sum([prefs[p1][it] for it in si])
    sum2=sum([prefs[p2][it] for it in si])
  
    # Вычислить сумму квадратов
    sum1Sq=sum([pow(prefs[p1][it],2) for it in si])
    sum2Sq=sum([pow(prefs[p2][it],2) for it in si])	
  
    # Вычислить сумму произведений
    pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])
  
    # Вычислить коэффициент Пирсона
    num=pSum-(sum1*sum2/n)
    den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
    if den==0: return 0

    r=num/den

    return r
sim_pearson(critics,'<NAME>','<NAME>'), sim_pearson(critics, '<NAME>','Toby')<jupyter_output><empty_output><jupyter_text>Кроме приведенных выше мер сходства, часто используют косинусную схожесть, которая определяется как $$\frac{(x,y)}{|x||y|},$$где $(x,y)$ -- скалярное произведение, а $|x|$ -- длина вектора $x$.Реализуйте функцию вычисляющую косинусную схожесть.<jupyter_code>def sim_cosine(prefs,person1,person2):
# Получить список предметов, оцененных обоими
    si={}
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item]=1
# Если нет ни одной общей оценки, вернуть 0
    if len(si)==0: return 0

    sum_of_prod=sum([prefs[person1][item]*prefs[person2][item] for item in si])
    len1 = sum([prefs[person1][item]*prefs[person1][item] for item in si])
    len2 = sum([prefs[person2][item]*prefs[person2][item] for item in si])
    return sum_of_prod/sqrt(len1*len2)<jupyter_output><empty_output><jupyter_text>Ранжирование критиков<jupyter_code># Возвращает список наилучших соответствий для человека из словаря prefs.
# Количество результатов в списке и функция подобия – необязательные
# параметры.
def topMatches(prefs,person,n=5,similarity=sim_pearson):
    sim_list = sorted([(similarity(prefs, person, p), p) for p in prefs if p != person], reverse = True)
    return sim_list[:n]
    
            
        
    

topMatches(critics,'Toby',n=3, similarity=sim_distance)
topMatches(critics,'Toby',n=3, similarity=sim_kernel)<jupyter_output><empty_output><jupyter_text>Рекомендация фильмов (User-based подход)Базовая идея:Мы уже научились сравнивать пользователей и находить наиболее похожих. Давайте выберем самых похожих пользователей и усредним их оценки с весами равными этой похожести. $R_{i} = \sum\limits_{k} sim(i,k)*R_{k}/\sum\limits_{k} sim(i,k),$ где $R_i$ -- оценка поставленная пользователем $i$<jupyter_code>0.5 0.3 0.3 -0.1


5 4 5 3


(0.5*5 + 0.3*4 + 0.3*5 + 0*3)/(0.5+0.3+0.3 + 0)
# Получить рекомендации для заданного человека, пользуясь взвешенным средним
# оценок, данных всеми остальными пользователями
def getRecommendations(prefs,person,similarity=sim_pearson, only_NA = True):
    top_persons = topMatches(prefs,person, 100, similarity)
    film_sum = {}
    film_multiplyer = {}
    for p in top_persons:
        if p[0] <=0: break
        for item in prefs[p[1]]:
            if not item in film_sum:
                film_sum[item] = 0
                film_multiplyer[item] = 0
            
            film_sum[item] += prefs[p[1]][item]*p[0]
            film_multiplyer[item] += p[0] 
    if only_NA:
        recomend = sorted([(film_sum[item]/film_multiplyer[item], item) for item in film_sum if item not in prefs[person]], reverse = True)
    else:
        recomend = sorted([(film_sum[item]/film_multiplyer[item], item) for item in film_sum], reverse = True)
        
    return recomend
getRecommendations(critics,'Toby')

getRecommendations(critics,'Toby', sim_kernel)
getRecommendations(critics,'Toby', only_NA = False)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14527603870233352, 'fraction_numerical': 0.03315310187820148, 'mean_word_length': 4.465785381026438, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '557729', 'license': 'MIT', 'n_tokens_mistral': 3016, 'n_tokens_neox': 3079, 'n_words': 668, 'path': 'week2/solution2 (1).ipynb', 'repo_name': 'vvseva/recomend_hse', 'size': '7090'}