Scikit网格搜索KNN回归中ValueError: 数组包含NaN或无穷大
我正在尝试使用Scikit learn实现网格搜索,以选择KNN回归的最佳参数。具体来说,我想做的是:
parameters = [{'weights': ['uniform', 'distance'], 'n_neighbors': [5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]}]
clf = GridSearchCV(neighbors.KNeighborsRegressor(), parameters)
clf.fit(features, rewards)
不幸的是,我遇到了一个错误:ValueError: 数组包含NaN或无穷大。
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/grid_search.pyc in fit(self, X, y, **params)
705 " The params argument will be removed in 0.15.",
706 DeprecationWarning)
--> 707 return self._fit(X, y, ParameterGrid(self.param_grid))
708
709
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/grid_search.pyc in _fit(self, X, y, parameter_iterable)
491 X, y, base_estimator, parameters, train, test,
492 self.scorer_, self.verbose, **self.fit_params)
--> 493 for parameters in parameter_iterable
494 for train, test in cv)
495
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.pyc in __call__(self, iterable)
515 try:
516 for function, args, kwargs in iterable:
--> 517 self.dispatch(function, args, kwargs)
518
519 self.retrieve()
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.pyc in dispatch(self, func, args, kwargs)
310 """
311 if self._pool is None:
--> 312 job = ImmediateApply(func, args, kwargs)
313 index = len(self._jobs)
314 if not _verbosity_filter(index, self.verbose):
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.pyc in __init__(self, func, args, kwargs)
134 # Don't delay the application, to avoid keeping the input
135 # arguments in memory
--> 136 self.results = func(*args, **kwargs)
137
138 def get(self):
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/grid_search.pyc in fit_grid_point(X, y, base_estimator, parameters, train, test, scorer, verbose, loss_func, **fit_params)
309 this_score = scorer(clf, X_test, y_test)
310 else:
--> 311 this_score = clf.score(X_test, y_test)
312 else:
313 clf.fit(X_train, **fit_params)
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/base.pyc in score(self, X, y)
320
321 from .metrics import r2_score
--> 322 return r2_score(y, self.predict(X))
323
324
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/metrics/metrics.pyc in r2_score(y_true, y_pred)
2181
2182 """
-> 2183 y_type, y_true, y_pred = _check_reg_targets(y_true, y_pred)
2184
2185 if len(y_true) == 1:
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/metrics/metrics.pyc in _check_reg_targets(y_true, y_pred)
59 Estimated target values.
60 """
---> 61 y_true, y_pred = check_arrays(y_true, y_pred)
62
63 if y_true.ndim == 1:
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.pyc in check_arrays(*arrays, **options)
231 else:
232 array = np.asarray(array, dtype=dtype)
--> 233 _assert_all_finite(array)
234
235 if copy and array is array_orig:
/Users/zikesjan/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.pyc in _assert_all_finite(X)
25 if (X.dtype.char in np.typecodes['AllFloat'] and not np.isfinite(X.sum())
26 and not np.isfinite(X).all()):
---> 27 raise ValueError("Array contains NaN or infinity.")
28
29
ValueError: Array contains NaN or infinity.
根据这个帖子,我已经尝试用下面这行代码替换上面的代码来进行拟合:
clf.fit(np.asarray(features).astype(float), np.asarray(rewards).astype(float))
然后根据这个帖子,我甚至尝试了这个:
scaler = preprocessing.StandardScaler().fit(np.asarray(features).astype(float))
transformed_features = scaler.transform(np.asarray(features).astype(float))
clf.fit(transformed_features, rewards)
但不幸的是,还是没有成功。所以我想问问有没有人知道问题可能出在哪里,以及我该如何让我的代码正常工作。
非常感谢大家的帮助。
编辑:
我发现当我只使用以下参数时,并不会出现这个错误:
parameters = [{'weights': ['uniform'], 'n_neighbors': [5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]}]
所以看起来问题出在当weights=distance时。有没有人知道为什么会这样?
关于这个问题,我还遇到了一个新问题,具体可以在这里询问。
编辑 2:
如果我在调试模式下运行我的代码,我会收到以下警告:
/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sklearn/neighbors/regression.py:160: RuntimeWarning: invalid value encountered in divide
y_pred[:, j] = num / denom
所以显然是出现了除以零的问题。那么我的问题是,为什么在regression.py的第160行,Scikit会进行除以0的操作呢?
2 个回答
我在使用scikit-learn的KNN回归时遇到了同样的问题。我当时设置了权重为'distance',结果在计算预测值时出现了无限大的值(但在训练KNN模型时,即学习合适的KD树或球树时没有问题)。我改成了权重为'uniform',程序就顺利完成了,这说明之前的权重设置是问题所在。如果你想使用基于距离的权重,建议你提供一个自定义的权重函数,确保在距离为零时不会出现无限大的情况,就像eickenberg的回答中提到的那样。
除了你已经尝试过的方法,你还可以看看
import numpy as np
features = np.nan_to_num(features)
rewards = np.nan_to_num(rewards)
这段代码会把你数组里所有不是数字的值都设置成 0
,这样至少可以让你的算法运行起来,除非错误发生在算法内部。要确保你的数据里没有太多非数字的条目,因为把它们都变成0可能会导致你的估算出现奇怪的偏差。
如果不是这种情况,而且你使用的是 weights='distance'
,那么请检查一下你的训练样本是否有完全相同的。这会导致在计算反距离时出现除以零的情况。
如果反距离导致了除以零的问题,你可以通过使用你自己的距离函数来解决,比如说
def better_inv_dist(dist):
c = 1.
return 1. / (c + dist)
然后使用 'weights': better_inv_dist
。你可能需要把常量 c
调整到合适的范围。无论如何,只要 c > 0
,就能避免除以零的问题。