处理kNN中的不完整数据(数据稀疏性)

时间:2012-05-06 17:33:44

标签: algorithm machine-learning classification sparse-matrix knn

我正在尝试使用knn创建一个简单的推荐系统。

假设我有一张桌子:

User | Book1 | Book2 | Book3 | Book4 | Book5 | Book6 | Book7 |
1    | 5     | ?     | 3     | ?     | 4     | 3     | 2     |
2    | 3     | 4     | ?     | 2     | 3     | 4     | 2     |
3    | 4     | 2     | 1     | ?     | ?     | 3     | 3     |
4    | 2     | 5     | 3     | ?     | 4     | 1     | 1     |
5    | 1     | 1     | 4     | 3     | 1     | ?     | 1     |
6    | 5     | 2     | 5     | 4     | 4     | 2     | ?     |

因此,如果要找到用户1的可能分数,我认为只是将用户1读取的书与其他用户的绝对差异。然后我会利用这个差异来找出该列表中哪个用户与用户1“最接近”。但在实际情况中,会有更多的?/未知分数。所以在使用knn时如何处理这些未知分数?

我没有任何代码,因为我还没有真正理解如何实现它。

感谢任何帮助!

4 个答案:

答案 0 :(得分:9)

您没有“未知功能”,您的数据点不完整。

这实际上是kNN中众所周知的问题,并且有一个彻底验证的模式来处理它。

虽然问题实际上是一个“不完整的数据”问题,但在kNN上下文中,它常常(通常?)被称为稀疏性问题。

在实践中,构建knn模型中的稀疏性问题可能除了有效存储/检索构成模型的数据之外,kNN的关键。

例如,考虑Amazon.com的推荐引擎,其中产品评级为包含的用户功能和包含的用户,为了使这个矩阵100%完整,每个亚马逊客户都必须购买和审查亚马逊销售的每一个产品。该矩阵的实际稀疏度必须> 95%。

最常见的技术(据我所知仍然是最先进的技术)被称为 NNMA ,或非负矩阵近似。这种技术通常也被称为错误地为NNMF,其中F代表因子分解。 (NNMA基于分解技术,但结果不是原始数据矩阵的因素。)我提到这一点,因为这个替代术语虽然不正确但被广泛使用,所以我将其包含在我的搜索引擎查询中。

从本质上讲,这种技术可用于从矩阵中删除稀疏性,或换句话说,填充缺失的单元格(即,R行的客户尚未复制C列的产品)。

您可以找到nnma的完整实现,包括Albert Au Yeung Ching-man's blog中的附带教程(在python + numpy中)。

或者,有几个python包(可通过PyPI获得)包含NNMA的打包代码。我只使用了其中一个PyMF,您可以在Google代码中找到它。

这样你就可以看到NNMA如何发挥其魔力,这里是我在python + NumPy中简单但完整的NNMA实现

import numpy as NP

def cf(q, v):
    """ the cost function """
    qv = (q - v)**2
    return NP.sum(NP.sum(qv, axis=0))


def nnma(d, max_iter=100):
    x, y = d.shape
    z = y
    w = NP.random.rand(x, y)
    h = NP.random.rand(y, z)
    for i in range(max_iter):
        wh = NP.dot(w, h)
        cost = cf(d, wh)
        if cost == 0: 
            break
        hn = NP.dot(w.T, d)
        hd = NP.dot(NP.dot(w.T, w), h)
        h *= hn/hd
        wn = NP.dot(d, h.T)
        wd = NP.dot(NP.dot(w, h), h.T)
        w *= wn/wd
    return NP.dot(w, h)

