【问题标题】:How to handle missing data in KNN without imputing?如何在不插补的情况下处理 KNN 中的缺失数据?
【发布时间】:2019-08-15 06:50:45
【问题描述】:

我正在执行一项任务,我需要使用 sklearn 库进行 KNN 回归 - 但是,如果我丢失了数据(假设它是随机丢失的),我不应该对其进行估算。相反,我必须将其保留为空,并且在我的代码中以某种方式使其忽略一个值为空的比较。

例如,如果我的观察结果是 (1, 2, 3, 4, null, 6) 和 (1, null, 3, 4, 5, 6),那么我将忽略第二个和第五个观察结果。

sklearn 库可以做到这一点吗?

ETA:我只会删除空值,但我不知道他们将要测试的数据是什么样的,它最终可能会删除 0% 到 99% 的数据。

【问题讨论】:

    标签: python scikit-learn knn


    【解决方案1】:

    这在一定程度上取决于您到底想做什么。

    1. 忽略所有带有空值的列:我想这不是您要问的,因为这更多是数据预处理步骤,并不是 sklearn 真正独有的。即使在纯 Python 中,也只需搜索包含空值的列索引,然后构造一个过滤掉这些索引的新数据集。
    2. 在向量比较中忽略空值:这实际上很有趣。本质上,您是在说[1, 2, 3, 4, None, 6][1, None, 3, 4, 5, 6] 之间的距离是sqrt(1*1 + 3*3 + 4*4 + 6*6)。在这种情况下,您需要某种 sklearn 支持的自定义指标。不幸的是,您无法在 KNN fit() 方法中输入空值,因此即使使用自定义指标,您也无法完全得到您想要的。解决方案是预先计算距离。例如:
    from math import sqrt, isfinite
    
    X_train = [
        [1, 2, 3, 4, None, 6],
        [1, None, 3, 4, 5, 6],
    ]
    y_train = [3.14, 2.72]  # we're regressing something
    
    def euclidean(p, q):
      # Could also use numpy routines
      return sqrt(sum((x-y)**2 for x,y in zip(p,q)))
    
    def is_num(x):
      # The `is not None` check needs to happen first because of short-circuiting
      return x is not None and isfinite(x)
    
    def restricted_points(p, q):
      # Returns copies of `p` and `q` except at coordinates where either vector
      # is None, inf, or nan
      return tuple(zip(*[(x,y) for x,y in zip(p,q) if all(map(is_num, (x,y)))]))
    
    def dist(p, q):
      # Note that in this form you can use any metric you like on the
      # restricted vectors, not just the euclidean metric
      return euclidean(*restricted_points(p, q))
    
    dists = [[dist(p,q) for p in X_train] for q in X_train]
    knn = KNeighborsRegressor(
        n_neighbors=1,  # only needed in our test example since we have so few data points
        metric='precomputed'
    )
    knn.fit(dists, y_train)
    
    X_test = [
        [1, 2, 3, None, None, 6],
    ]
    # We tell sklearn which points in the knn graph to use by telling it how far
    # our queries are from every input. This is super inefficient.
    predictions = knn.predict([[dist(q, p) for p in X_train] for q in X_test])
    

    如果您要回归的输出中有空值,仍然存在一个悬而未决的问题,但您的问题陈述并没有让人觉得这对您来说是个问题。

    【讨论】:

    • 这正是我要找的!澄清一下,data 是 X_train,outputs 是 y_train,query_data 是 X_test?
    • 谢谢,但我在 knn.fit 上遇到错误:ValueError: Input contains NaN, infinity or a value too large for dtype('float64'). 我完全粘贴了所有内容,并将我的代码添加到原始问题中。
    • 我搞砸了距离方程。您可能正在取负值的平方根。一秒。
    • 出色的工作,谢谢。但是,由于 dist 中仍有空值,因此在拟合时会引发错误。我只是错过了一步吗?
    • 不一定。这取决于您如何加载数据。在我上面定义的dist(p, q) 函数中,它假定我们要排除的唯一元素值是None。如果您正在使用 pandas 或 numpy 或其他一些东西,例如从 csv 读取数据,那么您可能有 NaN 值或类似的东西仍然会导致问题。
    【解决方案2】:

    这应该可行:

    import pandas as pd
    
    df = pd.read_csv("your_data.csv")
    
    df.dropna(inplace = True) 
    

    【讨论】:

    • 谢谢!唯一的问题是我不知道他们在提交后测试我的代码时数据会是什么样子,所以可能有 40% 的数据丢失。有没有其他办法解决这个问题?
    • 确实,如果您删除空值,您可能会丢失有价值的数据。也许用平均值或中值替换它会更好
    猜你喜欢
    • 2014-10-19
    • 2012-04-30
    • 1970-01-01
    • 2020-02-21
    • 2019-03-05
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多