scikit中的分类器 - 学习处理nan / null

时间:2015-05-19 05:02:35

标签: python pandas machine-learning scikit-learn nan

我想知道在scikit-learn中是否存在处理nan / null值的分类器。我以为随机森林回归器会处理这个问题但我在拨打predict时出错了。

X_train = np.array([[1, np.nan, 3],[np.nan, 5, 6]])
y_train = np.array([1, 2])
clf = RandomForestRegressor(X_train, y_train)
X_test = np.array([7, 8, np.nan])
y_pred = clf.predict(X_test) # Fails!

我是否可以使用缺少值的任何scikit-learn算法调用预测?

修改 现在我想到这一点,这是有道理的。这在培训期间不是问题,但是当您预测变量为空时如何分支?也许你可以分开两种方式并平均结果?只要距离函数忽略空值,似乎k-NN应该可以正常工作。

编辑2(年龄更大,更聪明) 一些gbm库(例如xgboost)正是为了这个目的而使用三元树而不是二叉树:2个孩子用于是/否决定,1个孩子用于缺失决策。 sklearn是using a binary tree

4 个答案:

答案 0 :(得分:25)

我做了一个示例,其中包含训练和测试集中的缺失值

我刚刚选择了使用SimpleImputer类替换缺失数据的策略。还有其他策略。

from __future__ import print_function

import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer


X_train = [[0, 0, np.nan], [np.nan, 1, 1]]
Y_train = [0, 1]
X_test_1 = [0, 0, np.nan]
X_test_2 = [0, np.nan, np.nan]
X_test_3 = [np.nan, 1, 1]

# Create our imputer to replace missing values with the mean e.g.
imp = SimpleImputer(missing_values=np.nan, strategy='mean')
imp = imp.fit(X_train)

# Impute our data, then train
X_train_imp = imp.transform(X_train)
clf = RandomForestClassifier(n_estimators=10)
clf = clf.fit(X_train_imp, Y_train)

for X_test in [X_test_1, X_test_2, X_test_3]:
    # Impute each test item, then predict
    X_test_imp = imp.transform(X_test)
    print(X_test, '->', clf.predict(X_test_imp))

# Results
[0, 0, nan] -> [0]
[0, nan, nan] -> [0]
[nan, 1, 1] -> [1]

答案 1 :(得分:4)

简短答案

有时缺少值根本不适用。估算它们是没有意义的。在这些情况下,您应该使用可以处理缺失值的模型。 Scitkit-learn的模型无法处理缺失值。 XGBoost可以。


关于scikit-learn和XGBoost的更多信息

this article中所述,scikit-learn的决策树和KNN算法不够健壮(yet,无法处理缺失值。如果插补没有意义,请不要这样做。

在插补没有意义的情况下考虑情景。

  

请记住,这是一个虚构的例子

考虑包含行汽车(“ Danho Diesel”,“ Estal Electric”,“ Hesproc Hybrid”)和列及其属性的列(重量,最高速度)的数据集,加速度,功率输出,二氧化硫排放量,范围)。

电动汽车不会产生废气-因此, Estal Electric 二氧化硫排放量应为NaN值(缺失)。您可能会争辩说应将其设置为0-但电动汽车无法产生二氧化硫。估算值会破坏您的预测。

this article中所述,scikit-learn的决策树和KNN算法不够健壮(yet,无法处理缺失值。如果插补没有意义,请不要这样做。

答案 2 :(得分:2)

如果使用的是DataFrame,则可以使用fillna。在这里,我用该列的平均值替换了丢失的数据。

df.fillna(df.mean(), inplace=True)

答案 3 :(得分:0)

对于位于GeoTIFF图像边缘的NoData(显然无法使用相邻像素的平均值进行插值),我用几行代码将其屏蔽。请注意,这是在一个频段(Sentinel 1图像的VH频段,首先转换为数组)上执行的。在对初始图像执行随机森林分类之后,我执行了以下操作:

image[image>0]=1.0
image[image==0]=-1.0
RF_prediction=np.multiply(RF_prediction,image)
RF_prediction[RF_prediction<0]=-9999.0 #assign a NoData value

保存时,不要忘记分配一个NoData值:

class_ds = gdal.GetDriverByName('GTiff').Create('RF_classified.tif',img_ds.RasterXSize,\
                                              img_ds.RasterYSize,1,gdal.GDT_Float32)

RF_ds.SetGeoTransform(img_ds.GetGeoTransform())    
srs = osr.SpatialReference()
srs.ImportFromEPSG(32733)                
RF_ds.SetProjection(srs.ExportToWkt()) # export coords to file
RF_ds.GetRasterBand(1).SetNoDataValue(-9999.0) #set NoData value
RF_ds.GetRasterBand(1).WriteArray(RF_prediction)
RF_ds.FlushCache()                     # write to disk
RF_ds = None