前言
最近在朋友圈拜读了Python爱好者社区公众号转载的徐麟兄发布的《“水泊梁山“互联网有限公司一百单八将内部社交网络》,内容相当精彩,收益匪浅。本文带领我第一次接触倒了“社交网络以及社群发现”,开拓了知识领域,也深入见识了Gephi社交网络分析的魅力。
于是准备深入研究并实现其文章中的内容。细看之下,发现此文虽然数据分析思路很新奇,但是代码实现比较粗糙,既缺乏相关的python包说明,文末也没有github代码链接。经过几番尝试,模仿学习基本实现本文内容,特此记录下来分享一下。
STEP1:分析原文代码
首先说明一下原文代码的问题,以及原文代码用到的python包。
我讲原文代码拷贝拼接后,发现第一个问题,包引用的问题。
第一个重量级的包,“haohan = pd.read_excel('水浒人物.xlsx')”通过这句以及平时的经验可以知道引用了pandas包,通用写法“import pandas as pd”。
第二个比较蹊跷的包引用是“bar = Bar("水泊梁山年收入TOP10")”。可能是本人经验有限,没有用过Bar包(也可能是模块)。于是求助百度,几番搜索尝试之下,终于找到了pyecharts。核对后面引用的方法,确定是此包无疑。
python包有了,于是安装两个包。安装语句如下:
pip install pandas
pip install pyecharts
本以为解决了包的问题,就可以运行徐麟兄的代码,岂知事情并非如此简单。
PART1代码如下:
with open("水浒传全文.txt", encoding='gb18030') as file:
shuihu = file.read()
shuihu = shuihu.replace('\n','')
shuihu_set = shuihu.split(' ')
shuihu_set=[k for k in shuihu_set if k!='']
songjiang_set=[k for k in shuihu_set if '宋江' in k]
haohan = pd.read_excel('水浒人物.xlsx')
haohan['出场段落']=0
第一二行是读取文本文件,弱弱的说一句,缺少了文件关闭语句。不过由于此文是读取文件,不影响程序执行。不过从代码规范性看,file.colse()是必不可少的。
第三、四、五行代码是对读取的内容进行简单处理并切分成一段一段的list集合。
不知徐麟兄是故意为之还是笔误,第三行将换行符替换成了空字符,第四行又用空格符进行切分。按照后文提到的按段落划分,应该是将换行符替换成空格符,然后根据空格符切分才合理。
第七行获取所有段落中包含“宋江”字符串的段落;
第八行读取水浒人物表生成DataFrame,暂无该文档,不知其内容。
第九行更诡异,直接将DataFrame的一个新字段全部设置为0.
正是由于第九行全部设置为0,所以我运行后面的代码得到的结果如下。
很诡异吧,全部是0。但是分析了上面的代码我才知道了原因。
认真学习了徐麟兄后面的内容,基本明白了其“出场段落”字段的含义。后文写到“作为能够长期运作的互联网公司,在员工收入分配方面始终员工KPI(出场段落数量)相挂钩,我们来看一下年薪TOP10和BOTTOM10”,其实只是普通的wordcount单词统计的一个变异,大致意思就是将原文按照行或者段落划分,统计水浒108将的名字在所有段落中出现的段落数,即每一个人物(文章称haohan)如果在一个自然段中出现一次或者多次,则视为该人物KPI+1.
上文第七行以宋江为例的代码可以看出这一点。
songjiang_set=[k for k in shuihu_set if '宋江' in k]
PART2是引用pyecharts包中的Bar模块实现数据展现,这一部分内容比较简单易懂,也非我所长,略过后文再叙。
PART3部分的代码如下:
net_df = pd.DataFrame(columns=['Source','Target','Weight','Source_Ratio','Target_Ratio'])
for i in range(0,107):
for j in range(i+1,108):
this_weight = len([k for k in shuihu_set if haohan['使用名'][i] in k and haohan['使用名'][j] in k])
net_df=net_df.append({'Source':haohan['姓名'][i],'Target':haohan['姓名'][j],
'Weight':this_weight,
'Source_Ratio':this_weight/haohan['出场段落'][i],
'Target_Ratio':this_weight/haohan['出场段落'][j]},
ignore_index=True)
print(str(i)+':'+str(j))
这部分代码再次让我感受到了迷茫。继续尝试解读一下吧。
第一行,定义了一个五个字段的DataFrame;
第二、三行创建了一个两层的循环,让水浒108好汉两两成对进行匹配成对;
第四行计算两两成对的好汉出现在同一个自然段或者说原文同一行的次数;
第五至九行给DataFrame拼接数据;
第十行只是输出了两两成对的姓名。
That's all?这样就完了?
其后只是简单的一句“我们在去除一些社交网络节点数据(聊天总数较少或聊天数量占一方数量比例过少)的情况后,用Gephi软件绘制出了整体的社交网络图如下:”就把我们带入了分析结果的页面。作为读者,个人是觉得徐麟兄这篇文章是不太负责任的,写得太粗糙了。
STEP2:亮出我的代码
为了能实现后面的内容,我只好自行补充完善了这部分代码。
首先,准备两个素材,《水浒传.txt》和《水浒人物.xlsx》,我自行去网上下载了这本小说文字版,并找到了所有人物姓名。经检查,小说文章是按行划分段落,满足要求。《水浒人物.xlsx》仅有一列,字段名为“姓名”。
然后改写代码如下:
with open(u'水浒传.txt','r') as f:
shuihu_set = f.readlines()
f.close()
haohan = pd.read_excel(u'水浒人物.xlsx')
haohan['出场段落'] = haohan.apply(lambda x:len([k for k in shuihu_set if x[u'姓名'] in k]), axis = 1)
第一二三行是读取文本文件,本次采用自带的os模块之间读取文件每一行生成一个list。
第三行读取excel文档中水浒人物的姓名。
第四行通过水浒人物的姓名计算出对于人物在水浒传中的“KPI”,即(出场段落数量)
至此,数据准备完毕。
STEP3:沿用原来的分析代码生成分析结果。
原文代码如下:
haohan.sort_values('出场段落',ascending=False,inplace=True)
attr = haohan['姓名'][0:10]
v1 = haohan['出场段落'][0:10]
bar = Bar("水泊梁山年收入TOP10")
bar.add("年收入(万)", attr, v1, is_stack=True,is_label_show=True)
bar.render('水泊梁山年收入TOP10.html')
haohan.sort_values('出场段落',ascending=True,inplace=True)
attr = haohan['姓名'][0:10]
v1 = haohan['出场段落'][0:10]
bar = Bar("水泊梁山年收入BOTTOM10")
bar.add("年收入(万)", attr, v1, is_stack=True,is_label_show=True)
bar.render('水泊梁山年收入BOTTOM10.html')
本次生成的结果截图如下:
两图数据和徐麟兄的结果略有差异,可能是我们用的文本文件不一致造成的。这个并不影响我们进一步分析。
STEP4:生成数据及社交网络分析
到了社交网络这一部分了,我并不知道“我们在去除一些社交网络节点数据(聊天总数较少或聊天数量占一方数量比例过少)的情况后”去除了一些什么数据,只能尝试这用一下Gephi软件。
根据百度上的了解和对徐麟原文的分析,生成社交网络总共需要
'Source','Target','Weight','Source_Ratio','Target_Ratio'
五个字段的数据,经分析,我改写的程序完全可以接上第三部分的程序,因此不做任何修改,仅将结果导出到csv文件。
加上代码“`
js
net_df.to_csv('sjwl.csv',index=False,sep=',')
”`
生成数据如上图。
接下来下载Gephi软件并安装。下载到的安装包中竟然还有一份使用教程,简直神助攻!
安装好以后,打开软件,进入主界面。
好吧,最开始导入数据后结果如下图。
我的想法和大家一样,这是什么鬼!
几番琢磨和调整,得到的数据图如下,只能说差强人意了。最后用到的数据只有前面三列,后面两列程序也没有跑出数据。
这里把导入分析的数据截个图。
文章就写到这里,Gephi软件还需要花时间再研究研究。
完整代码如下:
import pandas as pd
from pyecharts import Bar
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
with open(u'水浒传.txt','r') as f:
shuihu_set = f.readlines()
f.close()
haohan = pd.read_excel(u'水浒人物.xlsx')
haohan['出场段落'] = haohan.apply(lambda x:len([k for k in shuihu_set if x[u'姓名'] in k]), axis = 1)
haohan.to_csv('haohan.csv',index=False,sep=',')
haohan.sort_values('出场段落',ascending=False,inplace=True)
attr = haohan['姓名'][0:10]
v1 = haohan['出场段落'][0:10]
bar = Bar("水泊梁山年收入TOP10")
bar.add("年收入(万)", attr, v1, is_stack=True,is_label_show=True)
bar.render(u'水泊梁山年收入TOP10.html')
haohan.sort_values('出场段落',ascending=True,inplace=True)
attr = haohan['姓名'][0:10]
v1 = haohan['出场段落'][0:10]
bar = Bar("水泊梁山年收入BOTTOM10")
bar.add("年收入(万)", attr, v1, is_stack=True,is_label_show=True)
bar.render(u'水泊梁山年收入BOTTOM10.html')
net_df = pd.DataFrame(columns=['Source','Target','Weight','Source_Ratio','Target_Ratio'])
for i in range(0,107):
for j in range(i+1,108):
this_weight = len([k for k in shuihu_set if haohan['姓名'][i] in k and haohan['姓名'][j] in k])
net_df=net_df.append({'Source':haohan['姓名'][i],'Target':haohan['姓名'][j],
'Weight':this_weight,
'Source_Ratio':this_weight/haohan['出场段落'][i],
'Target_Ratio':this_weight/haohan['出场段落'][j]},
ignore_index=True)
print(str(i)+':'+str(j))
net_df.to_csv('sjwl.csv',index=False,sep=',')
很少写技术类的博文,有些啰嗦了。
原文发布时间为:2018-07-24
本文作者: 蚂蚁
本文来自云栖社区合作伙伴“ Python爱好者社区”,了解相关信息可以关注“ Python爱好者社区”