14.网络模型

import networkx as nx
import matplotlib.pyplot as plt
import csv
from operator import itemgetter
from networkx.algorithms import community


"""
图的基本操作:

# 创建图
G = nx.Graph()

# 添加一个节点
G.add_node(1)
G.add_nodes_from([2, 3])  # 您也可以通过传递列表参数来添加节点列表

# 添加边缘
G.add_edge(4,5)  # 节点4 5 建立连接(如果图中无某个节点则先创建该节点然后建立连接)

e =(2,3)
G.add_edge(* e)  # *解压缩元组

G.add_edges_from([[1, 2], [3, 4]])  # 也可以通过传递列表参数来添加边列表

# 查看图的基本信息
print(nx.info(G))

# 图的可视化
nx.draw_networkx(G)
plt.show()
"""



"""
我们的例子:朋友协会

在没有Facebook朋友之前,有一个叫Quakers的朋友协会。贵格会教徒成立于17世纪中叶,是基督教徒,
他们与英格兰官方教会持不同意见,并提倡广泛的宗教宽容,
他们更喜欢基督徒的所谓“内在光明”和良心,而不是国家强制的正统观念。

"""



# 获取数据(人物和关系)
with open("quakers_nodelist.csv") as nodecsv:
    nodereader = csv.reader(nodecsv)
    # remove the header row
    nodes = [i for i in nodereader][1:]

node_names = [n[0] for n in nodes]  # Get a list of only the node names

with open("quakers_edgelist.csv") as edgecsv:
    edgereader = csv.reader(edgecsv)
    edges = [tuple(e) for e in edgereader][1:]

# 检查数据
print(len(node_names))
print(len(edges))

# 创建图
G = nx.Graph()

# 添加节点和边
G.add_nodes_from(node_names)
G.add_edges_from(edges)

# 查看网络基本信息
print(nx.info(G))

# 添加属性 NetworkX允许您将属性添加到节点和边缘,并提供有关它们的更多信息
# head = [Name,HistoricalSignificance,Gender,Birthdate,Deathdate,ID]

# 创建属性字典
hist_sig_dict = {}
gender_dict = {}
birth_dict = {}
death_dict = {}
id_dict = {}

# 构建字典
for node in nodes:
    hist_sig_dict[node[0]] = node[1]
    gender_dict[node[0]] = node[2]
    birth_dict[node[0]] = node[3]
    death_dict[node[0]] = node[4]
    id_dict[node[0]] = node[5] 

# 将属性添加到Graph对象中的节点:节点属性,注意参数
# 如果是上下级关系或者亲属关系,则存在边属性,朋友关系则无
nx.set_node_attributes(G, hist_sig_dict, 'historical_significance')
nx.set_node_attributes(G, gender_dict, 'gender')
nx.set_node_attributes(G, birth_dict, 'birth_year')
nx.set_node_attributes(G, death_dict, 'death_year')
nx.set_node_attributes(G, id_dict, 'sdfb_id')

# 访问属性并打印查看,以birth_year查看出生年份为例
# for n in G.nodes():
#     print(n, G.nodes[n]["birth_year"])


# 可视化
# nx.draw_networkx(G)
# plt.show()






"""
NetworkX中可用的指标

网络密度:
网络中实际边与网络中所有可能边的比率。在像这样的无向网络中,任何两个节点之间可能只有一条边,但实际上只有少数可能的边存在。网络密度快速了解网络的紧密程度。

最短路径:
它计算出任何两个节点之间的节点和边的最短序列,这种方法本质上是在寻找朋友的朋友凯文·培根(Kevin Bacon)的“六度”游戏基本上是一种寻找从凯文·培根到任何其他演员
的最短路径(路径长度为6或更短)的游戏。

直径:
它是所有最短路径中的最长者。在计算完网络中每个可能的节点对之间的所有最短路径之后,直径是两个节点之间距离最远的路径的长度。该度量旨在让您大致了解网络的总体大小,即
从网络一端到另一端的距离。

聚类系数:
如果三个人彼此认识,就会产生一个闭合三角形,网络中这些封闭的三角形的数量可用于查找彼此非常了解的个人集群和社区。由于这种聚集趋势,一种测量三重封闭的方法称为聚集系数。

传递性:
传递性是实际存在的所有三角形与所有可能三角形的比率。传递性表示图的互连程度,以实际连接数与可能连接数之比表示。传递性使您可以考虑图形中可能存在但当前尚不存在的所有关系。

中心性:
哪些节点是网络中最重要的节点,有许多不同的计算中心度的方法:度,中间度和特征向量中心度。
    度:
    与某个节点相连的边的数量就是该节点的度。可以将度数视为给定人员认识的人数。社交网络中度最高的节点是认识人最多的人。这些节点通常称为集线器,计算度是识别集线器的最快方法。
    特征向量中心度:
    特征向量中心性会在意您是否是集线器,但也会在意您连接了多少个集线器。特征向量中心性对于了解哪些节点可以快速将信息分发到许多其他节点很有用。如果您认识很多人脉很好的人,则可以
    非常有效地传播信息。
    中间度:
    中间非常擅长于找到连接两个网络的不同部分的节点。如果您是连接两个集群的唯一对象,那么这些集群之间的所有通信都必须通过您。与集线器相比,这种节点通常称为代理。中间性不是找到经纪人
    的唯一方法而是一种快速的方法,可以使您了解哪些节点很重要,这不是因为它们本身有很多联系,而是因为它们站在组之间,具有网络连接和凝聚力。

"""


