【问题标题】:sklearn clustering with custom metric: pairwise_distances throwing error使用自定义指标进行 sklearn 聚类:pairwise_distances 抛出错误
【发布时间】:2019-11-16 16:52:26
【问题描述】:

我想使用我自己的指标对空间数据集进行聚类。数据以数据帧中的(x,y) 值对的形式出现,其中每组对都有一个id。就像在下面的例子中,我有三组点:

import pandas as pd 
import numpy as np

df = pd.DataFrame({'id': [1] * 4 + [2] * 5 + [3] * 3, 
                   'x': np.random.random(12),
                   'y': np.random.random(12)}) 
df['xy'] = df[['x','y']].apply(lambda row: [row['x'],row['y']], axis = 1)

这是我想使用的距离函数:

from scipy.spatial.distance import directed_hausdorff
def some_distance(u, v):
    return max(directed_hausdorff(u, v)[0], directed_hausdorff(v, u)[0])

此函数计算Hausdorff distance,即n 维空间的两个子集uv 之间的距离。就我而言,我想使用这个距离函数来聚类真实平面的子集。在上面的数据中,有三个这样的子集(ids 从 1 到 3)所以得到的距离矩阵应该是 3x3。

我对聚类步骤的想法是将sklearn.cluster.AgglomerativeClustering 与预先计算的指标一起使用,而我又想使用sklearn.metrics.pairwise import pairwise_distances 进行计算。

from sklearn.metrics.pairwise import pairwise_distances
def to_np_array(col):
    return np.array(list(col.values))
X = df.groupby('id')['xy'].apply(to_np_array).as_matrix()
m = pairwise_distances(X, X, metric=some_distance)

但是,最后一行给了我一个错误:

ValueError: setting an array element with a sequence.

但是,调用some_distance(X[1], X[2]) 可以正常工作。 我的直觉是X 需要采用不同的格式才能使pairwise_distances 工作。关于如何完成这项工作或如何自己计算矩阵以便我可以将其粘贴到sklearn.cluster.AgglomerativeClustering 的任何想法?

错误堆栈是

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-e34155622595> in <module>
     12 def some_distance(u, v):
     13     return max(directed_hausdorff(u, v)[0], directed_hausdorff(v, u)[0])
---> 14 m = pairwise_distances(X, X, metric=some_distance)

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\metrics\pairwise.py in pairwise_distances(X, Y, metric, n_jobs, **kwds)
   1430         func = partial(distance.cdist, metric=metric, **kwds)
   1431 
-> 1432     return _parallel_pairwise(X, Y, func, n_jobs, **kwds)
   1433 
   1434 

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\metrics\pairwise.py in _parallel_pairwise(X, Y, func, n_jobs, **kwds)
   1065 
   1066     if effective_n_jobs(n_jobs) == 1:
-> 1067         return func(X, Y, **kwds)
   1068 
   1069     # TODO: in some cases, backend='threading' may be appropriate

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\metrics\pairwise.py in _pairwise_callable(X, Y, metric, **kwds)
   1079     """Handle the callable case for pairwise_{distances,kernels}
   1080     """
