上学期为了做一个研究的作业,拿到了一个学习平台上用户给其他用户发表的博客评论的数据,要用这些数据做社会网络分析(没错,就是SNA)。但是ucinet这个社会网络分析工具只接受矩阵格式的数据,本白嫖大王于是在CSDN、知乎、各种问答网站上一通搜索提问邀请三连,最终啥也没搜到,只好自己动手丰衣足食。在自己提的知乎问题下面回复已解决后出乎意料竟然有很多小伙伴找我要代码,碍于知乎不能发文件有的小伙伴又不想提供邮箱,我就写个博客,下次直接扔个链接。

言归正传,首先粘上完整代码方便和我一样的白嫖大王复制粘贴。(netdraw是画社会网络图用的,如果你有ucinet等专门的社会网络分析工具这一段可以删掉)

注:代码作者为编程菜鸟,大概齐能用,不要期望太高。
切记:文件名要改成自己的,存储在同一个文件夹下。

import pandas as pd
from bisect import bisect_left
import csv
from networkx import *
import matplotlib.pyplot as plt

def list(l1, l2):
    for i in range(0, len(l1)):
        if l1[i] not in l2:
            l2.append(l1[i])
    return l2

def list_with_repeat(l1, l2):
    for i in range(0, len(l1)):
        l2.append(l1[i])
    return l2

def read(fname):
    data = pd.read_csv(fname)
    # print(data.head)
    user = []
    new1 = []
    new2 = []
    comment_user = list_with_repeat(data['user_id'], new1)
    article_user = list_with_repeat(data['commented_id'], new2)
    user = list(data['user_id'], user)
    user.sort()
    # print(comment_user)
    # print(article_user)
    #print(user)
    return user, comment_user, article_user

