Визуализация кластеризации на основе оценки сходства

У меня есть следующие данные в виде перекрестной таблицы:

            biz   user1  user2  user3  user4
    user
    A         1      1      0      0
    B         1      1      0      0
    C         1      1      1      0
    D         1      0      0      0
    E         0      0      1      1
    F         0      0      1      1
    G         0      0      1      1
    J         0      0      0      1
    M         0      1      0      0

и с помощью ковариации превратите его в:

   [ 1.  ,  0.75,  0.25,  0.  ],
   [ 0.75,  1.  ,  0.25,  0.  ],
   [ 0.25,  0.25,  1.  ,  0.75],
   [ 0.  ,  0.  ,  0.75,  1.  ]

Используя следующий код, я пытаюсь построить график этих данных:

   import pandas as pd
   import numpy as np
   import networkx as nx

    users=[]
    user_s=[(x+',')*4 for x in ['user1', 'user2', 'user3', 'user4']]
    for s in user_s:
        users.extend([e for e in s.split(',') if e!=''])

    X=[]
    user_s=[(x+',')*4 for x in ['32.5', '32.2', '30.4', '31.5']]
    for s in user_s:
        X.extend([float(e) for e in s.split(',') if e!=''])

    Y=[]
    user_s=[(x+',')*4 for x in ['-110', '-110', '-115', '-114']]
    for s in user_s:
        Y.extend([float(e) for e in s.split(',') if e!=''])    

    dat=pd.DataFrame({'user':users, 
        'biz':['A', 'B', 'C', 'D', 'A', 'B', 'C', 'M', 'C', 'E', 'F', 'G', 'E', 'F', 'G', 'J'],
        'X':X, 'Y':Y})

    rel=pd.crosstab(dat.user, dat.biz, rownames=['biz'], colnames=['user']).transpose()
    cov=np.dot(rel.transpose(), rel)/np.diag(np.dot(rel.transpose(), rel))
    dat.groupby('user').mean()[['X', 'Y']]
    dat.groupby('user').mean()[['X', 'Y']]
    G=nx.Graph()
    for i in rel.columns.tolist():
        G.add_node(i, X=dat.loc[dat.user==i, 'X'].mean(), Y=dat.loc[dat.user==i, 'Y'].mean())


    for i in np.arange(0, cov.shape[0]):
        idx=np.where(cov[i,]>.0)[0].tolist() ##for column i, get index of cov values above quantile p
        for j in idx:
            if i!=j: #eliminates (0,0) as an edge bc its redundant
                G.add_edge(rel.columns[i],
                rel.columns[j],weight=cov[i,j],length=1/cov[i,j], width=cov[i,j])

    centrality=nx.degree_centrality(G)    
    pos=nx.spring_layout(G)
    nx.draw(G,pos, node_size=[centrality[key]*500 for key in centrality.keys()],
        cm=plt.cm.Spectral,edge_cm=plt.cm.Blues,
        width=[(x[2]['width']*2)**2 for x in G.edges(data=True)], alpha=.5)  
    nx.draw_networkx_labels(G,pos,fontsize=16) 

график, созданный вышеуказанным кодом

Обратите внимание на сильную корреляцию между user1 и user2, а также user3 и user4; в то время как связь между двумя кластерами слабая.

Я хочу сделать две вещи:

  • Две группы должны иметь одинаковый цвет (чтобы указать принадлежность к кластеру).
  • Расстояние между пользователями user1 и user2 должно быть меньше, чем между user1 и user3. Аналогично для user3 и user4.

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

Моя основная цель - визуализировать это на гораздо большем наборе данных (10 тыс. Пользователей).


person Gene Burinsky    schedule 29.10.2015    source источник


Ответы (2)


Вы также можете рассмотреть дендрограмму.

Вы можете использовать scipy создать один.

person anana    schedule 30.10.2015

В графе вопроса связи определяются ненулевыми весами между пользователями; поэтому, чтобы проверить наличие очень похожих групп, я определил веса, необходимые для расчета связи, как и те, у которых корреляция выше 0,75. Это создает острова, и их можно отобразить как разные группы с помощью функции ниже:

    G=nx.Graph()
    G.add_nodes_from(['u1', 'u2', 'u3', 'u4', 'u5', 'u6', 'u7', 'u8'])
    G.add_edges_from([
    ('u1', 'u2', {'weight':.75}),  ('u1','u5', {'weight':1}),('u2', 'u5', {'weight':.75}),
    ('u3', 'u6', {'weight':.8}), ('u4', 'u6', {'weight':.65}),('u3', 'u4', {'weight':.75}),
    #('u3', 'u7', {'weight':.5}),
    #('u2', 'u4', {'weight':.3}),
    ('u7', 'u8', {'weight':.9})])

    def draw_group_graph(graph, edge_cmap=plt.cm.Blues,node_cmap=plt.cm.jet, w_pwr=3):
        plt.figure()
        pos=nx.spring_layout(graph)

        nx.draw_networkx_edges(graph,pos,
        width=[nx.get_edge_attributes(graph,'weight')[i]*w_pwr for i in  G.edges()],
        edge_cmap=edge_cmap, 
        edge_color=[nx.get_edge_attributes(graph,'weight')[i] for i in  G.edges()])

        nx.draw_networkx_edge_labels(G, pos, labels=[str(i) for i in weights])

        g_list=[j for j in nx.connected_component_subgraphs(graph) if len(j.edges())>0]

        col_val=np.linspace(0,1,num=len(g_list)).tolist()
        i=0; print(len(g_list))
        for g in g_list:
            print(i, "color:",node_cmap(col_val[i]) )
            nx.draw_networkx_nodes(g, pos, node_color=node_cmap(col_val[i]), alpha=.6,
            node_size=[nx.degree_centrality(g)[i]*1000 for i in  g.nodes()])
            nx.draw_networkx_labels(g, pos, fontsize=16)
            i=i+1

Указанный выше график построен с использованием разных групп

person Gene Burinsky    schedule 30.10.2015
comment
откуда ты берёшь вес? - person ethanenglish; 01.06.2017
comment
@ethanenglish Веса берутся из нормализованной ковариационной матрицы; приведенный выше график является взвешенным. - person Gene Burinsky; 02.06.2017