在使用knn回归模型时,我正在尝试应用自己的自定义距离度量函数。我的数据集是名义、有序、数字和二进制类型的字段的混合体
法典:
def cus_distance(array1, array2, **kwargs):
# calculate the distance, return a float
pass
knn = neighbors.KNeighborsRegressor(weights='distance', metric=cus_distance)
# train_data is a pandas dataframe obj
knn.fit(train_data.ix[:, fields_list], train_data['time_costs'])
最后一行将导致异常:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-284-04520b227b8a> in <module>()
----> 1 knn.fit(train_data.ix[:, fields_list], train_data['time_costs'])
/usr/local/lib/python2.7/dist-packages/sklearn/neighbors/base.pyc in fit(self, X, y)
587 X, y = check_arrays(X, y, sparse_format="csr")
588 self._y = y
--> 589 return self._fit(X)
590
591
/usr/local/lib/python2.7/dist-packages/sklearn/neighbors/base.pyc in _fit(self, X)
214 self._tree = BallTree(X, self.leaf_size,
215 metric=self.effective_metric_,
--> 216 **self.effective_metric_kwds_)
217 elif self._fit_method == 'kd_tree':
218 self._tree = KDTree(X, self.leaf_size,
/usr/local/lib/python2.7/dist-packages/sklearn/neighbors/ball_tree.so in sklearn.neighbors.ball_tree.BinaryTree.__init__ (sklearn/neighbors/ball_tree.c:7983)()
/usr/local/lib/python2.7/dist-packages/numpy/core/numeric.pyc in asarray(a, dtype, order)
318
319 """
--> 320 return array(a, dtype, copy=False, order=order)
321
322 def asanyarray(a, dtype=None, order=None):
ValueError: could not convert string to float: Unknown
我知道这个错误是由我的数据集中的字符串值("未知"是其中之一)引起的。
这让我感到困惑,在我的理解中,函数cus_distance应该处理这些str值,而KNeighborsRegressor只是使用我的函数的返回值。
问:
* 这是在 KNN 回归中使用自定义距离度量的正确方法吗?
* 如果是,为什么我遇到这个例外?
* 如果没有,正确的方法是什么?
球树和 KD 树需要浮点数据,无论使用何种指标。 如果您的数据无法转换为浮点数,那么您将收到此类错误。
>>> import numpy as np
>>> data = [1, "Unknown", 2]
>>> np.asarray(data, dtype=float)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
----> 1 np.asarray(data, dtype=float)
ValueError: could not convert string to float: Unknown
谢谢@jakevdp。
scikit-learn 支持蛮力、球树和 KD 树,根据@jakevdp的回答,我唯一能用的就是蛮力算法,所以我的代码改为:
knn = neighbors.KNeighborsRegressor(weights='distance', metric=cus_distance, algorithm='brute')
knn.fit(train_data.ix[:, fields_list], train_data['time_costs'])
这次不会再引发错误了,谢谢 jakevdp!
但是当我尝试使用这个knn对象时,新的问题来了:
knn.predict(check_data.ix[:, fields_list])
这将在我的问题中导致相同的错误。所以我查看了scikit-learn的源代码,发现这一行导致此错误:
elif callable(metric):
# Check matrices first (this is usually done by the metric).
X, Y = check_pairwise_arrays(X, Y)
n_x, n_y = X.shape[0], Y.shape[0]
函数check_pairwise_arrays将尝试将所有值转换为浮点数,"未知"再次导致错误。
我认为这是一个错误,因为scikit的内置指标不支持数据集的混合类型,我写了一个客户指标函数,但这行仍然强制数据集为纯浮点类型。
正如这一行上面的评论所说,检查工作应该由客户指标完成,所以我只是评论了这一行,重新加载这个模块,我的knn对象现在可以完美地工作:)
ps:我正在努力将此更改推送到 scikit-learn 官方 github 存储库。