Aternating Least Squares


In [1]:
import numpy as np
import pandas as pd
from matplotlib import pylab as plt
%matplotlib inline

In [183]:
user_movie_ratings = [
    (1, 1, 5),
    (1, 2, 4),
    (1, 5, 1),
    (2, 1, 5),
    (2, 4, 1),
    (3, 5, 1),
    (3, 2, 4),
    (4, 3, 2),
    (4, 1, 4),
    (4, 2, 5),
    (5, 1, 1),
    (5, 5, 5),
    (6, 2, 2),
    (6, 4, 4),
    (6, 3, 1),
    (7, 5, 4),
    (7, 4, 5),
    (8, 2, 1),
    (8, 5, 4),
    (9, 4, 4),
    (9, 5, 5),
    (9, 2, 1),
    (10, 2, 1),
    (10, 1, 1),
    (10, 4, 5),
    (11, 1, 5),
    (11, 2, 4),
    (11, 5, 1),
    (12, 1, 5),
    (12, 3, 1),
    (13, 1, 4),
    (13, 2, 5),
    (13, 4, 1),
    (14, 1, 5),
    (14, 2, 5),
    (14, 3, 1),
    (15, 2, 5),
    (15, 3, 1),
    (15, 5, 1),
    (16, 1, 5),
    (17, 1, 4),
    (17, 2, 5),
    (17, 4, 1),
    (17, 5, 1),
    (18, 1, 5),
    (18, 5, 1),
    (18, 4, 1),
    (19, 5, 1),
]

user_max_id = np.amax(user_movie_ratings, axis=0)[0]
movie_max_id = np.amax(user_movie_ratings, axis=1)[0]

A = np.zeros((movie_max_id, user_max_id))
for i in user_movie_ratings:
    A[i[1] - 1][i[0] - 1] = i[2]
A


Out[183]:
array([[ 5.,  5.,  0.,  4.,  1.,  0.,  0.,  0.,  0.,  1.,  5.,  5.,  4.,
         5.,  0.,  5.,  4.,  5.,  0.],
       [ 4.,  0.,  4.,  5.,  0.,  2.,  0.,  1.,  1.,  1.,  4.,  0.,  5.,
         5.,  5.,  0.,  5.,  0.,  0.],
       [ 0.,  0.,  0.,  2.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,
         1.,  1.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  0.,  0.,  0.,  4.,  5.,  0.,  4.,  5.,  0.,  0.,  1.,
         0.,  0.,  0.,  1.,  1.,  0.],
       [ 1.,  0.,  1.,  0.,  5.,  0.,  4.,  4.,  5.,  0.,  1.,  0.,  0.,
         0.,  1.,  0.,  1.,  1.,  1.]])

In [190]:
RANK = 5
U = np.random.rand(movie_max_id, RANK)
M = np.random.rand(RANK, user_max_id)

W = np.copy(A)
W[W!=0] = 1
W


Out[190]:
array([[ 1.,  1.,  0.,  1.,  1.,  0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,
         1.,  0.,  1.,  1.,  1.,  0.],
       [ 1.,  0.,  1.,  1.,  0.,  1.,  0.,  1.,  1.,  1.,  1.,  0.,  1.,
         1.,  1.,  0.,  1.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,
         1.,  1.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  0.,  0.,  0.,  1.,  1.,  0.,  1.,  1.,  0.,  0.,  1.,
         0.,  0.,  0.,  1.,  1.,  0.],
       [ 1.,  0.,  1.,  0.,  1.,  0.,  1.,  1.,  1.,  0.,  1.,  0.,  0.,
         0.,  1.,  0.,  1.,  1.,  1.]])

In [191]:
eta = 0.02
for i in range(40):
    error = np.sum(np.power(W * (A - U.dot(M)), 2))
    print(error)
    dU = -(W * (A - U.dot(M))).dot(M.T)
    U = U - eta * dU
    dM = -U.T.dot(W * (A - U.dot(M)))
    M = M - eta * dM


344.265171421
211.098239596
140.910095498
110.929470103
97.9878261018
91.0196535429
86.1914536527
82.13538932
78.2587791135
74.2569605764
69.9623381193
65.2918738966
60.2283664907
54.8133269715
49.1412078715
43.3496425643
37.6038255018
32.0762319182
26.9250846948
22.2757422192
18.2084932642
14.7546015326
11.9004315286
9.5976382527
7.77625363847
6.35743433961
5.26355916256
4.42472626052
3.78187078912
3.28736653652
2.90410718825
2.60388757833
2.36563010292
2.17375354383
2.01680733118
1.88639216663
1.77633835622
1.6820956015
1.60028705282
1.52838662463

In [192]:
i = 15
print(A[:,i])
print(U.dot(M).round(1)[:,i])


[ 5.  0.  0.  0.  0.]
[ 5.   4.3  1.4  4.2  3.5]

In [ ]:


In [ ]: