主路径分析遍历计数算法——SPC、SPLC、SPNP

主路径分析法(MPA)是针对于引文网络提出的一种路径分析方法,该方法于1989年由Hummon和Doreian首次提出,下图是MPA的主要步骤。
简单来说,主路径分析方法包括以下两个步骤:
第一步:获取引文网络中每条链路的遍历计数值;
第二步:依据遍历技术值连接引文网络中最重要的链路,形成主路径。
通常在主路径分析之前,我们需要准备一个引文网络。

一、引文网络的基本概念:

基于文献间的直接引用关系构建引文网络,其中 节点代表文献,包括文章、专利等,节点之 由引 用关系构造。 因 为文献 早的文献,因 网络是有向 环网络。
Hummon和Doreian在 连通性:D NA 研究 的进展 》 中 义起始节点,即 用而 节点为源(sorce):定 点而未被引用的终点节点为汇(sink)。在 图1-1中,A、B、C、D为源,N、O、P、Q为汇。首节 点指链路指 的节点,尾节 向节点。父 指从 路尾 以回 的节点,子 示从链 路首 点出发,沿 接线 的节点。

图1-1 准备的引文网络图

该引文网络图的绘制python代码如下,最后两行代码是为了在之后的算法中直接调用该引文网络,把它保存成了.pkl格式的文件:

import networkx as nx
import matplotlib.pyplot as plt
import pickle

# 创建有向图
G = nx.DiGraph()

# 添加路径
path_list = [
    ['A', 'H', 'J', 'N'],
    ['A', 'H', 'J', 'L', 'O'],
    ['B', 'E', 'H', 'J', 'N'],
    ['B', 'E', 'L', 'O'],
    ['C', 'E', 'H', 'J', 'N'],
    ['C', 'E', 'L', 'O'],
    ['C', 'F', 'I', 'L', 'O'],
    ['C', 'F', 'I', 'K', 'P'],
    ['C', 'F', 'K', 'P'],
    ['C', 'F', 'K', 'M', 'Q'],
    ['C', 'G', 'M', 'Q'],
    ['D', 'G', 'M', 'Q']
]


# 构建有向图
for path in path_list:
    for i in range(len(path)-1):
        G.add_edge(path[i], path[i+1])

# 绘制网络
pos = {
    'A': (0, 5),
    'B': (0, 4),
    'C': (0, 2),
    'D': (0, 1),
    'H': (2, 5),
    'E': (1, 4),
    'F': (1, 2),
    'G': (1, 1),
    'I': (2, 3),
    'J': (3, 5),
    'L': (4, 4),
    'K': (3, 2),
    'M': (4, 1),
    'N': (5, 5),
    'O': (5, 4),
    'P': (5, 2),
    'Q': (5, 1)
}

plt.figure(figsize=(10, 6))
nx.draw_networkx(G, pos, with_labels=True, node_size=1000, node_color='lightblue', font_size=12, arrowsize=20)

plt.axis('off')
plt.show()

with open('graph_1.pkl', 'wb') as f:
    pickle.dump(G, f)

二、遍历计数

SPC遍历计数算法:

在引文网络中,构成搜索路径的链路起着至关重要的作用,是知识传递的重要组成部分,因此一系列高权重的链路就构成了一条主路径,而一条链路在引文网络中的重要性可以采用遍历计数来衡量。搜寻路径数 SPC(search pathcount)是指在网络中从源到汇的所有路径中经过此链路的次数。例如,链路C→F的SPC值是5,因为有5条路径C→F→I→L→O,C→F→I→K→P,C→F→I→K→M→Q,C→F→K→P,C→F→K→M→Q 经过链路 C→F。

具体代码: 

 1.对指定边计算其SPC值:
import networkx as nx
import pickle

# 加载保存的图对象
with open('graph_1.pkl', 'rb') as f:
    G = pickle.load(f)

def search_path_count(G, start_node, end_node, edge):
    count = 0
    for path in nx.all_simple_paths(G, source=start_node, target=end_node):
        edge_in_path = list(zip(path, path[1:]))  # 获取路径中的所有链路
        if edge in edge_in_path:
            count += 1
    return count

start_nodes = ['A', 'B', 'C', 'D']  # the nodes where the search starts
end_nodes = ['N', 'Q', 'P', 'O']  # the nodes where the search ends
#查找指定边CF
edge = ('C', 'F')

total_count = 0
for start_node in start_nodes:
    for end_node in end_nodes:
        SPC = search_path_count(G, start_node, end_node, edge)
        print(f"SPC from {start_node} to {end_node} through {edge} is {SPC}")
        total_count += SPC

