Формат scipy
Я написал свою собственную процедуру кластеризации и хотел бы создать дендрограмму. Самый простой способ сделать это - использовать функцию дипрограммы scipy. Однако для этого требуется, чтобы ввод был в том же формате, что и функция scipy linking. Я не могу найти пример того, как выходные данные этого отформатированы. Мне было интересно, может ли кто-то там просветить меня.
5 ответов
Это из документации по функции scipy.cluster.hierarchy.linkage(), я думаю, что это довольно четкое описание выходного формата:
A (n-1) на 4 матрицы Z возвращается. На i-й итерации кластеры с индексами Z[i, 0] и Z[i, 1] объединяются в кластер n + i. Кластер с индексом меньше n соответствует одному из исходных наблюдений. Расстояние между кластерами Z[i, 0] и Z[i, 1] определяется как Z[i, 2]. Четвертое значение Z[i, 3] представляет количество исходных наблюдений во вновь образованном кластере.
Вам нужно что-то еще?
Я согласен с mortonjt том, что документация не полностью объясняет индексацию промежуточных кластеров, хотя я согласен с dkar том, что Формат в остальном точно объяснен.
Используя пример данных из этого вопроса: Учебник для scipy.cluster.hierarchy
A = np.array([[0.1, 2.5],
[1.5, .4 ],
[0.3, 1 ],
[1 , .8 ],
[0.5, 0 ],
[0 , 0.5],
[0.5, 0.5],
[2.7, 2 ],
[2.2, 3.1],
[3 , 2 ],
[3.2, 1.3]])
Матрица сцепления может быть построена с использованием единственной (т. Е. Ближайших совпадающих точек):
z = hac.linkage(a, method="single")
array([[ 7. , 9. , 0.3 , 2. ],
[ 4. , 6. , 0.5 , 2. ],
[ 5. , 12. , 0.5 , 3. ],
[ 2. , 13. , 0.53851648, 4. ],
[ 3. , 14. , 0.58309519, 5. ],
[ 1. , 15. , 0.64031242, 6. ],
[ 10. , 11. , 0.72801099, 3. ],
[ 8. , 17. , 1.2083046 , 4. ],
[ 0. , 16. , 1.5132746 , 7. ],
[ 18. , 19. , 1.92353841, 11. ]])
Как объясняется в документации, кластеры ниже n (здесь: 11) являются просто точками данных в исходной матрице А. Промежуточные кластеры, идущие вперед, индексируются последовательно.
Таким образом, кластеры 7 и 9 (первое объединение) объединяются в кластер 11, кластеры 4 и 6 в 12. Затем наблюдаем линию три, объединяя кластеры 5 (из А) и 12 (из непоказанного промежуточного кластера 12), что приводит к Расстояние внутри кластера (WCD) 0,5. Единственный метод влечет за собой то, что новая WCS равна 0,5, что является расстоянием между A[5] и ближайшей точкой в кластере 12, A[4] и A[6]. Давай проверим:
In [198]: norm([a[5]-a[4]])
Out[198]: 0.70710678118654757
In [199]: norm([a[5]-a[6]])
Out[199]: 0.5
Этот кластер теперь должен быть промежуточным кластером 13, который впоследствии объединяется с A[2]. Таким образом, новое расстояние должно быть ближайшим между точками A [2] и A[4,5,6].
In [200]: norm([a[2]-a[4]])
Out[200]: 1.019803902718557
In [201]: norm([a[2]-a[5]])
Out[201]: 0.58309518948452999
In [202]: norm([a[2]-a[6]])
Out[202]: 0.53851648071345048
Что, как можно видеть, также проверяет и объясняет промежуточный формат новых кластеров.
Документация scipy точна, как указал dkar... но немного трудно превратить возвращаемые данные в нечто, что можно использовать для дальнейшего анализа.
На мой взгляд, они должны включать в себя возможность возвращать данные в виде дерева, как структура данных. Код ниже будет перебирать матрицу и строить дерево:
from scipy.cluster.hierarchy import linkage
import numpy as np
a = np.random.multivariate_normal([10, 0], [[3, 1], [1, 4]], size=[100,])
b = np.random.multivariate_normal([0, 20], [[3, 1], [1, 4]], size=[50,])
centers = np.concatenate((a, b),)
def create_tree(centers):
clusters = {}
to_merge = linkage(centers, method='single')
for i, merge in enumerate(to_merge):
if merge[0] <= len(to_merge):
# if it is an original point read it from the centers array
a = centers[int(merge[0]) - 1]
else:
# other wise read the cluster that has been created
a = clusters[int(merge[0])]
if merge[1] <= len(to_merge):
b = centers[int(merge[1]) - 1]
else:
b = clusters[int(merge[1])]
# the clusters are 1-indexed by scipy
clusters[1 + i + len(to_merge)] = {
'children' : [a, b]
}
# ^ you could optionally store other info here (e.g distances)
return clusters
print create_tree(centers)
Вот еще один фрагмент кода, который выполняет ту же функцию. Эта версия отслеживает расстояние (размер) каждого кластера (node_id) и подтверждает количество членов.
При этом используется функция scipy linkage(), которая является той же основой кластерного агрегатора.
from scipy.cluster.hierarchy import linkage
import copy
Z = linkage(data_x, 'ward')
n_points = data_x.shape[0]
clusters = [dict(node_id=i, left=i, right=i, members=[i], distance=0, log_distance=0, n_members=1) for i in range(n_points)]
for z_i in range(Z.shape[0]):
row = Z[z_i]
cluster = dict(node_id=z_i + n_points, left=int(row[0]), right=int(row[1]), members=[], log_distance=np.log(row[2]), distance=row[2], n_members=int(row[3]))
cluster["members"].extend(copy.deepcopy(members[cluster["left"]]))
cluster["members"].extend(copy.deepcopy(members[cluster["right"]]))
clusters.append(cluster)
on_split = {c["node_id"]: [c["left"], c["right"]] for c in clusters}
up_merge = {c["left"]: {"into": c["node_id"], "with": c["right"]} for c in clusters}
up_merge.update({c["right"]: {"into": c["node_id"], "with": c["left"]} for c in clusters})
рассмотреть [вход] - это данные, для которых вы хотите нарисовать дентограмму,
когда вы используете связь, которая возвращает матрицу с четырьмя столбцами
column1 и column2 - представляют формирование кластера по порядку
то есть 2 и 3 делают кластер первым, этот кластер называется 5
(2 и 3 представляют собой индекс, который является 2 и 3-й строкой), 1 и 5 - это второй сформированный кластер, этот кластер называется 6
столбец 3 - представляет расстояние между кластерами
столбец 4 - показывает, сколько точек данных задействовано в создании этого кластера.