3

J'ai un ensemble de données en entrée (au format csv) qui comprend 100246 lignes et 7 colonnes. Ce sont les données de classification de film prises de http://grouplens.org/datasets/movielens/. La tête de mon dataframe est:Goulot d'étranglement dans le filtre collaboratif basé sur les éléments en utilisant des trames de données pandas et des boucles imbriquées en Python

In [5]: df.head() 
Out[5]: 
    movieId          genres userId  rating \ 
0  1 Adventure|Animation|Children|Comedy|Fantasy  1  5 
1  1 Adventure|Animation|Children|Comedy|Fantasy  2  3 
2  1 Adventure|Animation|Children|Comedy|Fantasy  5  4 
3  1 Adventure|Animation|Children|Comedy|Fantasy  6  4 
4  1 Adventure|Animation|Children|Comedy|Fantasy  8  3 

imdbId  title relDate 
0 114709 Toy Story  1995 
1 114709 Toy Story  1995 
2 114709 Toy Story  1995 
3 114709 Toy Story  1995 
4 114709 Toy Story  1995 

En utilisant cet ensemble de données, je calcule les scores de similarité entre chaque paire de films en utilisant la distance euclidienne entre l'utilisateur-ratings (par exemple, si deux films sont classés de façon similaire par l'échantillon d'utilisateurs , alors les films sont fortement corrélés). À l'heure actuelle, il est réalisé par itérer sur toutes les paires de films et en utilisant un instruction if pour trouver que les paires qui contiennent le film d'intérêt actuel:

for i,item in enumerate(df['movieId'].unique()): 
     for j, item_comb in enumerate(combinations(df['movieId'].unique(),2)): 
     if(item in item_comb): 
       ## calculate the similarity score between item i and the other item in item_comb 

Cependant, étant donné qu'il ya des 8927 films différents dans la ensemble de données, le nombre de paires est ~ 40M. C'est un goulot d'étranglement majeur. Donc, ma question est de savoir comment je peux accélérer mon code?

+0

Si vous essayez de produire une sorte de matrice, vous ne devriez pas essayer d'étendre tous les genres dans leurs propres colonnes, puis remplir les lignes avec '1/0' ou' True/False' et ensuite juste 'and' le filtre avec la sélection de l'utilisateur pour produire un calcul de similarité? – EdChum

+0

Le score de similarité n'est pas basé sur les genres, mais plutôt sur la corrélation (ou distance euclidienne) entre les notes des utilisateurs pour les deux films. Donc, pour deux films, j'ai deux vecteurs (x, y) représentant les classements de films donnés par les utilisateurs. J'ai modifié le message pour l'indiquer explicitement. – Feynman27

+0

Il y a beaucoup de questions de distance euclidiennes comme celle-ci, la plupart avec une balise 'numpy' ou' scipy'. – hpaulj

Répondre

-1

il a dans ce paper, dégoûté que vous pouvez rendre votre algorithme rapide avec une autre approche

Dans un document amazon (2003), ils l'ont décrit déjà En résumé, l'idée la plus importante de cet algorithme est de calculer le produit scalaire de deux vecteurs d'une autre manière plutôt que de parcourir simplement chaque élément . quand ils ont les mêmes clients. En d'autres termes, il ignore le 0 calcul de similarité.

For each item in product catalog, I1 
     For each customer C who purchased I1 
     For each item I2 purchased by customer C 
      Record that a customer purchased I1 and I2 
     For each item I2 
     Compute the similarity between I1 and I2 
0

Il existe des approches qui peuvent convertir le calcul de similarité itératif en multiplications matricielles. Si vous utilisez la similarité cosinus, la conversion est expliquée plus en détail dans la réponse à this stack exchange question.

L'autre approche consiste à utiliser les métriques de similarité par paire dans le paquet scikit-learn qui a une implémentation de cosine similarity disponible.

from scikit-learn.metrics.pairwise import cosine_similarity 
user_ratings_df = ....   # create the user x item dataframe 

# Note the dataframe is transposed to convert to items as rows 
item_similarity = cosine_similarity(user_ratings_df.T) 
0

La vectorisation est meilleure que pour la boucle.

Il y a peut-être deux fonctions pandas utiles: pivot_table() et corr()

Par exemple:

In [5]: pt = df.pivot_table(columns=['movieId'], index=['userId'], values='rating') 
Out[5]: 
    movieId  1 2 3 4 5 
    userId       
     1  5 ... 
     2  3 ... 
     5  4 ... 
     6  4 ... 
     8  3 ... 

In [6]: pt.corr() 
Out[6]: 
    movieId  1 2 3 4 5 
    movieId       
     1  1.0  ... 
     2  0.XXX ... 
     3  0.XXX ... 
     4  0.XXX ... 
     5  0.XXX ... 

Notez que corr() ici calculer le coefficient de corrélation standard (corrélation pearson) entre les films plutôt que le euclidienne distance. Vous pouvez également utiliser param min_periods pour définir le nombre minimal d'observations requises par paire de colonnes pour obtenir un résultat valide.