print(f"The total SPC through {edge} is {total_count}")
2.遍历整个例图,计算每个边的SPC值,并可视化:
import matplotlib.pyplot as plt
import networkx as nx
import pickle

# 加载保存的图对象
with open('graph_1.pkl', 'rb') as f:
    G = pickle.load(f)

def search_path_count(G, start_node, end_node, edge):
    count = 0
    for path in nx.all_simple_paths(G, source=start_node, target=end_node):
        edge_in_path = list(zip(path, path[1:]))  # 获取路径中的所有链路
        if edge in edge_in_path:
            count += 1
    return count

# 遍历图中的所有边并计算它们的SPC值
all_edges = list(G.edges())
start_nodes = ['A', 'B', 'C', 'D']  # the nodes where the search starts
end_nodes = ['N', 'Q', 'P', 'O']  # the nodes where the search ends

# 创建绘图对象
pos = {
    'A': (0, 5),
    'B': (0, 4),
    'C': (0, 2),
    'D': (0, 1),
    'H': (2, 5),
    'E': (1, 4),
    'F': (1, 2),
    'G': (1, 1),
    'I': (2, 3),
    'J': (3, 5),
    'L': (4, 4),
    'K': (3, 2),
    'M': (4, 1),
    'N': (5, 5),
    'O': (5, 4),
    'P': (5, 2),
    'Q': (5, 1)
}

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题

# 创建绘图对象
fig, ax = plt.subplots()
nx.draw(G, pos, with_labels=True, node_size=500, node_color='skyblue', font_size=10, ax=ax)

# 绘制边并标记SPC值
for edge in all_edges:
    total_count = 0
    for start_node in start_nodes:
        for end_node in end_nodes:
            SPC = search_path_count(G, start_node, end_node, edge)
            total_count += SPC
    # 添加边的标签(SPC值)
    if total_count > 0:
        label = total_count
        nx.draw_networkx_edge_labels(G, pos, edge_labels={(edge[0], edge[1]): label}, font_color='red', ax=ax)

# 添加标题
plt.title("搜索路径数SPC(search path count)", loc='center', pad=20)
plt.show()

SPLC遍历计数算法:

搜寻路径计数SPLC(search path link count)指从一条链路的尾节点及尾节点的父节点到汇点的所有路径中经过此链路的次数。例如,链路F→I的SPLC值是6,因为有6条路径C→F→I→L→Ο,C→F→I→K→P,C→F→I→K→M→Q,F→I→L→О,F→I→K→P,F→I→>K→M→O 通过链路 F→I,因此链路F→I的 SPLC值为6。这6条路径的起点是链路F→I的尾节点F及尾节点的父节点C。

具体代码:

1.对指定边计算其SPLC值:
import networkx as nx
import pickle

def get_parents(G, node):
    """返回一个包含所有可以到达指定节点的节点的集合."""
    parents = set()
    for start_node in G:
        if node_in_path(G, start_node, node):
            parents.add(start_node)
    print(f"The parent nodes of {node} are {parents}")
    return parents

def node_in_path(G, start, end):
    """在图G中检查是否存在一条从'start'到'end'的路径."""
    visited_nodes = {start}
    nodes_to_visit = [start]

    while nodes_to_visit:
        current_node = nodes_to_visit.pop(0)
        if current_node == end:
            return True
        for neighbor in G[current_node]:
            if neighbor not in visited_nodes:
                visited_nodes.add(neighbor)
                nodes_to_visit.append(neighbor)
    return False

# 深度优先搜索路径
def dfs_paths(G, start, goal, target_edge):
    stack = [(start, [start])]
    while stack:
        (vertex, path) = stack.pop()
        for next in set(G.neighbors(vertex)) - set(path):
            if next == goal:
                new_path = path + [next]
                if target_edge in zip(new_path, new_path[1:]):
                    yield new_path
            else:
                stack.append((next, path + [next]))

# 创建图并添加节点和边
with open('graph_1.pkl', 'rb') as f:
    G = pickle.load(f)

# 尾节点及其所有父节点到汇点的所有路径
tail_node = 'L'
parent_nodes = get_parents(G, tail_node)
target_nodes = parent_nodes.union(set([tail_node]))
target_edge = ('L', 'O')
end_node = ('N','O','P','Q')


splc = 0
for start_node in target_nodes:
    for end_node_single in end_node:
        for path in dfs_paths(G, start_node, end_node_single, target_edge):
            print('Path:', path)
            splc += 1