要使用此 NNMA函数, 只需为每个丢失的单元格传入一个“0”的二维数组(矩阵)(换句话说,就是数据矩阵,每个缺失值插入一个“0”:

>>> d    # the original (sparse) data matrix with missing cells denoted by "0"s

  array([[ 7.,  0.,  4.,  7.,  0.,  1.],
         [ 3.,  9.,  7.,  3.,  1.,  7.],
         [ 4.,  4.,  3.,  7.,  3.,  9.],
         [ 4.,  8.,  0.,  9.,  2.,  1.],
         [ 6.,  3.,  9.,  5.,  9.,  3.],
         [ 6.,  1.,  4.,  4.,  1.,  0.],
         [ 0.,  4.,  8.,  6.,  0.,  5.],
         [ 9.,  0.,  6.,  0.,  5.,  2.],
         [ 6.,  8.,  4.,  6.,  3.,  7.],
         [ 3.,  6.,  3.,  8.,  7.,  2.]])

>>> d1 = nnma(d)     # call nnma, passing in the original data matrix

>>> d1    # the approximated data matrix with all missing values populated

   array([[ 6.998,  0.29 ,  3.987,  7.008,  0.292,  0.796],
          [ 2.989,  8.92 ,  6.994,  3.02 ,  1.277,  7.053],
          [ 4.007,  4.496,  2.999,  7.01 ,  3.107,  8.695],
          [ 4.005,  8.019,  0.254,  9.002,  1.917,  0.89 ],
          [ 5.998,  3.014,  9.001,  4.991,  8.983,  3.052],
          [ 5.992,  1.077,  4.007,  3.976,  0.753,  0.464],
          [ 0.346,  3.436,  7.993,  5.988,  0.194,  5.355],
          [ 9.001,  0.124,  5.997,  0.375,  5.02 ,  1.867],
          [ 6.   ,  7.994,  3.998,  6.   ,  2.999,  7.009],
          [ 2.995,  6.022,  3.001,  7.987,  6.939,  2.185]])

正如您所看到的,结果并不太糟糕,特别是对于非常简单的实现。填充所有缺失的项目,其余值非常接近原始数据矩阵的对应值,例如,列0,原始数据矩阵中的行0为7.0,近似值为6.998。 / p>

答案 1 :(得分:4)

您缺少的是测量距离的方法。 Pearson相关性是最广泛使用的方法之一。余弦距离是另一个。 L1距离(差异的绝对值之和)通常不会给出好的结果。

如果你谷歌,你会发现根据你使用的相似距离处理缺失值的推荐方法是什么。例如,在Pearson中,仅使用由两个用户共同评定的书籍来测量相关性,因此简单地忽略缺失值。这是有道理的,好像两个用户阅读的一小部分书是共同的,很可能意味着有不同的口味。在余弦距离中,缺失值可以假设为零。

另一种常用方法是估算缺失值。例如,您可以首先使用Pearson查找书籍之间的相似性,然后为每个人预测缺失的评级。

答案 2 :(得分:2)

KNN通常对#features敏感。在现实生活中,我希望你会有更多的书。

我会尝试更改功能空间:不是每个文档都有一个功能,也许值得调查使用书籍列表作为功能。

Feature1 = { books with score 1 }
Feature2 = { books with score 2 }
...

现在,您可以为每个功能定义距离 - 可以在两个用户的每两个列表之间使用recall and precision

这种方法的另一个优点是你可以很容易地为功能赋予权重 - 也许排名为5的书籍列表比用3位排名的书籍更具信息量?

缺点很明显,如果用户A,B用4,5排名一本书,你将无法获得任何提升 - 但是也可以通过添加另一个功能来解决,比较两个用户之间的这些列表..

免责声明:我从来没有测试过这种方法,我也不知道它会如何表现 - 但我认为这是一种值得研究的方法。我认为没有好的方法来确定这个建议是否会产生良好的结果,除了经验测试,可以使用训练集中的cross-validation来完成。

答案 3 :(得分:0)

我的建议是您使用奇异值分解(SVD)对数据集执行降级。这将通过有效减少每本书提供的功能数量来填补这些缺失值。这与潜在语义分析非常相似,请查阅。