推荐系统已经成为机器学习在电子商务领域中最成功的应用之一,大多数有规模的电子商务网站都将推荐系统作为吸引和发掘客户的核心技术之一,接下来主要讲解推荐系统的基本原理与运行架构,并通过机器学习的代码或者模块实现。
1 推荐系统架构
2 协同过滤及其算法
2.1 协同过滤(Collaborative Filtering,CF)
协同过滤通过用户和产品及用户的偏好信息产生推荐的策略,最基本的策略有两种:一种是找到具有类似品味的人所喜欢的物品;另一种是从一个人喜欢的物品中找到类似的物品。这就是两个最知名的类别推荐技术:基于用户的推荐技术和基于物品的推荐技术,它们被称为协同过滤。
为了深入分析协同过滤的原理,首先我们开始实现协同过滤的模型及算法。
- 数据预处理与UI矩阵
- 推荐模型:User CF 和 Item CF
- KMeans计算相似性
- SVD计算相似性
2.2 数据预处理
一般我们收集到的用户行为数据,都是比较“脏”的数据,因此需要对数据进行一定的预处理,一般对于推荐系统相关的数据一般在数据预处理过程中主要考虑减噪和归一化,其目的是下一步更好的聚类。
- 减噪:用户行为数据是用户在使用应用过程中产生的,它可能存在大量的噪声和用户的误操作,我们需要通过一些减噪算法过滤掉数据中的噪声,一般是离群点,这样可以使得我们的分析更加精准。
- 归一化:在计算用户对物品的偏好程度时,不同行为的数据取值量纲不同,甚至可能相差很大。比如,用户的查看数据必然比购买数据大的多。归一化的任务就是统一量纲,使数据都集中在一个相同的取值范围内,从而使得用户的总体偏好更加精确。归一化的方法很多,最简单的归一化处理就是将各类数据除以此类中的最大值,以保证归一化后的数据取值在[0,1]范围内。
对于具体数据预处理的步骤可以参考我kaggle学习中整理的一些方法。
2.3 Kmeans聚类
聚类就是对大量未知标注的数据集,按数据的内在相似性将数据集划分为多个类别,使类别内的数据相似度较大而类别间的数据相似度较小,本质上是一种无监督学习。
基本思想:
给定一个有N个对象的数据集,构造数据的k个簇, k ≤ n k\le n k≤n,满足下列条件:
- 每一个簇至少包含一个对象
- 每一个对象属于且仅属于一个簇
- 将满足上述条件的k个簇称作一个合理划分
对于给定的类别数据k,首先给出初始划分,通过迭代改变样本和簇的隶属关系,使得每一次改进之后的划分方案都较前一次好。
K-Means算法
k-Means算法,也被称为k-平均或k-均值,是一种广泛使用的聚类算法,或者称为其他聚类算法的基础。
假定输入样本为 S = x 1 , x 2 , . . . . , x m S=x_1,x_2,....,x_m S=x1,x2,....,xm,则算法步骤为:
- 选择初始的 k k k个类别中心 μ 1 , μ 2 , . . . . . . μ k \mu_1,\mu_2,......\mu_k μ1,μ2,......μk;
- 对于每个样本 x i x_i xi,将其标记为距离类别中心最近的类别,即:
l a b e l i = a r g m i n 1 ≤ j ≤ k ∣ ∣ x i − μ j ∣ ∣ label_i = arg min_{1\le j\le k}||x_i-\mu_j|| labeli=argmin1≤j≤k∣∣xi−μj∣∣
- 将每个类别中心更新为隶属该类别的所有样本的均值:
μ j = 1 ∣ c j ∣ ∑ i ∈ c j x i \mu_j = \frac{1}{|c_j|}\sum_{i\in c_j}x_i μj=∣cj∣1i∈cj∑xi
- 重复最后两步,直到类别中心的变化小于某阈值。
终止条件
- 迭代次数/簇中心变化率/最小平方误差MSE(Minimum Squared Error)
首先我们采用Scikit-Learn的KMeans算法来简单进行对算法所实现的效果直观理解一下:
from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pylab as plt
import matplotlib as mpl
import sklearn.datasets as ds
x, y = ds.make_blobs(400, n_features=2, centers=4, random_state=2018)
model = KMeans(n_clusters=4, init='k-means++')
model.fit(x)
y_pred = model.predict(x)
plt.subplot(121)
plt.plot(x[:, 0], x[:, 1], 'r.', ms=3)
plt.subplot(122)
plt.scatter(x[:, 0], x[:, 1], c=y_pred, marker='.',cmap=mpl.colors.ListedColormap(list('rgbm')))
plt.tight_layout(2)
plt.show()
实现的效果图如下图所示:
如果把上图中的点为海量的用户和物品信息,通过Kmeans聚类,这些海量的数据就被精简为4个类别。这极大地减少了后续协同过滤算法的计算量。
2.4 User CF原理
下面给出一个简单的UI(User Item)矩阵实例:假设数据预处理后的结果为,有User A~D 4个用户,有Item A~F 6个物品,构成的矩阵如下表所示:
UI矩阵
User/Item | Item A | Item B | Item C | Item D | Item E | Item F |
---|---|---|---|---|---|---|
User A | 5 | 5 | 3 | 0 | 5 | 5 |
User B | 5 | 0 | 4 | 0 | 4 | 4 |
User C | 0 | 3 | 0 | 5 | 4 | 5 |
User D | 5 | 4 | 3 | 3 | 5 | 5 |
从而可以得到一个用户偏好(User Item)的矩阵,行是用户列表,列是物品列表,值是用户对物品的偏好。一般情况下用户偏好都进行了归一化,所以常为[0,1]或者[-1,1]的浮点数值。
矩阵中的每个元素表示用户选择某个物品的概率,按行的加总值为1.非零值的元素表示某用户对某类物品有偏好,值越大表示偏好月强烈,相反0表示无偏好,所以讲上表按照用户偏好概率归一化,得到:
用户相似度矩阵
User/Item | Item A | Item B | Item C | Item D | Item E | Item F |
---|---|---|---|---|---|---|
User A | 0.2174 | 0.2174 | 0.1304 | 0 | 0.2174 | 0.2174 |
User B | 0.238 | 0 | 0.1905 | 0.1905 | 0.1905 | 0.1905 |
User C | 0 | 0.177 | 0 | 0…294 | 0.235 | 0.294 |
User D | 0.2 | 0.16 | 0.12 | 0.12 | 0.2 | 0.2 |
接下来就上述例子简单实现,基于用户的CF的基本思想相当简单–》基于用户对物品的偏好划分用户类型(聚类算法),找到最近邻用户(KNN近邻算法),然后将同类用户和相邻用户所喜欢的推荐给当前用户。计算上,就是将一个用户对所有物品的偏好作为一个向量来计算用户之间的相似度,找到K邻居后,根据邻居的相似度权重及他们对物品的偏好,预测当前用户没有偏好的未涉及物品,计算得到一个排序的物品列表作为推荐。
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
train_x = np.array([[0.238,0,0.1905,0.1905,0.1905,0.1905],
[0,0.177,0,0.294,0.235,0.294],[0.2,0.16,0.12,0.12,0.2,0.2]])
y = np.array(['B','C','D'])
test_x = [[0.2174,0.2174,0.1304,0.0,0.2174,0.2174]]
model_neigh = KNeighborsClassifier(n_neighbors=3)
model_neigh.fit(train_x,y)
print(model_neigh.predict(test_x))
# 结果为:
['B']
因此,根据历史偏好,User A与User B更相似,而User A没有购买Item D,那么就将Item D推荐给User A。
2.5 Item CF原理
基于物品的协同过滤(Item-based Collaborative Filtering)算法是目前业界应用最多的算法,基于物品的C发的原理和基于用户的CF类似,只是在计算时采用物品之间的相似度,而不是从用户的角度,即基于用户对物品的偏好划分物品类型(聚类算法)找到最近邻物品(KNN近邻算法),然后将同类物品或相邻物品推荐给当前用户。计算角度,就是将所有用户对某个物品的偏好作为一个向量来计算物品之间的相似度,得到物品的相似度后,根据用户历史的偏好预测当前用户还没有偏好的物品,计算得到一个排序的物品列表作为推荐。
继续上面的例子,每个元素表示物品被某类User购买的概率,按列的加总值为1.非零值的元素表示某类User对某类物品的偏好,值越大表示偏好越强烈,相反0为无偏好,可以得到下表:
Item相似矩阵
User/Item | Item A | Item B | Item C | Item D | Item E | Item F |
---|---|---|---|---|---|---|
User A | 0.334 | 0.417 | 0.3 | 0 | 0.278 | 0.263 |
User B | 0.333 | 0 | 0.4 | 0 | 0.222 | 0.211 |
User C | 0 | 0.25 | 0 | 0.625 | 0.222 | 0.263 |
User D | 0.333 | 0.333 | 0.3 | 0.375 | 0.278 | 0.263 |
相应的算法如下:
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
train_x = np.array([[0.417,0.0,0.25,0.333],[0.3,0.4,0.0,0.3],
[0.0,0.0,0.625,0.375],[0.278,0.222,0.222,0.278],
[0.263,0.211,0.263,0.263]])
test_x = [[0.334,0.333,0.0,0.333]]
y_label = np.array(['B','C','D','E','F'])
model_neigh = KNeighborsClassifier(n_neighbors=3)
model_neigh.fit(train_x,y_label)
print(model_neigh.predict(test_x))
# 结果
['C']
因此对于Item A,根据所有用户的历史偏好,得出Item A 和Item C比较相似,可以将Item C推荐给喜欢Item A的用户。