%matplotlib inline

import matplotlib
import numpy as np
import matplotlib.pyplot as plt

# A dictionary of movie critics and their ratings of a small
# set of movies
critics={'Lisa Rose': {'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},
'Gene Seymour': {'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},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
 'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'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},
'Mick LaSalle': {'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},
'Jack Matthews': {'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}}

critics['Lisa Rose']['Lady in the Water']


critics['Toby']['Snakes on a Plane']=4.5


critics['Toby']

"""
Explanation: Collaborative Filtering
End of explanation
"""


from math import sqrt

# Returns a distance-based similarity score for person1 and person2
def sim_distance(prefs,person1,person2):
    # Get the list of shared_items
    si={}
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item]=1

    # if they have no ratings in common, return 0
    if len(si)==0: return 0

    # Add up the squares of all the differences
    sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2)
                      for item in si])

    return 1/(1+sqrt(sum_of_squares))

#This function can be called with two names to get a similarity score
#This gives you a similarity score between Lisa Rose and Gene Seymour. 
sim_distance(critics,'Lisa Rose','Gene Seymour')

"""
Explanation: Finding Similar Users
Euclidean Distance Score
One very simple way to calculate a similarity score is to use a Euclidean distance score, which takes the items that people have ranked in common and uses them as axes for a chart.
End of explanation
"""


"""
Returns the Pearson correlation coefficient for p1 and p2. This function will return a value between −1 and 1. 
A value of 1 means that the two people have exactly the same ratings for every item. Unlike with the distance metric, 
you don't need to change this value to get it to the right scale.
"""
def sim_pearson(prefs,p1,p2):
    # Get the list of mutually rated items
    si={}
    for item in prefs[p1]:
        if item in prefs[p2]: si[item]=1

    # Find the number of elements
    n=len(si)

    # if they have no ratings in common, return 0
    if n==0: return 0

    # Add up all the preferences
    sum1=sum([prefs[p1][it] for it in si])
    sum2=sum([prefs[p2][it] for it in si])

    # Sum up the squares
    sum1Sq=sum([pow(prefs[p1][it],2) for it in si])
    sum2Sq=sum([pow(prefs[p2][it],2) for it in si])

    # Sum up the products
    pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])

    # Calculate Pearson score
    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

#Run the code
print sim_pearson(critics,'Lisa Rose','Gene Seymour')

def dict_to_list(dict):
    dictlist = []

    for key, value in dict.iteritems():
        temp = [key,value]
        dictlist.append(temp)
        
    return dictlist

#Plot Two Movies

import collections

dim1 = critics ['Lisa Rose']
dim2 = critics['Gene Seymour']
dim1 = collections.OrderedDict(sorted(dim1.items()))
dim2 = collections.OrderedDict(sorted(dim2.items()))
print dim1
print dim2

x = list(dim1.values())
y = list(dim2.values())

print x
print y
plt.scatter(x,y, alpha=0.5)
plt.xlabel('Lisa Rose')
plt.ylabel('Gene Seymour')

plt.show()


"""
Explanation: Pearson Correlation Score
To determine the similarity between people's interests is to use a Pearson correlation coefficient. The correlation coefficient is a measure of how well two sets of data fit on a straight line.
End of explanation
"""


# Returns the best matches for person from the prefs dictionary.
# Number of results and similarity function are optional params.
def topMatches(prefs,person,n=5,similarity=sim_pearson):
    scores=[(similarity(prefs,person,other),other)
                  for other in prefs if other!=person]

    # Sort the list so the highest scores appear at the top
    scores.sort(  )
    scores.reverse(  )
    return scores[0:n]

# Calling this function with a name gives a list of movie critics and their similarity scores, compared to the name:
topMatches(critics,'Toby',n=3)

"""
Explanation: Ranking the Critics
Now that you have functions for comparing two people, you can create a function that scores everyone against a given person and finds the closest matches. In this case, I'm interested in learning which movie critics have tastes simliar to mine so that I know whose advice I should take when deciding on a movie.
The following function uses a Python list comprehension to compare me to every other user in the dictionary using one of the previously defined distance metrics. Then it returns the first n items of the sorted results.
End of explanation
"""


