「Python数据分析」 社交网络:共现/合作网络(无向有权图) 生成邻接矩阵、共现矩阵

这里的共现矩阵矩阵就是对角线上是节点权重的邻接矩阵,我为了区分他们换个名字而已。
不过用矩阵存储网络空间利用率还是太低了,所以一般我还是把节点权重和节点存在一起,边的权重和边存在一起,再加上一个邻接表,就不生成邻接矩阵了,这篇文章只是对之前代码迭代过程的一个记录。不过如果以后遇到对数据格式有特殊要求的场景,我就得再去学学稀疏矩阵了…

以下是原文:

使用从数据库中导出的论文、专利数据,做作者/专利权人合作网络,实际上也就是共现网络。

存储网络的形式有很多种:邻接矩阵(matrix)、共现矩阵、节点列表(node list)、带权重的边列表(weighted edges)、边列表(edge list)、邻接表(adjacency list),主要还是根据自己后续的数据处理需求来选择存储结构。

其中节点列表、边列表可以作为G.add_nodes_from()、G.add_edges_from()的输入,带权重的边列表可以作为networkx中G.add_weighted_edges_from()方法的输入。节点列表、合作矩阵(邻接矩阵)、边列表、邻接表还可以作为各种网络绘制软件的输入数据,比如Ucinet、Gephi。

本文记录邻接矩阵、共现矩阵生成方式,其他方式可参考:
生成节点、边列表生成边-权重列表生成邻接表

使用的数据形式示例:

数据
其中F列是作者信息,其他列包含其他信息。

合作网络构建

生成合作网络代码主函数:

if __name__ =='__main__' :

    co_list = [ ["AA | BB | CC | DD",2019],
                ["EE | BB | FF ",2018],
                ["AA | GG | FF | HH | KK",2019],
                ["CC | DD | FF | LL | AA",2020],
                ["AA | BB | FF ",2017],
                ["EE | BB | GG ",2018],
                ["DD | GG | LL | HH | EE",2019],
                ["AA | GG | CC | DD",2018]]

    # 1.获取节点列表
    author_list = get_nodes(co_list,0) 
    # 2.合作矩阵(类似于邻接矩阵)
    get_cooperate_matrix(author_list,0)
1. 提取出节点列表。

调用了自定义的函数get_nodes()。调用这两个函数之前要把原始数据提取到形如co_list的列表里

函数实现如下:

获取节点列表:get_nodes():

获取所有出现的节点列表。

def get_nodes(co_list,col):
	'''
        rows: 形如co_list的所有用来构建合作网络的数据行
        col: 作者信息所在列数-1
    '''
    nodes_list = []
    for authors in co_list:
        auths = authors[col].split(" | ") # 分隔符可换
        for auth in auths:
            if auth not in nodes_list: # 去重
                nodes_list.append(auth)
    return nodes_list

结果:

["AA","BB","CC","DD","EE","FF","GG","HH","KK","LL"]
2. 生成共现矩阵(对角线上是节点权重)

调用自定义的函数get_cooperate_matrix(),实现方法如下。

合作矩阵:1. 直接通过节点列表+原始数据构建

最开始实现的时候用了很多字典结构存储每个作者的合作关系,运行的时候发现内存开销异常的大(电脑内存不够的卑微),因此最后全部改回列表形式。其实这里没有涉及到大量数据搜索,所以使用字典的意义也不大,不能节省时间,反而增加内存占用。

def get_cooperate_matrix1(rows,nodes_list,col):
    '''
        rows: 形如co_list的所有用来构建合作网络的数据行
        nodes_list: 节点列表
        col: 节点共现信息所在列数-1
    '''

    length = len(nodes_list)
    cooperate_list = []
    # 遍历作者名,计数和各作者合作数(每次合作对自己也计数)
    for node in nodes_list:
        node_co = []
        node_co.append(node)
    # 合作列表:初始化为长度为节点个数的全零列表[name,0,0,0,...,0,0]
        for i in range(length):
            node_co.append(0) 
    # 遍历所有数据行,对作者字段进行匹配
        for row in rows:
            nodes = row[col].split(" | ") # 分隔符按数据结构选
    # 对包含当前节点的数据项,提取共现关系(合作列表对应位置+1)
            if node in nodes:
                for each_node in nodes:
                # 索引共现的节点编号,确定在合作列表中的位置
                    node_index = nodes_list.index(each_node)+1 
                # 对应位置+1
                    node_co[node_index] = node_co[node_index] + 1 
    # 添加到合作矩阵列表中
        cooperate_list.append(node_co)

    # 1. 生成合作矩阵:cooperate_mat
    cooperate_mat = []
    first_line = ['']
    first_line.extend(nodes_list)
    cooperate_mat.append(first_line) # 第一行,第一列为标题(出现的作者名)
    cooperate_mat.extend(cooperate_list)

    return cooperate_mat

写入操作这里就省略了,可以参照 csv文件写入

共现矩阵:2. 通过节点列表+边列表构建

生成节点列表、边列表方法:get_nodes_edges()

def get_cooperate_matrix2(nodes_list,edge_list):
    '''
        nodes_list:节点列表
        edge_list: 边列表
    '''
    length = len(nodes_list)
    cooperate_list = []

    for node in nodes_list:
        node_co = []
        node_co.append(node)
    # 合作列表:初始化为长度为节点个数的全零列表[node,0,0,0,...,0,0]
        for i in range(length):
            node_co.append(0) 
    # 遍历所有边,对节点进行匹配
        for edge in edge_list: 
    # 对包含当前节点的边,提取共现关系(合作列表对应位置+1)。对角线上为当前节点总次数。
            if node in edge:
                for each_node in edge:
                # 索引节点编号,确定在合作列表中的位置
                    node_index = nodes_list.index(each_node)+1 
                # 对应位置+1
                    node_co[node_index] = node_co[node_index] + 1 
        cooperate_list.append(node_co)

    # 合并各节点数据,生成合作矩阵。
    cooperate_mat = []
    first_line = ['']
    first_line.extend(nodes_list)
    cooperate_mat.append(first_line)
    cooperate_mat.extend(cooperate_list)

    return cooperate_mat

结果

合作矩阵(类似邻接矩阵):

对角线上是对应节点的总共出现次数,其他位置为共现次数(权重)。
在这里插入图片描述

3.生成邻接矩阵(对角线上为0)

生成“边-权重”列表方法: 生成边-权重列表

def get_adjacency_matrix(node_list,weighted_links):
    '''
        nodes_list:节点列表(sorted)
        edge_list: 边-权重列表
    '''
     # 初始化adjacency_mat为全零矩阵
    adjacency_mat = [[0 for val in range(len(node_list))] for val in range(len(node_list))]

    for x, y, val in weighted_links:
        i = node_list.index(x)
        j = node_list.index(y)
        adjacency_mat[i][j] = adjacency_mat[j][i] =  val
    return adjacency_mat

结果

除了对角线全为0,其它和共现矩阵一样。

合作/共现网络示例:

节点大小、边的粗细表示其权重。
图

  • 22
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
首先,我们需要了解无向有权邻接矩阵是什么。邻接矩阵是用一个二维数组来表示的方法,其中数组中的每个元素表示该位置上的两个顶点是否有边相连,如果相连则为边权,否则为无穷大。 假设我们有一个这样的无向有权,其中有5个节点和7条边: ``` 2 1------2 |\ /| | \ / | 4| \/ |3 | /\ | | / \ | |/ \| 4------5 5 ``` 我们可以用邻接矩阵来表示这个,其中数组a[i][j]表示从节点i到节点j的边权,如果没有边相连则为无穷大: ``` 1 2 3 4 5 1 0 2 inf 4 inf 2 2 0 3 5 1 3 inf 3 0 inf inf 4 4 5 inf 0 1 5 inf 1 inf 1 0 ``` 接下来,我们可以用普里姆算法来求最小生成树。普里姆算法是一种贪心算法,它从一个任意的节点开始,不断寻找与该节点直接相连的最小权值边所连接的节点,并将其加入生成树中,直到所有节点都加入为止。 我们在这里选择节点1作为起点,然后不断寻找与它相连的最小权值边所连接的节点。具体步骤如下: 1. 将节点1加入生成树中,并将其标记为已访问。 2. 找到与节点1相连的所有边,并选择其中权值最小的边(即与节点2相连的边),将节点2加入生成树中,并将其标记为已访问。 3. 找到与生成树中已有节点相连的所有边,并选择其中权值最小的边(即与节点5相连的边),将节点5加入生成树中,并将其标记为已访问。 4. 找到与生成树中已有节点相连的所有边,并选择其中权值最小的边(即与节点4相连的边),将节点4加入生成树中,并将其标记为已访问。 5. 找到与生成树中已有节点相连的所有边,并选择其中权值最小的边(即与节点2相连的边),但是节点2已经被标记为已访问,因此我们跳过这条边。 6. 找到与生成树中已有节点相连的所有边,并选择其中权值最小的边(即与节点5相连的边),但是节点5已经被标记为已访问,因此我们跳过这条边。 7. 所有节点都已经被加入生成树中,算法结束。 最终得到的最小生成树是: ``` 2 1------2 | 4------5 ``` 其中所有边的权值之和为2+1+1=4。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值