python-networkx практикует визуализацию социальных сетей

визуализация данных

«Это 25-й день моего участия в ноябрьском испытании обновлений. Ознакомьтесь с подробностями события:Вызов последнего обновления 2021 г."

Практикуйте визуализацию социальных сетей с помощью python-networkx

01 Используйте networkx, чтобы создать графовую сетевую модель

  • Создайте граф с networkx, добавьте узлы и ребра
  • Просмотр матрицы смежности/таблицы смежности/тепловой карты графика
  • Расширение возможностей графической сети
  • Графическая сетевая статистика (степень выхода и степень входа, кратчайший путь)

пакет гида

import networkx as nx 
import matplotlib.pyplot as plt 
import collections 
import random 
import numpy as np 
from pylab import rcParams 
import warnings
warnings.filterwarnings("ignore")
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

добавить узел

# 添加结点
G = nx.Graph() # 创建一个空的无向图 创建有向图使用nx.DiGraph()
G.add_node(1) # 创建单个节点
G.add_nodes_from(range(10)) # 创建一组节点
nx.draw(G,node_color="darkblue")

image.png

добавить преимущество

G.add_edge(1,2)
e = [(2,3),(9,3),(8,4),(3,5),(8,6),(0,8),(1,9)]
G.add_edges_from(e)
nx.draw(G,with_labels=True,node_color="darkblue",font_color="white")

image.png

вывести матрицу смежности и список смежности

# 打印邻接矩阵
print("邻接矩阵")
print(nx.adjacency_matrix(G))
print("="*50)
print("邻接表")
for i in G.adj.items():
    print(i)

image.png

Тепловая карта

# 邻接矩阵的热力图:反应稀疏程度
print(nx.to_numpy_matrix(G)) #转换邻接矩阵为numpy格式
plt.imshow(nx.to_numpy_matrix(G)) #创建2维热力图
cbar = plt.colorbar() #--> 设置colorbar热力图题注
cbar.set_ticks([0,1]) #--> 设置colorbar刻度范围
cbar.ax.set_yticklabels(['Zero','One'],) #--设置colorbar刻度轴首尾坐标名
cbar.set_label('link', rotation=0) #--设置colorbar坐标名
plt.xlabel('node idx') #--设置 x 轴
plt.ylabel('node idx') #--设置 y 轴

image.png

наделение полномочиями

# 赋权
for e in G.edges():
    G[e[0]][e[1]]['weight'] = random.uniform(0, 1) # 使用uniform分布给已存在的关系重新赋权
    print(nx.to_numpy_matrix(G))
plt.imshow(nx.to_numpy_matrix(G))
cbar = plt.colorbar() #--> 设置colorbar热力图题注
cbar.set_ticks([0,1]) #--> 设置colorbar刻度范围
cbar.ax.set_yticklabels(['Zero','One'],) #--设置colorbar刻度轴首尾坐标名
cbar.set_label('link', rotation=0) #--设置colorbar坐标名
plt.xlabel('node idx') #--设置 x 轴
plt.ylabel('node idx') #--设置 y 轴

image.png

сетевая статистика

##### 网络统计量
# 度
G =nx.karate_club_graph() # 创建一个空手道成员俱乐部图 :这是一个非常有名的社交网络图
degree_sequence = sorted([d for n, d in G.degree()], reverse=True) # 保存每个结点的度,并按降序排列
print("度 排列", degree_sequence)
print("= "*50)
degreeCount = collections.Counter(degree_sequence) # 计算每种度的数目
print("度 频率", degreeCount)
print("= "*50)

deg, cnt = zip(*degreeCount.items()) # 创建一个迭代器
rcParams['figure.figsize'] = 12, 8 # 设置画板全局大小
fig, ax = plt.subplots() # 创建子图

plt.bar(deg, cnt, width=0.80, color='darkblue')
plt.title("度 直方图")
plt.ylabel("频率")
plt.xlabel("度")
plt.axes([0.4, 0.4, 0.5, 0.5])
plt.axis('off')
ax.set_xticks([d + 0.4 for d in deg])
ax.set_xticklabels(deg)
pos = nx.spring_layout(G) #-- 设置网络布局
nx.draw_networkx_nodes(G, pos, node_color= 'darkblue',node_size=20) # 画图
nx.draw_networkx_edges(G, pos, alpha=0.5) # 画边
plt.show()
print('无向图的度均值:', np.mean(G.degree()))

image.png

Средняя степень неориентированного графа: 10,544117647058824

