Alternating Least squares (ASL) for implicit Feedback datasets mathematical derivation and Python implementation

Source: Internet
Author: User

Recently in the CF related papers, "collaborative Filtering for implicit Feedback Datasets" thought very good, very easy to understand. But from the target function

How to deduce the new formula of Xu and Yi's derivation process is not very good descriptive narrative. So here's a little bit of writing
Derivation:
The first derivative of Xu:

Where Y is the item matrix, n*f, each line is a item_vec,c^u is a diagonal matrix of n*n dimensions.
Each element on the diagonal is c_ui,p (U), which is the n*1 column vector, and the first element of it is p_ui.
Then the derivative = 0, which can be:

Because X_u and y_i are symmetric in the objective function. So very easy to get:

where x is the user matrix, the M*f dimension, and each row is a user_vec,c^i is the diagonal matrix of the m*m. Each element on the diagonal is c_ui. P (i) is the column vector of the m*1. The first and the elements of it are p_ui
Then the derivative = 0, which can be:

The following is the Python implementation of the thesis algorithm idea:

ImportNumPy asNpImportScipy.sparse asSparse fromScipy.sparse.linalgImportSpsolveImportTime def load_matrix(filename, num_users, num_items):T0 = Time.time () counts = Np.zeros ((num_users, num_items)) total =0.0Num_zeros = num_users * Num_itemsSuppose you want to traverse an index and iterate over an element for a list or array. Be able to use enumerate, when the input parameter is a file, the index is the line number, the element corresponding line "'"     forI, lineinchEnumerate (open (filename,' R ')):#strip () remove the front and back spacesUser, item, Count = Line.strip (). Split (' \ t 'user = Int (user) item = INT (item) Count = Float (count)ifUser >= Num_users:Continue        ifItem >= Num_items:Continue        ifCount! =0: Counts[user, Item] = Count Total + = count Num_zeros-=1        ifI100000==0:Print ' Loaded%i counts ... '% i#数据导入完成后计算稀疏矩阵中零元素个数和非零元素个数的比例, recorded as AlphaAlpha = Num_zeros/totalPrint ' Alpha%.2f '% Alpha counts *= Alpha#用CompressedSparse Row format to compress sparse matricesCounts = Sparse.csr_matrix (counts) T1 = Time.time ()Print ' finished loading matrix in%f seconds '% (T1-T0)returnCounts class IMPLICITMF():     def __init__(self, Counts, num_factors=, num_iterations=, reg_param=0.8):Self.counts = Counts Self.num_users = counts.shape[0] Self.num_items = counts.shape[1] Self.num_factors = num_factors Self.num_iterations = num_iterations Self.reg_param = Reg_param def Train_model(self):        #创建user_vectors和item_vectors, the normal distribution of their element ~n (0,1)Self.user_vectors = Np.random.normal (size= (Self.num_users, Self.num_fact                                                   ORS)) Self.item_vectors = Np.random.normal (size= (Self.num_items, self.num_factors))" to generate very large sequence of numbers, using xrange will be much better than range performance, because there is no need to open up a very large amount of memory space, these two are basically in the loop when the "         forIinchXrange (self.num_iterations): T0 = Time.time ()Print ' Solving for user vectors ... 'Self.user_vectors = Self.iteration (True, Sparse.csr_matrix (self.item_vectors))Print ' solving for item vectors ... 'Self.item_vectors = Self.iteration (False, Sparse.csr_matrix (self.user_vectors)) T1 = Time.time ()Print ' Iteration%i finished in%f seconds '% (i +1, t1-t0) def Iteration(self, user, fixed_vecs):        #相当于C的三木运算符. If user=true num_solve = Num_users, and vice versa is Num_itemsNum_solve = Self.num_usersifUserElseSelf.num_items num_fixed = fixed_vecs.shape[0] Yty = fixed_vecs.        T.dot (fixed_vecs) eye = Sparse.eye (num_fixed) Lambda_eye = Self.reg_param * Sparse.eye (self.num_factors) Solve_vecs = Np.zeros ((num_solve, self.num_factors)) T = Time.time () forIinchXrange (num_solve):ifUser:counts_i = Self.counts[i].toarray ()Else:#假设要求item_vec, Counts_i is the transpose of column I in countsCounts_i = self.counts[:, I]. T.toarray ()In the original paper, c_ui=1+alpha*r_ui, but in order to reduce the complexity of time in the calculation of Y ' CuY, the use of Y ' cuy=y ' y+y ' (cu-i) y, because the Cu is a diagonal matrix, the element is c_ui, that is 1+alpha*r_ui                。 So cu-i is the diagonal matrix of the diagonal element alpha*r_ui.CuI = Sparse.diags (counts_i, [0]) Pu = counts_i.copy ()#np. WHERE (PU! = 0) Returns the index of the element in Pu that is not 0, and assigns these elements to a value of 1, and does not know why this is assigned to a value of 1?Pu[np.where (PU! =0)] =1.0Ytcuiy = Fixed_vecs. T.dot (CuI). dot (fixed_vecs) Ytcupu = Fixed_vecs. T.dot (CuI + eye). Dot (Sparse.csr_matrix (PU). T) Xu = spsolve (yty + Ytcuiy + lambda_eye, ytcupu) solve_vecs[i] = XuifI +==0:Print ' Solved%i vecs in%d seconds '% (i, time.time ()-t) T = time.time ()returnSolve_vecs

Alternating Least squares (ASL) for implicit Feedback datasets mathematical derivation and Python implementation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.