-> 1081     X, Y = check_pairwise_arrays(X, Y)
   1082 
   1083     if X is Y:

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\metrics\pairwise.py in check_pairwise_arrays(X, Y, precomputed, dtype)
    106     if Y is X or Y is None:
    107         X = Y = check_array(X, accept_sparse='csr', dtype=dtype,
--> 108                             warn_on_dtype=warn_on_dtype, estimator=estimator)
    109     else:
    110         X = check_array(X, accept_sparse='csr', dtype=dtype,

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\utils\validation.py in check_array(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, warn_on_dtype, estimator)
    525             try:
    526                 warnings.simplefilter('error', ComplexWarning)
--> 527                 array = np.asarray(array, dtype=dtype, order=order)
    528             except ComplexWarning:
    529                 raise ValueError("Complex data not supported\n"

C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\numeric.py in asarray(a, dtype, order)
    536 
    537     """
--> 538     return array(a, dtype, copy=False, order=order)
    539 
    540 

ValueError: setting an array element with a sequence.

【问题讨论】:

  • 该错误是否包含回溯?告诉我们Xsklearn 和您的 some_distance 可能需要 numpy 数组,或者可以通过像 np.asarray(X) 这样的简单调用将其制成数组的对象。我不认为它对pandas 结构有特殊的了解。
  • 谢谢@hpaulj。当我使用as_matrix()X 更改为numpy.ndarray 时,也会发生同样的错误。我已经包含了上面的错误堆栈。我开始怀疑“pairwise_distances”可能无法处理包含比实际空间中的点更复杂的东西的数组(即使你传入了一个距离函数,它会为这些复杂的东西产生距离)。

标签: python pandas numpy scikit-learn


【解决方案1】:

试试这个....

import numpy as np
import pandas as pd
from scipy.spatial.distance import directed_hausdorff
from sklearn.metrics.pairwise import pairwise_distances
from sklearn.cluster import AgglomerativeClustering

df = pd.DataFrame({'id': [1] * 4 + [2] * 5 + [3] * 3, 'x':
np.random.random(12), 'y': np.random.random(12)}) 
df['xy'] = df[['x','y']].apply(lambda row: [row['x'],row['y']], axis = 1)
df.groupby('id')['xy'].apply(to_np_array)


def some_distance(u, v):
    return max(directed_hausdorff(u, v)[0], directed_hausdorff(v, u)[0])


def to_np_array(col):
    return np.array(list(col.values))


X = df.groupby('id')['xy'].apply(to_np_array)
d = np.zeros((len(X),len(X)))

for i, u in enumerate(X):
    for j, v in list(enumerate(X))[i:]:
        d[i,j] = some_distance(u,v)
        d[j,i] = d[i,j]

现在,当您打印 d 时,您会得到这个..

array([[0.        , 0.58928274, 0.40767213],
   [0.58928274, 0.        , 0.510095  ],
   [0.40767213, 0.510095  , 0.        ]])

对于聚类...

cluster = AgglomerativeClustering(n_clusters=2, affinity='precomputed', linkage = 'average')
cluster.fit(d)

希望这会有所帮助!

【讨论】:

  • 澄清一下 - Hausdorff 是一个在(在我的情况下)二维真实空间的子集上运行的集合度量。这些子集作为不同长度的数组传入(上面代码中的uv)。在我的示例中,有三组(ids 从 1 到 3)所以任何距离矩阵都应该是 3x3。正如我上面提到的some_distance(X[1], X[2]) 工作得很好,所以我不清楚你为什么要改变距离函数,以及为什么一个 4x4 矩阵是有意义的。
  • pairwise_distance 的文档说它需要输入X,它的形状是` [n_samples_a, n_features] `,但是你输入了一个系列,每个元素都是一个特征矩阵,同样@987654331 @ 是一个可调用对象,它在每对实例(行)上被调用,因此您的代码将无法根据您的需要运行。相反,您可以像我在答案中所做的那样编写一个简单的 for 循环并计算距离。
  • 谢谢。对于以后可能遇到此问题的任何人 - 这就是您将距离矩阵转换为 sklearn.cluster.AgglomerativeClustering 的方法:只需运行 cluster = AgglomerativeClustering(n_clusters=2, affinity='precomputed', linkage = 'average'); cluster.fit(d)
  • 顺便说一句,我添加了距离矩阵计算以考虑到它是对称的。
【解决方案2】:

如果您显示一些变量会有所帮助。幸运的是,您提供了足够的代码来运行它。例如数据框:

In [9]: df                                                                                                      
Out[9]: 
    id         x         y                                          xy
0    1  0.428437  0.267264   [0.42843730501201727, 0.2672637429997736]
1    1  0.944687  0.023323  [0.9446872371859233, 0.023322969159167317]
2    1  0.091055  0.683154   [0.09105472832178496, 0.6831542985617349]
3    1  0.474522  0.313541    [0.4745222021519122, 0.3135405569298565]
4    2  0.835237  0.491541    [0.8352366339973815, 0.4915408434083248]
5    2  0.905918  0.854030    [0.9059178939221513, 0.8540297797160584]
6    2  0.182154  0.909656   [0.18215390836391654, 0.9096555360282939]
7    2  0.225270  0.522193   [0.22527013482912195, 0.5221926076838651]
8    2  0.924208  0.858627    [0.9242076604008371, 0.8586274362498842]
9    3  0.419813  0.634741   [0.41981292371175905, 0.6347409684931891]
10   3  0.954141  0.795452    [0.9541413559045294, 0.7954524369652217]
11   3  0.896593  0.271187    [0.8965932351250882, 0.2711872631673109]

还有你的X

In [10]: X                                                                                                      
Out[10]: 
array([array([[0.42843731, 0.26726374],
       [0.94468724, 0.02332297],
       [0.09105473, 0.6831543 ],
       [0.4745222 , 0.31354056]]),
       array([[0.83523663, 0.49154084],
       [0.90591789, 0.85402978],
       [0.18215391, 0.90965554],
       [0.22527013, 0.52219261],
       [0.92420766, 0.85862744]]),
       array([[0.41981292, 0.63474097],
       [0.95414136, 0.79545244],
       [0.89659324, 0.27118726]])], dtype=object)

这是一个 (3,) 对象数组 - 实际上是 3 个二维数组的列表,具有不同的大小 ((3,2),(5,2),(4,2))。这是每个组的一个数组。

pairwise 应该如何将其提供给您的距离代码? pairwise docs 说 X 应该是一个 (n,m) 数组 - n 个样本,m 个特征。您的 X 不符合该描述!

错误可能是由于尝试从X 生成浮点数组时产生的:

In [12]: np.asarray(X,dtype=float)                                                                              
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-12-a6e08bb1590c> in <module>
----> 1 np.asarray(X,dtype=float)

/usr/local/lib/python3.6/dist-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    536 
    537     """
--> 538     return array(a, dtype, copy=False, order=order)
    539 
    540 

ValueError: setting an array element with a sequence.

【讨论】:

  • 谢谢。澄清一下 - 所以X 需要是一个(n,m) 浮点数组?或者它也可以是some_other_object(n,1) 数组,然后我传入一个可以计算some_other_objects 距离的距离函数?
猜你喜欢
  • 2020-01-21
  • 1970-01-01
  • 2019-05-19
  • 2018-12-01
  • 2019-03-26
  • 1970-01-01
  • 2018-03-14
  • 2020-12-28
  • 2017-03-31
相关资源
最近更新 更多