кратчайший путь

# 最短路径
R = nx.karate_club_graph() 
source=14 # 选一个点做起点
target=16 # 选一个点做终点

# 最短路径作图函数
def short_path_plot(G,source,target):
    pos = nx.spring_layout(G) #-- 设置网络布局
    nx.draw(G,pos,node_color='k', with_labels=True, font_color='white') #-- 画图结构

    path = nx.shortest_path(G,source=14,target=16) #-- 调用shortest path计算最短路径
    print("最短路径:",path) 
    
    path_edges = list(zip(path,path[1:])) #-- 创建最短路径边
    nx.draw_networkx_nodes(G,pos,nodelist=path,node_color='r', label=True)  #-- 画结点
    nx.draw_networkx_edges(G,pos,edgelist=path_edges,edge_color='r',width=10)  #--画边
    plt.axis('equal')
    plt.show()
    return

#调用函数
short_path_plot(R,source,target)

image.png

02 Структура сети

  • случайный граф
  • модель маленького мира
  • безмасштабная сеть
# 下载 幂律分布 包
# !pip install powerlaw

import re
import powerlaw
import seaborn as sns
from operator import itemgetter

# 直方图绘制
def draw_hist_network(G):
    degree_sequence = sorted([d for n, d in G.degree()], reverse=True) 
    degreeCount = collections.Counter(degree_sequence) 
    deg, cnt = zip(*degreeCount.items()) 
    rcParams['figure.figsize'] = 10, 5 
    fig, ax = plt.subplots() 
    plt.bar(deg, cnt, width=0.80, color='darkblue') 
    plt.title("度 直方图")
    plt.ylabel("频率")
    plt.xlabel("度")
    ax.set_xticks([d + 0.4 for d in deg])
    ax.set_xticklabels(deg)
    plt.axes([0.4, 0.4, 0.5, 0.5])
    Gcc = G.subgraph(sorted(nx.connected_components(G), key=len, reverse=True)[0])
    pos = nx.spring_layout(G) 
    plt.axis('off') 
    nx.draw_networkx_nodes(G, pos, node_color= 'darkblue',node_size=20)
    nx.draw_networkx_edges(G, pos, alpha=0.4)
    plt.show()
    pass
# 网络绘制
def draw_network(G,name):
    plt.title(name)
    pos = nx.circular_layout(G) 
    nx.draw_networkx_nodes(G, pos, node_color= 'darkblue',node_size=20)
    nx.draw_networkx_edges(G, pos, alpha=0.4)
    plt.axis('off') 
    plt.show()
    pass

случайный граф

# 生成随机图
nodes_n=50
degree=20
simulation_number=10
rcParams['figure.figsize'] = 5, 5

#连通率 = 0.01:
#------------------------------
G = nx.random_regular_graph(degree,nodes_n) #<-- Generate the Small World Network
draw_network(G,name="随机正太分布图")

image.png

Сеть Малого Мира

# 小世界网络
nodes_n=1000
degree=20
rcParams['figure.figsize'] = 5, 5

#简单的小世界模型------------------------------
G = nx.watts_strogatz_graph(20,5,p=0.01) #<-- 生成小世界模型
draw_network(G,name="小世界模型")
#连通率 = 0.01:
#------------------------------
G = nx.watts_strogatz_graph(nodes_n,degree, p = 0.01) #<-- 生成小世界模型
draw_hist_network(G)

#连通率  = 0.05:
#------------------------------
G = nx.watts_strogatz_graph(nodes_n,degree, p = 0.05) #<-- 生成小世界模型
draw_hist_network(G)

#连通率  = 0.1:
#------------------------------
G = nx.watts_strogatz_graph(nodes_n,degree, p = 0.1) #<-- 生成小世界模型
draw_hist_network(G)

image.png

image.png

безмасштабная сеть

Безмасштабные сети демонстрируют степенное распределение

# 无标度网络
node_n = 100000 #-- 节点数
m=3   #-- 从新节点附加到现有节点的边缘数
G = nx.barabasi_albert_graph(node_n, m)
# draw_network(G,name="无标度网络") # 100000结点绘图很慢很占内存 
degree_freq = nx.degree_histogram(G)
degrees = range(len(degree_freq))
plt.figure(figsize=(12, 8)) 
plt.loglog(degrees[m:], degree_freq[m:],'go-') 
plt.xlabel('度', fontsize = 'x-large')
plt.ylabel('频率', fontsize = 'x-large')
plt.show()

image.png

