#2018-03-30 09:21:39 March Friday the 13 week, the 089 day SZ SSMR
python数据挖掘课程】十七.社交网络Networkx库分析人物关系(初识篇) 

图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,
这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。


图G=(V,E)是一个二元组(V,E),集合V中的元素称为图G的定点(或节点、点),而集合E的元素称为边(或线)。通常,描绘一个图的方法是把定点画成一个小圆圈,
如果相应的顶点之间有一条边,就用一条线连接这两个小圆圈,如何绘制这些小圆圈和连线时无关紧要的,重要的是要正确体现哪些顶点对之间有边,哪些顶点对之间没有边 
二. Networkx基础知识


Networkx是一个用来创建、操作、研究复杂网络结构的Python扩展包。它支持图的快速创建,同时常用的图算法。同时Networkx扩展包完善了Python的科学计算工具集,如Scipy、Numpy等。
2.基础代码
下面首先给大家看一个Networkx调用draw(G)绘图的代码。
# -*- coding: utf-8 -*-
import networkx as nx
import matplotlib.pyplot as plt

#定义有向图
DG = nx.DiGraph() 
#添加五个节点(列表)
DG.add_nodes_from(['A', 'B', 'C', 'D', 'E'])
print (DG.nodes())
#添加边(列表)
DG.add_edges_from([('A', 'B'), ('A', 'C'), ('A', 'D'), ('D','A'),('E','A'),('E','D')])
print(DG.edges())
#绘制图形 设置节点名显示\节点大小\节点颜色
colors = ['red', 'green', 'blue', 'yellow']
nx.draw(DG,with_labels=True, node_size=900, node_color = colors)
plt.show()

3.Networkx详细介绍
(1) 导入扩展包创建无多重边有向图
    import networkx as nx
    DG = nx.DiGraph()
图对象主要包括点和边,Networkx创建图包括四类:Graph无多重边无向图,DiGraph无多重边有向图,MultiGraph有多重边无向图,MultiDiGraph有多重边有向图。 

(2) 增加点,采用序列增加五个点
    DG.add_nodes_from(['A', 'B', 'C', 'D', 'E'])
增加点可以通过G.add_node(1)、G.add_node("first_node")函数增加一个点,也可以调用DG.add_nodes_from([1,2,3])、DG.add_nodes_from(D)函数批量增加多个点。删除点调用DG.remove_node(1)或DG.remove_nodes_from([1,2,3])实现。


(3) 增加边,采用序列增加多条边
    DG.add_edges_from([('A', 'B'), ('A', 'C'), ('A', 'D'), ('D','A')])
增加一条边可以调用DG.add_edge(1,2)函数,表示在1和2之间增加一个点,从1指向2;也可以定义 e=(1,2) 边,在调用DG.add_edge(*e)函数实现,注意*用来获取元组(1,2)中的元素。增加多条表则使用DG.add_edges+from([(1,2), (2,3)])函数实现。
同理,删除边采用remove_edge(1,2)函数或remove_edges_from(list)实现。



(4) 访问点和边
    DG.nodes()  #访问点,返回结果:['A', 'C', 'B', 'E', 'D']
    DG.edges()  #访问边,返回结果:[('A', 'C'), ('A', 'B'), .... , ('D', 'A')]
    DG.node['A']         #返回包含点和边的列表
    DG.edge['A']['B']   #f返回包含两个key之间的边


(5) 查看点和边的数量
    DG.number_of_nodes()  #查看点的数量,返回结果:5
    DG.number_of_edges()  #查看边的数量,返回结果:6
    DG.neighbors('A')          #所有与A连通的点,返回结果:['C', 'B', 'D']
    DG['A']  #所有与A相连边的信息,{'C': {}, 'B': {}, 'D': {}},未设置属性


(6) 设置属性
可以给图、点、边赋予各种属性,其中权值属性最为常见,如权重、频率等。
    DG.add_node('A', time='5s')
    DG.add_nodes_from([1,2,3],time='5s')
    DG.add_nodes_from([(1,{'time':'5s'}), (2,{'time':'4s'})])  #元组列表
    DG.node['A']  #访问
    DG.add_edges_from([(1,2),(3,4)], color='red')

三. 分析人物关系网络

