【问题标题】:Handling Incomplete Data (Data Sparsity) in kNN在 kNN 中处理不完整数据(数据稀疏性)
【发布时间】:2012-05-15 09:44:41
【问题描述】:

我正在尝试使用 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“最接近”。但在现实世界中,会有更多的 ?/unknown 分数。那么在使用knn的时候如何处理那些未知的分数呢?

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

感谢任何帮助!

【问题讨论】:

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


    【解决方案1】:

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

    我会尝试更改特征空间:与其为每个文档都设置一个特征,不如使用书籍列表作为特征进行研究。

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

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

    此方法的另一个优点是您可以轻松地赋予特征权重 - 排名为 5 的书籍列表可能比排名为 3 的书籍列表提供更多信息?

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

        你没有“未知特征”,你有不完整的数据点。

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

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

        在实践中,构建 kNN 模型的稀疏性问题是 kNN 的症结所在,除了对构成模型的数据的有效存储/检索可能例外。

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

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

        本质上,这种技术可用于消除矩阵中的稀疏性,或者换一种说法,填充缺失的单元格(即 R 行的客户尚未审查 C 列的乘积)。

        您可以在Albert Au Yeung Ching-man's blog 中找到完整的 nnma 实现,包括随附的教程(在 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 函数, 只需传入一个 2D 数组(矩阵),其中每个缺失的单元格都带有一个“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。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-05-12
          • 2011-06-13
          • 2011-12-27
          • 2016-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多