03 Измерение узлов — Центральность

Что такое центральность?

Центральность — это термин, описывающий важность отдельных узлов в графе. Для того, чтобы ответить на вопрос «Какой узел является самым важным узлом (вершиной) в графе?», было проведено большое количество экспериментов, и список экспериментов выглядит следующим образом:

  • Центральность степени
  • Промежуточность
  • Близость
  • Центральность собственного вектора
  • Кац Центральность

Абсолютная центральность используется для точечной центральности/центральности промежуточного положения/центральности близости.

import pandas as pd
import matplotlib.colors as mcolors
from pylab import rcParams

Zachary Karate Club — это широко используемая социальная сеть, в которой узлы представляют членов клуба карате, а ребра представляют отношения между членами.

# Zachary 空手道俱乐部
G = nx.karate_club_graph() 
pos = nx.circular_layout(G) #-- 圆盘布局
nodes = nx.draw_networkx_nodes(G, pos, node_size=400,node_color='White',edgecolors='b')
nodes.set_norm(mcolors.SymLogNorm(linthresh=0.03, linscale=2))
labels = {i:i for i in G.nodes()}
labels = nx.draw_networkx_labels(G, pos, labels, font_size=12)
edges = nx.draw_networkx_edges(G, pos, edge_color = 'grey')
plt.axis('off')
plt.show()

def draw(G, pos, measures, measure_name):
    nodes = nx.draw_networkx_nodes(G, pos, node_size=400, cmap=plt.cm.plasma, 
                                   node_color=list(measures.values()),
                                   nodelist=list(measures.keys())) 
    nodes.set_norm(mcolors.SymLogNorm(linthresh=0.03, linscale=1))
    labels = nx.draw_networkx_labels(G, pos, font_color='white')
    edges = nx.draw_networkx_edges(G, pos)
    plt.title(measure_name,size=18)
    cbar = plt.colorbar(nodes)
    cbar.set_label('中心度权重', rotation=0)
    plt.axis('off')
    plt.show()
    pass

image.png

точечная центральность

# 点度中心度 Degree Centrality
draw(G, pos,nx.degree_centrality(G),'点度中心度')

image.png

промежуточность

# 中介中心度 Betweenness Centrality
draw(G, pos, nx.betweenness_centrality(G), '中介中心度')

image.png

близость

# 接近中心度 Closeness Centrality
draw(G, pos, nx.closeness_centrality(G), '接近中心度')

image.png

Центральность собственного вектора

# 特征向量中心度 Eigenvector Centrality
draw(G, pos, nx.eigenvector_centrality(G), '特征向量中心度')

image.png

Кац Центральность

# 卡茨中心度 Katz Centrality
draw(G, pos, nx.katz_centrality(G, alpha=0.1, beta=1.0), '卡茨中心度')

image.png

#创建一个pandas表比较各种中心度:
dataset1=[]
for k in nx.degree_centrality(G).keys():
    dataset1.append([k,nx.degree_centrality(G)[k],nx.katz_centrality(G)[k],nx.eigenvector_centrality(G)[k],
                    nx.closeness_centrality(G)[k],nx.betweenness_centrality(G)[k]])
rcParams['figure.figsize'] = 5, 5 
sns.set(style="ticks")
#创建dataframe:
df=pd.DataFrame(dataset1,columns=['id',
                                  'Degree centrality','Katz centrality','Eigenvector centrality',
                                  'Clossness centrality','Betweenness centrality'])
#输出 变量两两之间的关系:
sns.pairplot(df)

image.png

04. Общее измерение

  • плотность
  • центральный потенциал
# 密度
G = nx.karate_club_graph()
print('karate_club_graph图 密度:', nx.density(G))

G = nx.watts_strogatz_graph(21,7,p=0.05) #<-- 生成小世界模型
print('生成的小世界模型 密度:', nx.density(G))

Плотность графика karate_club_graph: 0,13903743315508021 Сгенерированная модель маленького мира Плотность: 0,3

плотность

1. Плотность
Плотность неориентированного графа равнаD=2mn(n1)D=\frac{2m}{n(n-1)} Плотность направленного графикаD=mn(n1)D=\frac{m}{n(n-1)}вnколичество узлов в Gm— количество ребер в G.
Граф без ребер имеет плотность 0, полный граф имеет плотность 1, а мультиграф может иметь плотность больше 1.

центральный потенциал