print('Search Path Link Count (SPLC):', splc)
2.遍历整个例图,计算每个边的SPLC值,并可视化:
import networkx as nx
import pickle
import matplotlib.pyplot as plt

def get_parents(G, node):
    """返回一个包含所有可以到达指定节点的节点的集合."""
    parents = set()
    for start_node in G:
        if nx.has_path(G, start_node, node):
            parents.add(start_node)
    print(f"节点 {node} 的父节点为 {parents}")
    return parents

# 创建图并添加节点和边
with open('graph_1.pkl', 'rb') as f:
    G = pickle.load(f)

# 计算整个网络所有边的SPLC值
splc_dict = {}
end_nodes = ('N', 'O', 'P', 'Q')
for u, v in G.edges():
    target_edge = (u, v)
    splc = sum(1 for start_node in G.nodes() for end_node in end_nodes
               for path in nx.all_simple_paths(G, start_node, end_node)
               if target_edge in zip(path, path[1:]))
    splc_dict[target_edge] = splc

# 创建绘图对象
pos = {
    'A': (0, 5),
    'B': (0, 4),
    'C': (0, 2),
    'D': (0, 1),
    'H': (2, 5),
    'E': (1, 4),
    'F': (1, 2),
    'G': (1, 1),
    'I': (2, 3),
    'J': (3, 5),
    'L': (4, 4),
    'K': (3, 2),
    'M': (4, 1),
    'N': (5, 5),
    'O': (5, 4),
    'P': (5, 2),
    'Q': (5, 1)
}

plt.figure(figsize=(12, 8))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.title("搜寻路径计数SPLC(search path link count)", loc='center', pad=20)
nx.draw(G, pos, with_labels=True, node_size=1000, node_color='skyblue', font_size=10)
edge_labels = {(u, v): splc_dict[(u, v)] for u, v in G.edges()}
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_color='red')
plt.show()

SPNP遍历计数算法:

搜寻路径节点对数 SPNP(search path node pair)是指从一条链路的首节点及首节点的子节点到尾节点及尾节点的父节点的所有路径中经过此链路的次数。例如,链路E-L的SPNP值是6,因为有6条路径的起点是链路-L的尾节点E和E的父节点B、C,终点是链路E→L的首节点L和L 的子节点O。这6条路径为 B→E→L→O,B→E→L,C→E→L→O,E→L→O,E→L,C→E→L。

 具体代码:

1.对指定边计算其SPNP值:
import networkx as nx
import pickle

# 加载保存的图对象
with open('graph_1.pkl', 'rb') as f:
    G = pickle.load(f)

def dfs_nodepair_paths(G, start_nodes, goal_nodes, target_edge):
    spnp_paths = []
    for start in start_nodes:
        stack = [(start, [start])]
        while stack:
            (vertex, path) = stack.pop()
            for next_node in set(G.neighbors(vertex)) - set(path):
                next_path = path + [next_node]
                if next_node in goal_nodes:
                    if target_edge in zip(next_path, next_path[1:]):
                        spnp_paths.append(next_path)
                    else:
                        spnp_paths.append(next_path)
                stack.append((next_node, next_path))
    return spnp_paths

# 获取节点及其所有子节点
def get_all_descendants(G, node):
    descendants = set()
    stack = [node]
    while stack:
        current = stack.pop()
        for successor in G.successors(current):
            if successor not in descendants:
                descendants.add(successor)
                stack.append(successor)
    return descendants

# 获取节点及其所有父节点
def get_all_ancestors(G, node):
    ancestors = set()
    stack = [node]
    while stack:
        current = stack.pop()
        for predecessor in G.predecessors(current):
            if predecessor not in ancestors:
                ancestors.add(predecessor)
                stack.append(predecessor)
    return ancestors

# 计算链路 E→L 的 SPNP 路径
head_node = 'I'
tail_node = 'F'
head_descendants = get_all_descendants(G, head_node)
tail_ancestors = get_all_ancestors(G, tail_node)

# 包括自己
head_descendants.add(head_node)
tail_ancestors.add(tail_node)

target_edge = ('F', 'I')
spnp_paths = dfs_nodepair_paths(G, tail_ancestors, head_descendants, target_edge)

# 过滤掉不包含目标边的路径
spnp_paths = [path for path in spnp_paths if target_edge in zip(path, path[1:])]

# 打印结果
print('SPNP paths for edge {}:'.format(target_edge))
for path in spnp_paths:
    print(' -> '.join(path))

