1
\$\begingroup\$

Task:
Creating a user-based collaborative filtering in the subsequent addition to the hybrid model.

Code:

Model:

import sys
import math
import os
from sklearn.neighbors import NearestNeighbors


class CollaborateFilter:

    def fit(self, X):
        ''' Train similar users search model. '''
        # Create book evaluation matrix
        X_matrix = self.data_preparation(X, 'X')

        # Learning NearestNeighbors
        knn = NearestNeighbors(metric='correlation')

        # Train the model
        knn.fit(X_matrix.values)

        self.knn = knn
        self.X_matrix = X_matrix

    def predict(self, y, k=5):
        y_matrix = self.data_preparation(y, 'y')
        similar_users = self.find_similar_user(y_matrix, k)
        recommendation = self.recommend(self.X_matrix, y_matrix, similar_users)
        return recommendation

    def data_preparation(self, data, type_data=None):
        if type_data == 'X':
            X_matrix = data.pivot_table(index='user',
                                     columns='id_book',
                                     values='grade').fillna(0).astype('int64')
            X_matrix_sort = X_matrix[sorted(X_matrix.columns)]
            return X_matrix_sort
        elif type_data == 'y':
            df_y = data.pivot_table(
                index='user', columns='id_book',
                values='grade')
            df_X = pd.DataFrame(columns=(self.X_matrix.columns))

            y_matrix = df_y.merge(df_X, how='left').fillna(0).astype('int64')
            y_matrix_sort = y_matrix[sorted(y_matrix.columns)]
            return y_matrix_sort
        else:
            raise ValueError('Invalid data specified in the type_data parameter.')


    def find_similar_user(self, y_matrix, k):
        ''' Search for similar users. '''
        distances, indices = self.knn.kneighbors(y_matrix, n_neighbors=k)
        # Find the user id by its index in the elementwise matrix.
        user_indices = self.X_matrix.iloc[indices[0]].index

        data = {
            'user': user_indices[0].tolist(),
            'weight': distances.tolist()[0]
        }
        similar_users = pd.DataFrame(data)

        return similar_users

    def recommend(self, X_matrix, y_matrix, similar_users):
        ''' Recommending books to the target user. '''

        X = X_matrix.stack().reset_index()
        X.rename(columns={0: 'grade'}, inplace=True)
        
        df_sim_user = X.merge(similar_users, on='user', how='right')
        mean = df_sim_user.groupby(by="user",
                                   as_index=False)['grade'].mean().round(2)

        df_sim_user = df_sim_user.merge(mean,
                                        on='user',
                                        suffixes=('', '_mean'))
        df_sim_user['grade_predict'] = y_matrix.mean() + (
            df_sim_user['grade'] - df_sim_user['grade_mean']
        ) * df_sim_user['weight'] / df_sim_user['weight'].abs().sum()
        item_score = df_sim_user[['id_book', 'grade_predict'
                                  ]].sort_values(by='grade_predict',
                                                 ascending=False).reset_index(drop=True)

        return item_score

Model call:

train, test = train_test_split(df_user)

model = CollaborateFilter()
model.fit(train)
test_user = test.query("user==42923")

model.predict(test_user)

My problem:
My code is not fast enough, at least it takes a long time to test it, since you need to wait for each user individually for 10 seconds.

Link to data:
https://dropmefiles.com/rf3G0

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.