Кластеризация данных с использованием корреляционной матрицы — разумная идея, но сначала необходимо предварительно обработать корреляции. Во-первых, на корреляционную матрицу, возвращаемую numpy.corrcoef
, влияют ошибки машинной арифметики:
- Он не всегда симметричен.
- Диагональные члены не всегда точно равны 1
Их можно исправить, взяв среднее значение с транспонированием и заполнив диагональ 1:
import numpy as np
data = np.random.randint(0, 10, size=(20, 10)) # 20 variables with 10 observations each
corr = np.corrcoef(data) # 20 by 20 correlation matrix
corr = (corr + corr.T)/2 # made symmetric
np.fill_diagonal(corr, 1) # put 1 on the diagonal
Во-вторых, входные данные для любого метода кластеризации, такого как linkage
, должны измерять несходство объектов. Корреляция измеряет сходство. Поэтому его необходимо преобразовать таким образом, чтобы корреляция 0 сопоставлялась с большим числом, а корреляция 1 сопоставлялась с 0.
В этом сообщении блога обсуждается несколько способов получения таких данных. трансформации и рекомендует dissimilarity = 1 - abs(correlation)
. Идея состоит в том, что сильная отрицательная корреляция также указывает на то, что объекты связаны, как и положительная корреляция. Вот продолжение примера:
from scipy.cluster.hierarchy import linkage, fcluster
from scipy.spatial.distance import squareform
dissimilarity = 1 - np.abs(corr)
hierarchy = linkage(squareform(dissimilarity), method='average')
labels = fcluster(hierarchy, 0.5, criterion='distance')
Обратите внимание, что мы не передаем полную матрицу расстояний в linkage
, ее нужно сначала сжать с помощью squareform
.
Какие именно методы кластеризации использовать и какие пороги, зависит от контекста вашей проблемы, универсальных правил нет. Часто 0,5 является разумным порогом для корреляции, поэтому я так и сделал. С моими 20 наборами случайных чисел я получил 7 кластеров: закодированных в labels
как
[7, 7, 7, 1, 4, 4, 2, 7, 5, 7, 2, 5, 6, 3, 6, 1, 5, 1, 4, 2]
person
Community
schedule
11.12.2017