Кластеризация с одной связью в редактируемой матрице расстояний с критерием остановки порога расстояния - PullRequest
0 голосов
/ 02 мая 2019

Я пытаюсь назначить плоские кластеры с одной связью для идентификаторов последовательностей, разделенных расстоянием редактирования scipy.cluster.hierarchy.fclusterdata() с criterion='distance' может быть способом сделать это, но он не совсем возвращает кластеры, которые я ожидал бы для этого игрушечного примера.

В частности, в приведенном ниже примере матрицы расстояний 4x4, Я ожидал бы clusters_50 (который использует t=50) для создания 2 кластеров, где на самом деле он находит 3. Я думаю, проблема в том, что fclusterdata() не ожидает матрицу расстояний, но fcluster() не кажетсялибо делать то, что я хочу.

Я также посмотрел на sklearn.cluster.AgglomerativeClustering, но для этого нужно указать n_clusters, и я хочу создать столько кластеров, сколько необходимо, пока заданный порог расстояния не будет установленудовлетворен.

Я вижу, что в данный момент существует необработанный запрос scikit-learn pull для этой конкретной функции: https://github.com/scikit-learn/scikit-learn/pull/9069

Может кто-нибудь указать мне направильное направление?Кластеризация с критерием порога абсолютного расстояния выглядит как обычный случай использования.

import pandas as pd
from scipy.cluster.hierarchy import fclusterdata

cols = ['a', 'b', 'c', 'd']

df = pd.DataFrame([{'a': 0, 'b': 29467, 'c': 35, 'd': 13},
                   {'a': 29467, 'b': 0, 'c': 29468, 'd': 29470},
                   {'a': 35, 'b': 29468, 'c': 0, 'd': 38},
                   {'a': 13, 'b': 29470, 'c': 38, 'd': 0}],
                  index=cols)

clusters_20 = fclusterdata(df.values, t=20, criterion='distance')
clusters_50 = fclusterdata(df.values, t=50, criterion='distance')
clusters_100 = fclusterdata(df.values, t=100, criterion='distance')

names_clusters_20 = {n: c for n, c in zip(cols, clusters_20)}
names_clusters_50 = {n: c for n, c in zip(cols, clusters_50)}
names_clusters_100 = {n: c for n, c in zip(cols, clusters_100)}
names_clusters_20  # Expecting 3 clusters, finds 3
>>> {'a': 1, 'b': 3, 'c': 2, 'd': 1}

names_clusters_50  # Expecting 2 clusters, finds 3
>>> {'a': 1, 'b': 3, 'c': 2, 'd': 1}

names_clusters_100 # Expecting 2 clusters, finds 2
>>> {'a': 1, 'b': 2, 'c': 1, 'd': 1}

Ответы [ 2 ]

0 голосов
/ 02 мая 2019

Вы не установили параметр метрики.

Значением по умолчанию является metric='euclidean', а не предварительно вычислено .

0 голосов
/ 02 мая 2019

Понял это, передав linkage() в fcluster(), который поддерживает metric='precomputed' в отличие от fclusterdata().

fcluster(linkage(condensed_dm, metric='precomputed'), criterion='distance', t=20)

Решение:

import pandas as pd
from scipy.spatial.distance import squareform
from scipy.cluster.hierarchy import linkage, fcluster

cols = ['a', 'b', 'c', 'd']

df = pd.DataFrame([{'a': 0, 'b': 29467, 'c': 35, 'd': 13},
                   {'a': 29467, 'b': 0, 'c': 29468, 'd': 29470},
                   {'a': 35, 'b': 29468, 'c': 0, 'd': 38},
                   {'a': 13, 'b': 29470, 'c': 38, 'd': 0}],
                  index=cols)

dm_cnd = squareform(df.values)

clusters_20 = fcluster(linkage(dm_cnd, metric='precomputed'), criterion='distance', t=20)
clusters_50 = fcluster(linkage(dm_cnd, metric='precomputed'), criterion='distance', t=50)
clusters_100 = fcluster(linkage(dm_cnd, metric='precomputed'), criterion='distance', t=100)

names_clusters_20 = {n: c for n, c in zip(cols, clusters_20)}
names_clusters_50 = {n: c for n, c in zip(cols, clusters_50)}
names_clusters_100 = {n: c for n, c in zip(cols, clusters_100)}
names_clusters_20
>>> {'a': 1, 'b': 3, 'c': 2, 'd': 1}

names_clusters_50
>>> {'a': 1, 'b': 2, 'c': 1, 'd': 1}

names_clusters_100
>>> {'a': 1, 'b': 2, 'c': 1, 'd': 1}

Asфункция:

import pandas as pd
from scipy.spatial.distance import squareform
from scipy.cluster.hierarchy import fcluster, linkage

def cluster_df(df, method='single', threshold=100):
    '''
    Accepts a square distance matrix as an indexed DataFrame and returns a dict of index keyed flat clusters 
    Performs single linkage clustering by default, see scipy.cluster.hierarchy.linkage docs for others
    '''

    dm_cnd = squareform(df.values)
    clusters = fcluster(linkage(dm_cnd,
                                method=method,
                                metric='precomputed'),
                        criterion='distance',
                        t=threshold)
    names_clusters = {s:c for s, c in zip(df.columns, clusters)}
return names_clusters
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...