print('SPNP value for edge {}: {}'.format(target_edge, len(spnp_paths)))
2.遍历整个例图,计算每个边的SPNP值,并可视化:
import networkx as nx
import pickle
import matplotlib.pyplot as plt

# 加载保存的图对象
with open('graph_1.pkl', 'rb') as f:
    G = pickle.load(f)

# 深度优先搜索函数,查找所有路径
def dfs_nodepair_paths(G, start_nodes, goal_nodes, target_edge):
    spnp_paths = []
    for start in start_nodes:
        stack = [(start, [start])]
        while stack:
            (vertex, path) = stack.pop()
            for next_node in set(G.neighbors(vertex)) - set(path):
                next_path = path + [next_node]
                if next_node in goal_nodes:
                    spnp_paths.append(next_path)
                stack.append((next_node, next_path))
    return spnp_paths

# 获取节点及其所有子节点
def get_all_descendants(G, node):
    descendants = set()
    stack = [node]
    while stack:
        current = stack.pop()
        for successor in G.successors(current):
            if successor not in descendants:
                descendants.add(successor)
                stack.append(successor)
    return descendants

# 获取节点及其所有父节点
def get_all_ancestors(G, node):
    ancestors = set()
    stack = [node]
    while stack:
        current = stack.pop()
        for predecessor in G.predecessors(current):
            if predecessor not in ancestors:
                ancestors.add(predecessor)
                stack.append(predecessor)
    return ancestors

# 计算图中所有边的 SPNP 值
def calculate_all_spnp_values(G):
    spnp_values = {}
    for edge in G.edges():
        tail_node, head_node = edge
        head_descendants = get_all_descendants(G, head_node)
        tail_ancestors = get_all_ancestors(G, tail_node)

        # 包括自己
        head_descendants.add(head_node)
        tail_ancestors.add(tail_node)

        # 计算所有路径
        spnp_paths = dfs_nodepair_paths(G, tail_ancestors, head_descendants, edge)

        # 过滤包含目标边的路径
        spnp_paths = [path for path in spnp_paths if edge in zip(path, path[1:])]

        # 存储SPNP值
        spnp_values[edge] = len(spnp_paths)

    return spnp_values

# 获取所有边的SPNP值
all_spnp_values = calculate_all_spnp_values(G)

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 可视化图及SPNP值
def draw_graph_with_spnp(G, spnp_values):
    pos = {
        'A': (0, 5),
        'B': (0, 4),
        'C': (0, 2),
        'D': (0, 1),
        'H': (2, 5),
        'E': (1, 4),
        'F': (1, 2),
        'G': (1, 1),
        'I': (2, 3),
        'J': (3, 5),
        'L': (4, 4),
        'K': (3, 2),
        'M': (4, 1),
        'N': (5, 5),
        'O': (5, 4),
        'P': (5, 2),
        'Q': (5, 1)
    }

    plt.title("搜寻路径节点对数SPNP(search path node pair)", loc='center', pad=20)
    # 绘制节点和边
    nx.draw(G, pos, with_labels=True, node_color='lightblue', edge_color='gray', node_size=500, font_size=10)
    # 为每条边添加SPNP值
    edge_labels = {edge: spnp_values[edge] for edge in G.edges()}
    nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_color='red')
    # 显示图
    plt.show()

# 绘制包含SPNP值的图
draw_graph_with_spnp(G, all_spnp_values)

本篇文章主要针对代码实现部分进行分享,其余理论部分来自这篇博士论文:

[1]万小萍.基于引文网络分析的知识主路径研究[D].华中师范大学,2020.DOI:10.27159/d.cnki.ghzsu.2020.004048.

论文中关于SPLC和SPNP算法给的例图有个别边计算错误,本文已经纠正。

首图来自论文:

Chen, Liang, et al. "A semantic main path analysis method to identify multiple developmental trajectories." Journal of Informetrics 16.2 (2022): 101281.

