1.数据描述
数据来自于国家人口与健康科学数据共享平台的方剂现代应用数据库 dbcenter.cintcm.com/channel-lin…
使用关键字“肝炎”进行检索,可得到记录476条。
以“养阴清热健脾利湿方”为例,在方剂的详情页里有处方来源、药物组成、功效和主治等内容,爬取了处方来源、药物组成、功效和主治这四个字段。
对于构建中药成分共现网络,就可以使用数据中的药物组成字段来进行构建。部分结果如下所示:
2.读取数据,并构建成份共现网络
根据清洗得到的中药方剂成份数据,来构建中药成份共现网络。节点是方剂中的药材,如果两种药材在同一个方剂中出现,则这两个节点之间就形成了一条边。下面是中药成分共现网络的邻接矩阵,矩阵元素是两种药材的共现频次:
为方便读取,在Excel中创建了一个不含节点标签的邻接矩阵。
读取邻接矩阵:
import pandas as pd
import xlrd
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import plotly.offline as py
import plotly.graph_objects as go
import networkx as nx
#从Excel中读邻接矩阵,返回二维数组
def excel_to_array(path,sheet):
table = xlrd.open_workbook(path).sheets()[sheet]#获取第san个sheet表
row = table.nrows # 行数
col = table.ncols # 列数
datamatrix = np.zeros((row, col))#生成一个nrows行ncols列,且元素均为0的初始矩阵
for x in range(col):
cols = np.matrix(table.col_values(x)) # 把list转换为矩阵进行矩阵操作
datamatrix[:, x] = cols # 按列把数据存进矩阵中
return datamatrix
Array=excel_to_array('./matrix.xlsx',1)
#读节点标签
label_table = xlrd.open_workbook('./matrix.xlsx').sheets()[0]#获取第san个sheet表
labels=label_table.col_values(0)
#删除头部空值
del labels[0]
#用于创建网络的数据
DF_adj = pd.DataFrame(Array,index=labels,columns=labels)
利用networkx创建药材共现网络:
#创建图
G = nx.Graph()
#添加节点
G.add_nodes_from(labels)
#添加边,出现的次数作为权重
for i in range(DF_adj.shape[0]):
col_label = DF_adj.columns[i]
for j in range(DF_adj.shape[1]):
row_label = DF_adj.index[j]
node = DF_adj.iloc[i,j]
if node != 0:
G.add_edge(col_label,row_label,weight=node)
初始网络情况,包括节点和边的数量:
3.初步图像绘制
这时用随机布局画图结果如下:
与下图的理想效果相差较大。
4.图像优化
第一步 因为节点太多很难用一张图展示清楚,所以先去除掉一部分节点和边,选取节点度排名前50的节点进行展示。 #取出度排名前50的药材(即从网络中删掉剩余的节点)
sort=sorted(dict(G.degree()).items(),key=lambda d:d[1],reverse=True)
remove =[node for node,degree in sort[50:len(sort)-1]]
#remove = [node for node,degree in sort[0:50] if degree <= 10]
G.remove_nodes_from(remove)
第二步 进一步调整,想要节点按度值的大小有着不同的大小和深浅,连边按边权重的大小有着不同的粗细、深浅和样式。
将节点和边进行分组:
#按节点度值将节点分为大、中、小 三个组
nlarge=[u for (u,v) in G.nodes(data=True) if G.degree(u)>40]
nmid=[u for (u,v) in G.nodes(data=True) if G.degree(u)>35 and G.degree(u)<=40]
nsmall=[u for (u,v) in G.nodes(data=True) if G.degree(u)<=35]
#按边权重值值将节点分为大、中、小 三个组
elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] > 20]
emid = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] <= 20 and d['weight'] >10]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d['weight'] <= 10 ]
绘图:
#设置图像大小
plt.figure(figsize=(30,30))
#运用布局
pos = nx.spring_layout(G)
#画点
nx.draw_networkx_nodes(G, pos, nodelist=nlarge,node_size=2000,node_color='cornflowerblue')
nx.draw_networkx_nodes(G, pos, nodelist=nmid,node_size=1000,alpha=0.6,node_color='cornflowerblue')
nx.draw_networkx_nodes(G, pos, nodelist=nsmall,node_size=500,alpha=0.2,node_color='cornflowerblue')
#画边
nx.draw_networkx_edges(G, pos, edgelist=elarge,edge_color='cornflowerblue',width=8)
nx.draw_networkx_edges(G, pos, edgelist=emid,edge_color='cornflowerblue',alpha=0.6, width=4)
nx.draw_networkx_edges(G, pos, edgelist=esmall,width=1, alpha=0.2, edge_color='cornflowerblue', style='dashed')
#显示标签
nx.draw_networkx_labels(G, pos, font_size=15, font_family='sans-serif')
#不显示坐标轴
plt.axis('off')
#储存图片
plt.savefig('./test2.jpg')
plt.show()
最终效果: