Sklearn 凝聚聚类自定义亲和力
Sklearn Agglomerative Clustering Custom Affinity
我正在尝试使用具有自定义距离度量(即亲和力)的凝聚聚类,因为我想通过序列相似性对整数序列进行聚类,而不是像欧氏距离这样没有意义的东西。
我的数据看起来像这样
>> dat.values
array([[860, 261, 240, ..., 300, 241, 1],
[860, 840, 860, ..., 860, 240, 1],
[260, 860, 260, ..., 260, 220, 1],
...,
[260, 260, 260, ..., 260, 260, 1],
[260, 860, 260, ..., 840, 860, 1],
[280, 240, 241, ..., 240, 260, 1]])
我创建了以下相似度函数
def sim(x, y):
return np.sum(np.equal(np.array(x), np.array(y)))/len(x)
所以我只是 return 两个序列中的 % 匹配值与 numpy 并进行以下调用
cluster = AgglomerativeClustering(n_clusters=5, affinity=sim, linkage='average')
cluster.fit(dat.values)
但我收到一条错误消息
TypeError: sim() missing 1 required positional argument: 'y'
我不确定为什么会收到此错误;我认为该函数会将成对的行聚集在一起,以便传递每个必需的参数。
如有任何帮助,我们将不胜感激
通常的做法是将 affinity='precomputed
并拟合距离矩阵(参见此处的示例:https://gist.github.com/codehacken/8b9316e025beeabb082dda4d0654a6fa)
更新
在 sklearn.hierarchical.py (https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/cluster/hierarchical.py#L460) 中,您可以看到您的自定义亲和力必须仅获取 X(而非 y)作为输入。输入应该是 linkage_tree。所以,你需要重写你的 sim() 函数。
不过我觉得第一种方式更方便
'affinity'
作为可调用项需要单个输入 X
(这是您的特征或观察矩阵),然后调用其中所有点(样本)之间的距离。
因此您需要将方法修改为:
# Your method to calculate distance between two samples
def sim(x, y):
return np.sum(np.equal(np.array(x), np.array(y)))/len(x)
# Method to calculate distances between all sample pairs
from sklearn.metrics import pairwise_distances
def sim_affinity(X):
return pairwise_distances(X, metric=sim)
cluster = AgglomerativeClustering(n_clusters=5, affinity=sim_affinity, linkage='average')
cluster.fit(X)
或者您可以按照@avchauzov 的建议使用affinity='precomputed'
。为此,您必须在 fit()
中为您的观察传递预先计算的距离矩阵。类似于:
cluster = AgglomerativeClustering(n_clusters=5, affinity='precomputed', linkage='average')
distance_matrix = sim_affinity(X)
cluster.fit(distance_matrix)
注意:您指定了相似度而不是距离。因此,请确保您了解聚类在这里的工作方式。或者也许将您的相似度函数调整为 return 距离。类似于:
def sim(x, y):
# Subtracted from 1.0 (highest similarity), so now it represents distance
return 1.0 - np.sum(np.equal(np.array(x), np.array(y)))/len(x)
我正在尝试使用具有自定义距离度量(即亲和力)的凝聚聚类,因为我想通过序列相似性对整数序列进行聚类,而不是像欧氏距离这样没有意义的东西。
我的数据看起来像这样
>> dat.values
array([[860, 261, 240, ..., 300, 241, 1],
[860, 840, 860, ..., 860, 240, 1],
[260, 860, 260, ..., 260, 220, 1],
...,
[260, 260, 260, ..., 260, 260, 1],
[260, 860, 260, ..., 840, 860, 1],
[280, 240, 241, ..., 240, 260, 1]])
我创建了以下相似度函数
def sim(x, y):
return np.sum(np.equal(np.array(x), np.array(y)))/len(x)
所以我只是 return 两个序列中的 % 匹配值与 numpy 并进行以下调用
cluster = AgglomerativeClustering(n_clusters=5, affinity=sim, linkage='average')
cluster.fit(dat.values)
但我收到一条错误消息
TypeError: sim() missing 1 required positional argument: 'y'
我不确定为什么会收到此错误;我认为该函数会将成对的行聚集在一起,以便传递每个必需的参数。
如有任何帮助,我们将不胜感激
通常的做法是将 affinity='precomputed
并拟合距离矩阵(参见此处的示例:https://gist.github.com/codehacken/8b9316e025beeabb082dda4d0654a6fa)
更新 在 sklearn.hierarchical.py (https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/cluster/hierarchical.py#L460) 中,您可以看到您的自定义亲和力必须仅获取 X(而非 y)作为输入。输入应该是 linkage_tree。所以,你需要重写你的 sim() 函数。
不过我觉得第一种方式更方便
'affinity'
作为可调用项需要单个输入 X
(这是您的特征或观察矩阵),然后调用其中所有点(样本)之间的距离。
因此您需要将方法修改为:
# Your method to calculate distance between two samples
def sim(x, y):
return np.sum(np.equal(np.array(x), np.array(y)))/len(x)
# Method to calculate distances between all sample pairs
from sklearn.metrics import pairwise_distances
def sim_affinity(X):
return pairwise_distances(X, metric=sim)
cluster = AgglomerativeClustering(n_clusters=5, affinity=sim_affinity, linkage='average')
cluster.fit(X)
或者您可以按照@avchauzov 的建议使用affinity='precomputed'
。为此,您必须在 fit()
中为您的观察传递预先计算的距离矩阵。类似于:
cluster = AgglomerativeClustering(n_clusters=5, affinity='precomputed', linkage='average')
distance_matrix = sim_affinity(X)
cluster.fit(distance_matrix)
注意:您指定了相似度而不是距离。因此,请确保您了解聚类在这里的工作方式。或者也许将您的相似度函数调整为 return 距离。类似于:
def sim(x, y):
# Subtracted from 1.0 (highest similarity), so now it represents distance
return 1.0 - np.sum(np.equal(np.array(x), np.array(y)))/len(x)