2. Центральный потенциал: Центральный потенциал используется для измерения общей центральности сети.

  1. Сначала найдите максимальное значение центральности MAX в сети;
  2. Затем вычислите «разницу» между значением MAX и центральностью других точек соответственно;
  3. Затем вычислите сумму этих «разностей»;
  4. Наконец, разделите эту сумму на теоретически максимально возможное значение суммы разностей.

Абсолютный центральный потенциал равенCAD=i=1n(CADmaxCADi)(n1)(n2)C_{AD}= \frac{\sum_{i=1}^{n}(C_{ADmax}-C_{ADi})}{(n-1)(n-2)}

Относительный центральный потенциал равенCRD=i=1n(CRDmaxCRDi)(n2)C_{RD}= \frac{\sum_{i=1}^{n}(C_{RDmax}-C_{RDi})}{(n-2)}

# 点度中心势
def Degree_Centralization(G,mode="AD"):
    n = nx.number_of_nodes(G) #-- n节点数目
    centrality_list = np.array(list(nx.degree_centrality(G).values())) # 中心度列表
    max_centrality = max(centrality_list) # 中心度 最大值
    if mode=='AD':
        degree_centralization = sum(max_centrality - centrality_list) / (n-1)*(n-2)
    if mode=='RD':
        degree_centralization = sum(max_centrality - centrality_list) / (n-2) 
    return degree_centralization
G = nx.karate_club_graph()
print('karate_club_graph图 绝对中心势:', Degree_Centralization(G,mode='AD'))
print('karate_club_graph图 相对中心势:', Degree_Centralization(G,mode='RD'))
draw_network(G,name="")

G = nx.watts_strogatz_graph(21,7,p=0.05) #<-- 生成小世界模型
print('生成的小世界模型 绝对中心势:', Degree_Centralization(G,mode='AD'))
print('生成的小世界模型 相对中心势:', Degree_Centralization(G,mode='RD'))
draw_network(G,name="")

image.png

05. Агломеративные подгруппы

  • Подгруппа конденсата K-ядра
G = nx.karate_club_graph()
nx.core_number(G)

# 输出
{0: 4,
 1: 4,
 2: 4,
 3: 4,
 4: 3,
 5: 3,
 6: 3,
 7: 4,
 8: 4,
 9: 2,
 10: 3,
 11: 1,
 12: 2,
 13: 4,
 14: 2,
 15: 2,
 16: 2,
 17: 2,
 18: 2,
 19: 3,
 20: 2,
 21: 2,
 22: 2,
 23: 3,
 24: 3,
 25: 3,
 26: 2,
 27: 3,
 28: 3,
 29: 3,
 30: 4,
 31: 3,
 32: 4,
 33: 4}
def draw_clu(G, pos, measures, measure_name):
    clusters=np.array(list(set(measures.values())))
    plt.figure()
    nodes = nx.draw_networkx_nodes(G, pos, node_size=250, cmap=mcolors.ListedColormap(plt.cm.Set3(clusters)), 
                                   node_color=np.array(list(measures.values()))-1,
                                   nodelist=list(measures.keys()))
    print(measures.values())
    print(measures.keys())
    labels = nx.draw_networkx_labels(G, pos)
    edges = nx.draw_networkx_edges(G, pos)
    plt.title(measure_name)
    rcParams['figure.figsize'] = 12, 8
    rcParams['font.sans-serif'] = ['SimHei']
    cb = plt.colorbar(nodes,ticks=range(0,len(clusters)), label='子群标签')
    cb.ax.tick_params(length=0)
    cb.set_ticklabels(list(set(measures.values())))
    nodes.set_clim(-0.5, len(clusters)-0.5)
    plt.axis('off')
    plt.show()
    
G = nx.karate_club_graph()
pos = nx.spring_layout(G)
draw_clu(G, pos, nx.core_number(G),'k-Core')

image.png

draw(G, pos, nx.core_number(G), 'k-Core')

image.png

06. Предсказание ссылок

import networkx as nx
import numpy as np
import urllib.request
urllib.request.urlretrieve("http://snap.stanford.edu/data/ca-GrQc.txt.gz", "ca-GrQc.txt.gz")
graph = nx.read_edgelist('ca-GrQc.txt.gz')
graph.order()
draw_network(graph,name="")

image.png

degrees = dict(graph.degree())
author = sorted(degrees.items(),key=lambda x: x[1],reverse=True)[500][0]
print('学者 %s 的"度"为 %d' % (author, graph.degree()[author]))