# 查看网络密度
density = nx.density(G)
print("Network density:", density)

# 计算某两个节点之间的最短路径
fell_whitehead_path = nx.shortest_path(G, source="Margaret Fell", target="George Whitehead")
print("Shortest path between Fell and Whitehead:", fell_whitehead_path)

# 计算图的直径
    # 可能一个图存在多个子图,此时找到最大的子图并仅计算该子图的直径即可
    # 1.检查是否只有一个子图
    # 2.获取所有子图列表
    # 3.找到最大的图
    # 4.新建一个图保存最大图,并计算直径

print(nx.is_connected(G))
components = nx.connected_components(G)
largest_component = max(components, key=len)
subgraph = G.subgraph(largest_component)
diameter = nx.diameter(subgraph)
print("Network diameter of largest component:", diameter)


# 计算传递性
triadic_closure = nx.transitivity(G)
print("Triadic closure:", triadic_closure)

# 计算度
degree_dict = dict(G.degree(G.nodes()))
nx.set_node_attributes(G, degree_dict, 'degree')

print(G.nodes['William Penn']["degree"])

# 按照"度"进行排序,获取前20的社交达人
sorted_degree = sorted(degree_dict.items(), key=itemgetter(1), reverse=True)
print("Top 20 nodes by degree:")
for d in sorted_degree[:20]:
    print(d)

# 计算特征向量中心度和中间度
eigenvector_dict = nx.eigenvector_centrality(G) 
betweenness_dict = nx.betweenness_centrality(G)
# Assign each to an attribute in your network
nx.set_node_attributes(G, eigenvector_dict, 'eigenvector')
nx.set_node_attributes(G, betweenness_dict, 'betweenness')

# 排序
sorted_betweenness = sorted(betweenness_dict.items(), key=itemgetter(1), reverse=True)
print("Top 20 nodes by betweenness centrality:")
for b in sorted_betweenness[:20]:
    print(b)


"""
是不是高度就代表高中间度?
将每个人的这两个数据打印出来进行比较
"""
#First get the top 20 nodes by betweenness as a list
top_betweenness = sorted_betweenness[:20]

#Then find and print their degree
for tb in top_betweenness: # Loop through top_betweenness
    degree = degree_dict[tb[0]] # Use degree_dict to access a node's degree, see footnote 2
    print("Name:", tb[0], "| Betweenness Centrality:", tb[1], "| Degree:", degree)




"""
Advanced NetworkX:具有模块化的社区检测

有关网络数据集的另一个常见问题是,较大的社会结构中的子群体或社区是什么。您的网络是一个每个人都认识的大家庭吗?
还是仅由一个或两个中间人连接的较小子组的集合?网络中的社区检测领域旨在回答这些问题。
计算网络中社区,集团和集群的方法有很多,但是当前最受欢迎的方法是模块化。
模块化是衡量网络中相对密度的一种方法:一个社区(称为模块或模块化类)相对于其模块中的其他节点具有较高的密度,但与外部节点相比则具有较低的密度。
模块化为您提供了网络脆弱程度的总体评分,该评分可用于划分网络并返回各个社区。
"""


"""
下面代码是检测社区的数量,并每个人所属的社区信息添加到个人的属性中,这样每个人就有了自己的社区号
"""
# 社区检测,尝试确定适合该图的社区数量,并根据这些社区将所有节点分组为子集
communities = community.greedy_modularity_communities(G)
# 将每个人以及对应的子网络编号存放到字典中,key=名字,value=所属子网络
modularity_dict = {}
for i,c in enumerate(communities):
    for name in c:
        modularity_dict[name] = i
# 将所属子网络的信息添加到节点属性
nx.set_node_attributes(G, modularity_dict, 'modularity')



"""
以社区为单位查看某个社区的人的特征,比如特征向量中心度,以编号0为例
"""

# First get a list of just the nodes in that class
class0 = [n for n in G.nodes() if G.nodes[n]['modularity'] == 0]

# Then create a dictionary of the eigenvector centralities of those nodes
class0_eigenvector = {n:G.nodes[n]['eigenvector'] for n in class0}

# Then sort that dictionary and print the first 5 results
class0_sorted_by_eigenvector = sorted(class0_eigenvector.items(), key=itemgetter(1), reverse=True)

print("Modularity Class 0 Sorted by Eigenvector Centrality:")
for node in class0_sorted_by_eigenvector[:5]:
    print("Name:", node[0], "| Eigenvector Centrality:", node[1])


"""
在像这样的小型网络中,一项常见的任务是查找并列出所有模块化类及其成员。
"""
for i,c in enumerate(communities):
    if len(c) > 2:
        print('Class '+str(i)+':', list(c))

 

posted @ 2020-11-09 13:30  止一  阅读(195)  评论(0编辑  收藏  举报