如何在不进行插补的情况下处理KNN中的丢失数据?

时间:2019-08-13 22:18:36

标签: python scikit-learn knn

我正在做一个需要使用sklearn库进行KNN回归的作业-但是,如果我缺少数据(假设它是随机丢失的),则不应该推论它。相反,我必须将其保留为null,并在我的代码帐户中以某种方式使其忽略一个值为null的比较。

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

sklearn库是否有可能?

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

2 个答案:

答案 0 :(得分:4)

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

  1. 忽略所有包含空值的列:我想这不是您要问的问题,因为这更多的是数据预处理步骤,并不是sklearn真正独有的。即使在纯python中,也只需搜索包含null的列索引,然后使用过滤掉的那些索引构建新的数据集。
  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])

如果您要回归到的输出中存在空值,该怎么办仍然是一个悬而未决的问题,但是问题陈述并没有听起来像是您要解决的问题。

答案 1 :(得分:0)

这应该有效:

import pandas as pd

df = pd.read_csv("your_data.csv")

df.dropna(inplace = True)