# 获取子图
def get_subgraph(graph, nodes, n=100):
    neighbors = set()
    for ni in nodes:
        neighbors |= set(graph.neighbors(ni))
    # plot at least the target node and his neighbors.
    result = set(nodes) | neighbors
    # add "friends of friends" up to n total nodes.
    for x in neighbors:
        # how many more nodes can we add?
        maxsize = n - len(result) 
        toadd = set(graph.neighbors(x)) - result
        result.update(list(toadd)[:maxsize])
        if len(result) > n:
            break
    return graph.subgraph(result)

subgraph = get_subgraph(graph, [author], n=30)
print('子图有个 %d 结点' % len(subgraph.nodes()))

Ученый 13813 имеет «степень» 13.
Подграф имеет 30 узлов

# 绘制子图
def plot_subgraph(subgraph, target_nodes):
    nodes = list(subgraph.nodes())
    colors = ['c'] * len(nodes)
    for n in target_nodes:
        idx = nodes.index(n)
        colors[idx] = 'r'
    sizes = [800] * len(nodes)
    sizes[idx] = 1000
    plt.figure(figsize=(8,8))
    plt.axis('off')
    nx.draw_networkx(subgraph, nodelist=nodes, with_labels=True,
                     width=.5, node_color=colors,
                     node_size=sizes, alpha=.5)

plot_subgraph(subgraph, [author])

image.png

Кому следует порекомендовать автора 13813 для сотрудничества?

Метод предсказания соединения

  • Думайте о задаче прогнозирования ссылок как о проблеме ранжирования в поиске информации.
  • Рассчитать новую оценку для каждого ребраs(X,Y)s(X,Y).
  • Отсортировать все возможные дробные ребра в порядке убыванияs(X,Y)s(X,Y).
  • Выберите самое результативное преимуществоs(X,Y)s(X,Y) \rightarrow.

1.) Кратчайший путь: s(X,Y)=s(X,Y) = отXXприбытьYYДлина кратчайшего пути.

# 最短路径算法
def rank_by_shortest_path(graph, node):
    paths = nx.shortest_path_length(graph, node)
    return sorted(paths.items(), key=lambda x: x[1])

shortest_paths = rank_by_shortest_path(graph, author)
print('最短路径 top-20 :')
shortest_paths[:20]
print("以作者13813为起始点,在网络中最短路径为2的合作者有%s位" % len([s for s in shortest_paths if s[1] == 2]))
print('链接预测 top-10 :')
[s for s in shortest_paths if s[1] == 2][:10]

image.png

Взяв за отправную точку автора 13813, мы получим 57 соавторов с кратчайшим путем 2 в сети.

image.png

визуализация, рекомендательный эффект

pair = set([author, '5227','5543','10931','639','18736'])
plot_subgraph(get_subgraph(graph, pair, n=30), pair)

image.png

Другой способ: еслиXXиyyМного соавторов с соавторами, тоxxиyyскорее всего в соавторстве

2.) жаккард: S=N(X)N(Y)N(X)N(Y)S = \frac{|N(X) \cap N(Y)|}{|N(X) \cup N(Y)|}

def rank_by_jaccard(graph, node):
    neighbors = set(graph.neighbors(node))
    scores = []
    for n in graph.nodes():
        neighbors2 = set(graph.neighbors(n))
        scores.append((n, len(neighbors & neighbors2) / len(neighbors | neighbors2)))
    return sorted(scores, key=lambda x: x[1], reverse=True)

common_jaccard = rank_by_jaccard(graph, author)
common_jaccard[:20]
plt.plot(sorted([x[1] for x in common_jaccard if x[1] > 0.]))
plt.show()

image.png

image.png

def dataframe_scores(scores_list, names, n):
    ids = set()
    for scores in scores_list:
        ids.update([x[0] for x in scores[:n]])
    print('jaccard算法链接预测的 top %d' % (n))
    results = []
    for id_ in ids:
        result = {'id': id_}
        for scores, name in zip(scores_list, names):
            for rank, (id2, score) in enumerate(scores):
                if id2 == id_:
                    result[name + '_rank'] = rank
                    result[name + '_score'] = score
                    break
        results.append(result)
    headers = ['id']
    for name in names:
        headers.append(name + '_rank')
        headers.append(name + '_score')
    return pd.DataFrame(results, columns=headers)
    
df = dataframe_scores([common_jaccard],['jaccard'],20)
df.sort_values('jaccard_rank').head(10)

pair = set([author, '23204','19204','17559','409','6746'])
plot_subgraph(get_subgraph(graph, pair, n=30), pair)

image.png