【3】数据分析-4-2-由煮面条到图论到图论--igraph
igrpah
一、安装
py2安装
pip install python-igraph
二、教学示例
2.1 Igraph网络图创建与优化
以中国古代战国七雄为对象(点),不同国家若地理位置相邻,则认为存在地理联系(边),以此为基准,试着创建一个简单的抽象网络图(这里只探究两两相邻关系,不保证地理方位的正确性):
# 创建一个空对象
g = igraph.Graph()
# 添加网络中的点
vertex = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
g.add_vertices(vertex)
# 添加网络中的边
edges = [('a', 'c'), ('a', 'e'), ('a', 'b'), ('b', 'd'), ('b', 'g'), ('c', 'e'),
('d', 'f'), ('d', 'g'), ('e', 'f'), ('e', 'g'), ('f', 'g')]
g.add_edges(edges)
# -----------------------其它信息-----------------------------
# 国家名称
g.vs['label'] = ['齐', '楚', '燕', '韩', '赵', '魏', '秦']
# 国家大致相对面积(为方便显示没有采用真实面积)
g.vs['aera'] = [50, 100, 70, 40, 60, 40, 80]
# 统计日期
g['Date'] = '公元前279年'
# -----------------------简单作图-----------------------------
# 选择图的布局方式
layout = g.layout('kk')
# 用Igraph内置函数绘图
igraph.plot(g, layout)
战国势力地理关系图1.0
这张图不是很美观,那么如何去优化和完善它呢?比如说点的颜色、大小,边的长短、粗细等。可以通过调节igraph.plot()中的参数达到我们想要的效果:
# -----------------------设置参数-----------------------------
# 参数集合。visual_style是一个参数字典,可以动态添加想要个性化设定的参数
visual_style = {}
# 根据相对面积,设置点的大小
visual_style["vertex_size"] = g.vs['aera']
# 根据国家实力,设置点的颜色
visual_style["vertex_color"] = [color_map[power] for power in g.vs["power"]]
# 边的粗细(这里随机生成)
visual_style['edge_width'] = [2 + 5*np.random.rand() for i in np.arange(11)]
# 图尺寸
visual_style["bbox"] = (600, 480)
# 边缘距离
visual_style["margin"] = 50
# 布局方式
visual_style["layout"] = layout
# -----------------------画图-----------------------------
igraph.plot(g, **visual_style)
PS:看懂以上代码,就了解了Igraph中基本的网络图的构建方法,以及可视化展示的常用参数设置方法。接下来,重点讲讲如何从这些网络图中找出一些有价值的信息。
2.2 网络图信息价值挖掘
那么,基于这张图,有哪些有价值的信息可以挖掘呢?
1.节点的度(degree)。
概念:某节点的度,只与该节点有直接联系的其它点的个数。在有向图中,度还可分为出度(out-defree)和进度(in-degree),它一定程度上表现了某节点周围的密集程度。 在本例中,度的实际含义是一个国家的邻国数量。
# 点的度
numbers = g.degree()
# 不同国家邻国数量
neighbors = dict(zip(g.vs['label'], numbers))
print(neighbors)
输出结果:
{‘魏’: 3, ‘燕’: 2, ‘赵’: 4, ‘楚’: 3, ‘齐’: 3, ‘韩’: 3, ‘秦’: 4}
2.中介中心性(betweenness)。
概念:一个结点担任其它两个结点之间最短路路劲的桥梁的次数,次数越多,该数越大。 在本例中指的是国家起到的枢纽作用大小。
# 计算中介中心性
betweenness = g.betweenness()
# 保留一位小数
betweenness = [round(i, 1) for i in betweenness]
# 与国家名对应
country_betweenness = dict(zip(g.vs['label'], betweenness))
print('不同国家的中介中心性(枢纽作用):\n', country_betweenness)
输出结果:
不同国家的中介中心性(枢纽作用):
{'魏': 0.8, '燕': 0.0, '赵': 4.2, '楚': 1.8, '齐': 1.8, '韩': 0.5, '秦': 1.8}
3.另一个非常常见的操作是找两个点之间的最短路径。
概念:任选两个节点,连通这两个节点的最少边数,定义为这两个节点的最短路径长度。 当然,这里所指的最短路径,只用来表示不同国家间的抽象地理关系,和实际中的最短路径含义并不一致。
#计算魏国和齐国的最短路径(如有多条路径,只取其中之一)
path = g.get_shortest_paths('c', 'd')[0]
seq = g.vs.select(path)
print('燕韩之间的最短路径: ', seq['label'])
输出文字结果:
燕韩之间的最短路径: ['燕', '齐', '楚', '韩']
将最短路径用红色标记:
# --------------------------路径-----------------------------
path = seq['name']
# ---------------------给边设定颜色---------------------------
# 默认为黑色
edge_color = dict(zip(edges, ['black']*11))
# 最短路径里的边映射为红色。映射时需要考虑元组中对象顺序,这里按字母从小到大排序
for i in np.arange(np.size(path)-1):
if path[i] < path[i+1]:
edge_color[(path[i], path[i + 1])] = 'red'
else:
edge_color[(path[i + 1], path[i])] = 'red'
visual_style['edge_color'] = [edge_color[edge] for edge in edges]
# ------------------------画图------------------------------
m = igraph.plot(g, **visual_style)
四、我的案例
4.1
代码示例
import igraph
import pandas as pd
from igraph import *
import matplotlib.pyplot as plt
import numpy as np
print(igraph.__version__)
g = Graph()
input_fp = 'summary/cell_info_merge_sort.xlsx'
df = pd.read_excel(input_fp)
df['gemline'] = df['HC_blastp_hit'].str.split('_',expand=True)[0] + '-' + df['LC_blastp_hit'].str.split('_',expand=True)[0]
df = df[df['choosed']==1]
df['cdr_num_normal'] = df['cdr_num'].apply(np.log)
max_cdr = df['cdr_num_normal'].max()
colors = plt.get_cmap('OrRd')
pair_edge = []
vertex = []
verter_hash = {}
germline_hit = {}
for index_1,row_1 in df.iterrows():
germline = row_1['gemline']
barcode = row_1['barcode']
umis_min = row_1['umis_min']
cdrs = row_1['cdr_num_normal']
pair_edge.append((row_1['barcode'],row_1['gemline']))
distance = 200 - row_1['HC_blastp_identity_1(%)'] -row_1['LC_blastp_identity_1(%)']
vertex.append(germline)
vertex.append(barcode)
if germline not in verter_hash:
verter_hash[germline] = {}
if barcode not in verter_hash:
verter_hash[barcode] ={}
verter_hash[germline]['size'] =1
verter_hash[germline]['edge_arrow_size'] = distance
verter_hash[germline]['vertex_label'] = ''
verter_hash[germline]['vertex_label_size'] = 1
color = colors(0.1)
verter_hash[germline]['vertex_color'] = color
verter_hash[barcode]['size'] = umis_min *20
verter_hash[barcode]['edge_arrow_size'] = distance
verter_hash[barcode]['vertex_label'] = ''
verter_hash[barcode]['vertex_label_size'] = 1
color = colors(np.true_divide(cdrs,max_cdr))
verter_hash[barcode]['vertex_color'] = color
if germline not in germline_hit:
germline_hit[germline] = 0
germline_hit[germline] +=1
#label
germline_hit_sorted = sorted(germline_hit.items(),key=lambda vv:vv[1],reverse=True )[:5]
# germline_hit_sorted = ['test1','test2','test3']
for one_key in germline_hit_sorted:
verter_hash[one_key[0]]['vertex_label'] = one_key[0]
verter_hash[one_key[0]]['vertex_label_size'] = 10
vertex = list(set(vertex))
# vertex = [0,1,2]
g.add_vertices(vertex)
g.add_edges(pair_edge)
layout = g.layout_fruchterman_reingold() # 这个版布局是为了所有的cluster的线条不交叉
visual_style = {}
visual_style["layout"] = layout
visual_style["vertex_size"] = [verter_hash[ii]['size'] for ii in vertex]
visual_style["edge_arrow_size"] = [verter_hash[ii]['edge_arrow_size'] for ii in vertex]
visual_style["vertex_label"] = [verter_hash[ii]['vertex_label'] for ii in vertex]
visual_style["vertex_color"] = [verter_hash[ii]['vertex_color'] for ii in vertex]
visual_style["vertex_label_size"] = [verter_hash[ii]['vertex_label_size'] for ii in vertex]
plot(g, **visual_style)
参考资料
这里是一个广告位,,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn