我怎样才能为KNeighboursRegressor使用自定义距离指标?

时间:2013-12-18 10:15:32

标签: python scikit-learn

我在使用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回归中使用自定义距离度量的正确方法吗?  *如果是,为什么我遇到这个例外?
 *如果没有,那么正确的方法是什么?

2 个答案:

答案 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回购。