下一篇分享关于基于SPC、SPLC、SPNP遍历计数算法的局域搜索主路径和全局搜索主路径相关代码。

  • 28
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Pajek是一款图论软件,可以用于社会网络分析、复杂网络分析等多个领域。在专利引证路径分析中,我们可以使用Pajek来构建专利引证网络,并通过Pajek的算法计算路径。 以下是使用Pajek进行专利引证路径分析的步骤: 1. 准备数据 首先,我们需要准备好专利引证数据。这些数据通常包括专利号、引证专利号、引证年份等信息。可以使用Excel等工具进行整理和清洗。 2. 构建专利引证网络 使用Pajek打开数据文件,将数据转化为网络格式。在Pajek中,可以使用“Network”菜单中的“New Network”命令来创建新的网络。然后,我们可以使用“Vertices”和“Arcs”菜单中的命令来添加节点和边,并设置节点和边的属性。 在专利引证网络中,节点表示专利,边表示引证关系。我们可以使用不同的颜色、形状和大小来表示不同类型的节点和边。 3. 计算路径 在Pajek中,我们可以使用“Network”菜单中的“Path Analysis”命令来计算路径。在弹出的对话框中,选择“Main Path”选项,然后点击“OK”按钮即可。 Pajek会计算出所有节点之间的最短路径,并将其中最长的路径作为路径。我们可以使用“Main Path”菜单中的命令来查看和编辑路径。 4. 可视化路径 最后,我们可以使用Pajek的可视化功能来展示专利引证网络和路径。在Pajek中,可以使用“Visualization”菜单中的命令来选择不同的布局算法,并设置节点和边的颜色、形状和大小。 通过可视化,我们可以更清晰地看到路径的结构和特征,从而深入理解专利引证网络的演化过程和机制。 ### 回答2: Pajek是一种常用的网络分析软件,可以用于进行专利引证路径分析。以下是使用Pajek进行专利引证路径分析的步骤: 1. 数据准备:首先,需要将专利引证数据整理成适合Pajek导入的格式,一般为邻接矩阵或关系列表。邻接矩阵表示哪些专利被其他专利引证,关系列表则记录每个引证对。 2. 导入数据:打开Pajek软件后,选择“File”菜单中的“Import”选项,然后选择适当的数据导入格式。根据数据格式选择相应的选项,将数据导入到Pajek中。 3. 构建网络:根据导入的数据,使用Pajek的网络构建工具来构建专利引证网络。可以使用“Network”菜单中的“Create Network”选项来定义节点和边的属性,并根据数据创建网络。 4. 进行路径分析:选择“Analysis”菜单中的“Paths”选项,可以进行路径分析。在弹出的窗口中,选择合适的节点和边的属性,以及路径的限制条件和最大长度。 5. 可视化分析结果:在得到路径分析的结果后,可以使用Pajek提供的网络可视化功能将分析结果可视化展示。选择“Network”菜单中的“Draw Network”选项,可以根据需要设置节点和边的样式、颜色等。 6. 结果解读和分析:分析完成后,可以根据网络路径分析结果来解读专利引证的路径分析结果。考察网络中的核心节点、路径之间的关系等,并分析这些信息对于理解专利引证网络的结构和演化过程的意义。 需要注意的是,上述步骤只是一种使用Pajek进行专利引证路径分析的基本流程,具体的操作可能因数据的特点和研究目的而有所差异。在使用Pajek进行分析时,应该根据实际情况进行相应的调整和优化。 ### 回答3: Pajek是一种用于复杂网络分析的软件,可以用于研究社交网络、科学合作网络、文献引证网络等。在进行专利引证路径分析时,可以按照以下步骤操作: 1. 数据准备:从数据库或文献数据库中收集所需的专利数据,包括专利号、申请日期、发表日期等信息。同时,还需要导出专利之间的引证关系数据,即每个专利引用了哪些其他专利。 2. 导入数据:打开Pajek软件并新建一个空白项目,选择"Network"-"Network from Pajek files"将专利之间的引证关系数据导入。 3. 构建网络:在导入的数据中,每个专利都是一个节点,而引证关系则是节点之间的边。根据需要,可以添加一些附加信息,比如将节点的大小与专利被引用的次数关联起来,或将节点的颜色与专利的申请日期关联起来等。 4. 可视化网络:将构建好的网络进行可视化,可以通过选择合适的布局算法将节点和边进行排列,以便更好地观察专利引证的结构和路径。 5. 分析网络:通过Pajek提供的分析工具,可以计算网络的各种属性,如节点的度中心性、介数中心性等,以及网络的整体特征,如网络的平均路径长度、聚集系数等。这些属性可用于描述和比较不同的专利引证网络。 6. 发现路径路径是指在网络中连接最多节点的路径,代表了专利之间的核心引证关系。通过Pajek中的搜索算法,可以找到网络中最重要的路径,以便进一步研究这些核心引证关系对专利系统的影响。 总结:以上是使用Pajek进行专利引证路径分析的基本步骤。通过Pajek软件提供的网络可视化和分析功能,研究者可以更好地了解和分析专利之间的引证关系,揭示专利系统中的核心技术和关键创新路径

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WYWKADW

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值