def toMatrix(fpath, list, com, art):
    header = list
    print(list)
    # print(type(com[0]))
    # print(type(list[0]))
    # print(type(list[0]))
    bool_list = []

    with open(fpath, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(list)

    matrix = [[0 for _ in range(len(list))] for _ in range(len(list))]
    # matrix = [[0]*731]*731
    for i in range(0,len(com)):
        x = com[i]
        y = art[i]
        # print(x)
        x_bool = x in list
        y_bool = y in list
        # print(y)
        # print(x_bool)
        bool_list.append(x_bool)
        if x_bool == True and y_bool == True:
            x_index = list.index(x)
            y_index = list.index(y)
            # print(x_index)
            # print(y_index)

            matrix[x_index][y_index] += 1
        # print(matrix)
        else:
            # print('not in')
            pass

    with open('comdat.csv', 'w', newline='') as ff:
        writer = csv.writer(ff)
        for j in range(0,len(list)):
            writer. writerow(matrix[j])
            # print(j)

    print(matrix)
    return matrix

'''
def netdraw(nodelist, matrix):
    G = networkx.Graph()
    point = nodelist
    G.add_nodes_from(point)
    edgelist = []
    for i in range(len(point)):
        for j in range(len(point)):
            edgelist.append((matrix[i][0], matrix[i][j]))
    G = networkx.graph(edgelist)
    position = networkx.circular_layout(G)
    networkx.draw_networkx_nodes(G, position, nodelist=point, node_color='blue')
    networkx.draw_networkx_edges(G, position)
    networkx.draw_networkx_labels(G, position)
    plt.show()
'''
def main(fname):
    f = fname
    list, com, art = read(f)
    matrix = toMatrix('data_matrix.csv', list, com, art)
    # netdraw(list, matrix)

if __name__ == '__main__':
    filename = 'cmooc_comments.csv'
    main(filename)

第一步 数据整理

数据整理其实是两个工作,一方面要将所需数据挑出来形成可以生成邻接矩阵的形式;另一方面是文件格式转化为csv格式,方便Python读取。

我们的原始数据其实非常的繁杂,需要用到的数据分布在excel文件的好几个表里,下面的图片分别是发帖情况统计和评论情况统计。


要生成邻接矩阵的话,只需要两列数据,一列是评论者,一列是被评论者,每一行代表着一条评论。在原始数据中,评论者和被评论者不在一个数据表里,但它们有一个共同的外链数据,也就是博客的ID,我亲爱的同组同学使用excel的强大功能将它们整合在了一个表中,而我并不知道这个功能怎么用(可能是vlookup吧),如下图。

我们只需要后面两列,把这两列粘到新文件中另存为csv格式即可。

第二步 生成所涉用户列表

在这个研究中,我们只研究与他人产生过社交行为的用户,因此不能使用那个包含所有用户的列表,为了方便后续代码的使用,我定义了三个list,一个是所有涉及用户列表(也就是被评论者和评论者的并集),一个是评论者数据列表,一个是被评论者数据列表

后两个都好说,直接读入就可以,至于第一个,基于list的中元素的可重复性,我的思路是,读取其中一个列表,判断其中数据是否在另一个列表中,若否,则添加到该列表中,这个列表没有重复数据,为了之后方便查看数据我们也可以把它处理成有序的。

def list(l1, l2):
    for i in range(0, len(l1)):
        if l1[i] not in l2:
            l2.append(l1[i])
    return l2

而后两个列表则是为了存储数据,所以需要有重复,且顺序不能有变,可以这样实现:

def list_with_repeat(l1, l2):
    for i in range(0, len(l1)):
        l2.append(l1[i])
    return l2

然后读入刚刚整理好的csv文件把相关数据存储在这几个list里面:

def read(fname):
    data = pd.read_csv(fname)
    # print(data.head)
    user = []
    new1 = []
    new2 = []
    comment_user = list_with_repeat(data['user_id'], new1)
    article_user = list_with_repeat(data['commented_id'], new2)
    user = list(data['user_id'], user)
    user.sort()
    # print(comment_user)
    # print(article_user)
    #print(user)
    return user, comment_user, article_user

读入csv文件需要使用panda包,记得在py文件开头写上这一行:

import pandas as pd

第三步 生成邻接矩阵并存储

邻接矩阵的表头就是我们刚刚的第一个list,包含所有参与到互动中的用户。邻接矩阵的生成其实就是一个计数的过程,我们知道这一个评论动作的发出者和接受者之后,根据他们的ID找到矩阵中对应的那个格子,值加一,这样邻接矩阵中的数据就可以体现出交互的次数

def toMatrix(fpath, list, com, art):
    header = list
    print(list)
    # print(type(com[0]))
    # print(type(list[0]))
    # print(type(list[0]))
    bool_list = []

    with open(fpath, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(list)

    matrix = [[0 for _ in range(len(list))] for _ in range(len(list))]
    # matrix = [[0]*731]*731
    for i in range(0,len(com)):
        x = com[i]
        y = art[i]
        # print(x)
        x_bool = x in list
        y_bool = y in list
        # print(y)
        # print(x_bool)
        bool_list.append(x_bool)
        if x_bool == True and y_bool == True:
            x_index = list.index(x)
            y_index = list.index(y)
            # print(x_index)
            # print(y_index)

            matrix[x_index][y_index] += 1
        # print(matrix)
        else:
            # print('not in')
            pass

    with open('comdat.csv', 'w', newline='') as ff:
        writer = csv.writer(ff)
        for j in range(0,len(list)):
            writer. writerow(matrix[j])
            # print(j)

    print(matrix)
    return matrix

因为我水平有限,不太知道怎么写入竖向的表头,所以这个矩阵 呢,就只有顶端横着的表头,不过没关系,你可以使用excel强大的功能,在表格最左侧插入一个空行,把上面的表头转置一下粘过来就好啦哈哈哈。

最后一步 别忘了main函数

main调用上面的东西,就齐活了,记得不要把传的变量搞错了。

def main(fname):
    f = fname
    list, com, art = read(f)
    matrix = toMatrix('data_matrix.csv', list, com, art)
    # netdraw(list, matrix)

if __name__ == '__main__':
    filename = 'cmooc_comments.csv'
    main(filename)

第一次用Python解决实际问题还是很开心的,代码有很多不完善的地方,请各位大佬多多指正,本人玻璃心,轻点喷。

更多推荐

菜鸟如何用Python将交互数据生成邻接矩阵(超详细)