我在使用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
我知道我的数据集中由字符串值(&#39;未知&#39;是其中之一)引起的此错误。
这让我很困惑,在我的理解中,函数cus_distance应该处理这些str值,而KNeighborsRegressor只使用我函数的返回值。
问:
*这是在KNN回归中使用自定义距离度量的正确方法吗?
*如果是,为什么我遇到这个例外?
*如果没有,那么正确的方法是什么?
答案 0 :(得分:4)
无论使用何种指标,Ball Tree和KD Tree都需要浮点数据。如果您的数据无法转换为浮点数,那么您将收到此类错误。
>>> 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
答案 1 :(得分:1)
谢谢@jakevdp scikit-learn支持Brute Force,Ball Tree和KD Tree,根据@jakevdp的回答,我唯一可以使用的是Brute Force algorighm,所以我的代码改为:
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的源代码,发现 this line 导致此错误:
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将尝试将所有值转换为float,“Unknown”会再次导致错误。
我认为这是一种错误,因为scikit的内置指标不支持混合类型的数据集,我编写了客户指标函数,但这一行仍然强制数据集为纯浮点类型。
正如此行上方的评论所述,检查工作应该由客户指标完成,所以我只是评论了这一行,重新加载这个模块,我的knn对象现在可以完美地工作了:)
ps:我正在努力将这一变化推向scikit-learn官方github回购。