写到这里正式开始我们的人物关系分析,首先统计了我这门课程的105个学生信息,如下表所示,主要包括姓名、性别、学院、班级、宿舍等内容,这里主要根据学院信息简历人物关系。
步骤如下:
1.调用Pandas库读取data.csv文件,并获取学生姓名,姓名存储在一个数组里;
2.计算各个学生的共现矩阵,比如A和B都是同一个学院的,则共现依次,权重加1。注意,这里的学生来自各个学院,分析他们学院之间的关系;
3.将共现矩阵存储至word_node.txt文件中,格式为"学生A 学生B 共现词频";
4.读取word_node.txt文件,采用空格分割,绘制对应关系图,如果学生A和学生B共同出现,则建立一条边,表示存在关系。类似的,如果做小说或电视人物关系分析,如果人物某一章同时出现,则认为存在关系建立一条边。
5.调用Networkx库绘制图形。
#由于没有对应数据,这节课笔记没有验证,不过用来分析电视剧,红楼梦人物的关系挺好的,可以作为一个项目来做了。
import pandas as pd
import numpy as np
import codecs
import networkx as nx
import matplotlib.pyplot as plt


""" 第一步:读取数据并获取姓名 """
data = pd.read_csv("data.csv",encoding ="gb2312") #中文乱码
print data[:4]
print data[u'姓名'] #获取某一列数据
print type(data[u'姓名'])
name = []
for n in data[u'姓名']:
    name.append(n)
print name[0]


""" 第二步:计算共现矩阵 定义函数实现 """
a = np.zeros([2,3])
print a
print len(name)
word_vector = np.zeros([len(name),len(name)]) #共现矩阵

#1.计算学院共线矩阵
i = 0
while i<len(name):  #len(name)
    academy1 = data[u'学院'][i]
    j = i + 1
    while j<len(name):
        academy2 = data[u'学院'][j]
        if academy1==academy2: #学院相同
            word_vector[i][j] += 1
            word_vector[j][i] += 1
        j = j + 1   
    i = i + 1
print word_vector
np_data = np.array(word_vector)  #矩阵写入文件
pd_data = pd.DataFrame(np_data)
pd_data.to_csv('result.csv')
#2.计算大数据金融班级共线矩阵
#3.计算性别共线矩阵
#4.计算宿舍楼层共线矩阵
"""
i = 0
while i<len(name):  #len(name)
    academy1 = data[u'宿舍楼层'][i]
    j = i + 1
    while j<len(name):
        academy2 = data[u'宿舍楼层'][j]
        if academy1==academy2: #相同
            word_vector[i][j] += 1
            word_vector[j][i] += 1
        j = j + 1   
    i = i + 1
print word_vector
"""


""" 第三步:共现矩阵计算(学生1 学生2 共现词频)文件 """
words = codecs.open("word_node.txt", "a+", "utf-8")
i = 0
while i<len(name):  #len(name)
    student1 = name[i]
    j = i + 1
    while j<len(name):
        student2 = name[j]
        #判断学生是否共现 共现词频不为0则加入
        if word_vector[i][j]>0:
            words.write(student1 + " " + student2 + " " 
                + str(word_vector[i][j]) + "\r\n")
        j = j + 1
    i = i + 1
words.close()


""" 第四步:图形生成 """
a = []
f = codecs.open('word_node.txt','r','utf-8')
line = f.readline()
print line
i = 0
A = []
B = []
while line!="":
    a.append(line.split())   #保存文件是以空格分离的
    print a[i][0],a[i][1]
    A.append(a[i][0])
    B.append(a[i][1])
    i = i + 1
    line = f.readline()
elem_dic = tuple(zip(A,B)) 
print type(elem_dic)
print list(elem_dic)
f.close()

import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']   
matplotlib.rcParams['font.family']='sans-serif'

colors = ["red","green","blue","yellow"]
G = nx.Graph()
G.add_edges_from(list(elem_dic))
#nx.draw(G,with_labels=True,pos=nx.random_layout(G),font_size=12,node_size=2000,node_color=colors) #alpha=0.3
#pos=nx.spring_layout(G,iterations=50)
pos=nx.random_layout(G)
nx.draw_networkx_nodes(G, pos, alpha=0.2,node_size=1200,node_color=colors)
nx.draw_networkx_edges(G, pos, node_color='r', alpha=0.3) #style='dashed'
nx.draw_networkx_labels(G, pos, font_family='sans-serif', alpha=0.5) #font_size=5
plt.show()