Склеарн Агломеративная кластеризация Custom Affinity - PullRequest
0 голосов
/ 19 декабря 2018

Я пытаюсь использовать агломерационную кластеризацию с пользовательской метрикой расстояния (то есть сродством), поскольку я хотел бы кластеризовать последовательность целых чисел по сходству последовательностей, а не что-то вроде евклидова расстояния, которое не имеет смысла.

Мои данные выглядят примерно так

>> 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)

Так что я просто возвращаю значения% соответствия в двух последовательностяхс numpy и сделайте следующий вызов

cluster = AgglomerativeClustering(n_clusters=5, affinity=sim, linkage='average')
cluster.fit(dat.values)

Но я получаю сообщение об ошибке, говорящее

TypeError: sim() missing 1 required positional argument: 'y'

Я не уверен, почему я получаю эту ошибку;Я думал, что функция будет кластеризовать пары строк, поэтому каждый требуемый аргумент будет передан.

Любая помощь с этим будет принята с благодарностью

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

'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)

Или вы можете использовать affinity='precomputed', как предложил @avchauzov.Для этого вам придется передать предварительно рассчитанную матрицу расстояний для ваших наблюдений в fit().Что-то вроде:

cluster = AgglomerativeClustering(n_clusters=5, affinity='precomputed', linkage='average')
distance_matrix = sim_affinity(X)
cluster.fit(distance_matrix)

Примечание : Вы указали сходство вместо расстояния.Поэтому убедитесь, что вы понимаете, как кластеризация будет работать здесь.Или, может быть, настроить вашу функцию сходства, чтобы вернуть расстояние.Что-то вроде:

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)
0 голосов
/ 19 декабря 2018

Обычный способ сделать это - поставить affinity='precomputed и подогнать матрицу расстояний (см. Пример здесь: https://gist.github.com/codehacken/8b9316e025beeabb082dda4d0654a6fa)

UPD В sklearn.hierarchical.py (https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/cluster/hierarchical.py#L460) вы можетеобратите внимание, что ваше пользовательское сходство должно получить только X (не y) в качестве ввода. И вход должен быть linkage_tree. Итак, вам нужно переписать вашу функцию sim ().

Но, на мой взгляд, первоепуть гораздо удобнее.

...