名师讲堂|使用 Python 测算各城市技术集群指标

本讲义介绍如何使用 Python 测算各城市的技术集群指标(技术关联性 link_c 和技术多样性 diver_c),该方法参考自冉征等(2025)《技术集群结构与颠覆式创新》一文。

附件中提供了该参考文献的 PDF 文件,感兴趣的小伙伴可以阅读原文。


一、指标来源与计算原理

1.1 显性技术比较优势(RTCA)

1.2 技术多样性(diver_c)

1.3 技术关联性(link_c)

1.4 计算步骤概述

整个计算过程分为以下几个步骤:

  1. 数据读取与去重:读取专利数据,按公告号和申请号两步去重
  2. IPC 小类展开:将每条专利的多个 IPC 分类号展开,取前 4 位作为技术领域标识
  3. RTCA 计算:逐年计算每个城市每个技术领域的 RTCA 值
  4. diver_c 计算:统计每个城市具有 RTCA ≥ 1 的技术领域数量
  5. link_c 计算:基于技术联系矩阵 Φ 计算技术关联性
  6. 结果保存:输出 CSV 和 Stata 格式文件

二、使用 reticulate 创建与管理 Python 虚拟环境

在 R 中通过 reticulate 包来调用 Python,最好的实践是为项目创建一个专属的 Python 虚拟环境,将所需依赖隔离到独立空间,避免与系统 Python(如 Anaconda)发生版本冲突。

重要说明(避免”已初始化”报错):reticulate 在 R 会话中只能绑定一次 Python——一旦某个 {python} 代码块运行,Python 解释器就被锁定,之后再调用 use_virtualenv() 会报错。因此,虚拟环境的激活必须在所有 {python} 代码块之前完成。本文档的解决方案是在 setup chunk 中通过 Sys.setenv(RETICULATE_PYTHON = ...) 提前锁定 Python 路径。

2.1 安装 reticulate(仅首次)

# 设置 CRAN 镜像
options(repos = c(CRAN = "https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))

# 仅在尚未安装时才安装
if (!requireNamespace("reticulate", quietly = TRUE)) {
install.packages("reticulate")
message("reticulate 安装完成!")
} else {
message("reticulate 已安装,版本:", packageVersion("reticulate"))
}

2.2 虚拟环境初始化(已在 setup chunk 中完成)

本文档的 setup chunk(隐藏运行)包含如下逻辑:

library(reticulate)

.venv_name <- ".venv"
.venv_python <- virtualenv_python(.venv_name)

# 虚拟环境不存在时自动创建
if (!file.exists(.venv_python)) {
virtualenv_create(.venv_name)
.venv_python <- virtualenv_python(.venv_name)
}

# 通过环境变量抢先锁定 Python(优先级最高)
Sys.setenv(RETICULATE_PYTHON = .venv_python)
use_virtualenv(.venv_name, required = TRUE)

这样做的关键在于:knitr 在处理第一个 {python} chunk 时,reticulate 已经通过 RETICULATE_PYTHON 环境变量知道要使用 .venv,不会再去碰 Anaconda。

2.3 在虚拟环境中安装 Python 包(仅首次)

# 检查关键包是否已安装,缺失的才安装
py_pkgs <- c(
"numpy", "pandas", "pyreadr", "matplotlib"
)

installed <- py_list_packages(".venv")$package
need_install <- setdiff(py_pkgs, installed)

if (length(need_install) > 0) {
virtualenv_install(".venv", packages = need_install)
message("已安装缺失的包:", paste(need_install, collapse = ", "))
} else {
message("所有 Python 包已就绪,无需安装")
}

2.4 验证激活状态

# 验证当前绑定的 Python 路径(应指向 .venv 目录)
py_config()

三、详细计算代码(Python 版本)

以下代码对应 计算技术关联性与多样性.py 脚本,以 2010–2012 年为例演示完整计算过程。

3.1 路径与参数设置

import pandas as pd
import numpy as np
import os
from pathlib import Path

# 设置工作目录(请根据实际情况修改)
# os.chdir("/Users/ac/Desktop/使用 Python 测算各城市技术集群指标/")

# 路径与参数
DATA_DIR = "newIP专利数据分年_csv"
RDS_PATH = "phi_matrix.rds"
OUT_DIR = "output"
YEARS = list(range(2010, 2013)) # 2010-2012 年

os.makedirs(OUT_DIR, exist_ok=True)

# IPC 小类提取正则
IPC_SUBCLASS_PATTERN = r"^[A-Z][0-9]{2}[A-Z]"

print("路径与参数设置完成")
print(f"目标年份:{YEARS}")

代码说明:

  • DATA_DIR:专利 CSV 数据所在文件夹
  • RDS_PATH:技术联系矩阵文件(来自 R 语言版本,无需重新计算)
  • OUT_DIR:输出文件夹
  • YEARS:目标计算年份

3.2 工具函数定义

import re

def extract_ipc4(ipc_str):
"""提取 IPC 小类(前4位)"""
if pd.isna(ipc_str):
return None
match = re.search(IPC_SUBCLASS_PATTERN, str(ipc_str).strip())
return match.group(0) if match else None

def split_ipc(ipc_str):
"""拆分多 IPC 字符串 → 返回列表"""
if pd.isna(ipc_str):
return []
parts = str(ipc_str).replace(",", ";").split(";")
return [p.strip() for p in parts if p.strip()]

print("工具函数定义完成")

函数说明:

  • extract_ipc4():使用正则表达式提取 IPC 小类前 4 位(如 F42B、G06Q)
  • split_ipc():将包含多个 IPC 分类号的字符串按分号/逗号分隔

3.3 Step 1:读取并去重专利数据

def read_and_dedup(yr):
"""读取某一年份的专利数据并去重"""
path = os.path.join(DATA_DIR, f"{yr}.csv")
print(f" 读取 {yr} 年...", end="")

# 只读取需要的列
cols = ["newipzlid", "年份", "公开公告号", "申请号", "IPC",
"市代码", "市", "省代码", "省"]
dt = pd.read_csv(path, encoding="utf-8", dtype=str, usecols=cols)
print(f" {len(dt)} 行")

# 清洗公开公告号(去末尾字母)
dt["公开公告号_clean"] = dt["公开公告号"].str.replace(r"[A-Za-z]+$", "", regex=True)

# Step1: 按 市代码 + 年份 + 公开公告号_clean 去重
dt = dt.drop_duplicates(subset=["市代码", "年份", "公开公告号_clean"])

# Step2: 按 市代码 + 年份 + 申请号 去重
dt = dt.drop_duplicates(subset=["市代码", "年份", "申请号"])

print(f" 去重后:{len(dt)} 行")
return dt

# 读取目标年份数据
patent_list = [read_and_dedup(yr) for yr in YEARS]
patent_dt = pd.concat(patent_list, ignore_index=True)
print(f"合并后总行数:{len(patent_dt)}")

去重规则说明:

  1. 先清洗公开公告号末尾的字母(如 CN12345A → CN12345)
  2. 按「市代码 + 年份 + 公开公告号_clean」去重
  3. 再按「市代码 + 年份 + 申请号」去重

3.4 展开 IPC 小类

此处代码需下载讲义材料查看~

说明:每条专利可能有多个 IPC 分类号(分号/逗号分隔),需要展开后取前 4 位作为 IPC 小类标识,然后再进行统计。


四、技术联系矩阵与指标计算

4.1 读取技术联系矩阵 Φ

此处代码需下载讲义材料查看~

重要说明:phi_matrix.rds 由 R 语言版本的课程提供,使用 1985–2022 年全样本专利引用关系构建,以保证外生性。Python 版本通过 pyreadr 包直接读取,无需重新计算。

4.2 逐年计算 RTCA、diver_c、link_c

print("\n" + "="*40)
print("Step 3: 逐年计算技术多样性和技术关联性")
print("="*40)

results_list = []

# 此处代码需下载讲义材料查看~

关键步骤说明:

  1. RTCA 计算:(n / n_city) / (n_nat / n_total),≥1 则 x_ci = 1
  2. diver_c 计算:对每个城市,统计 x_ci 之和
  3. link_c 计算:

4.3 汇总输出

print("\n" + "="*40)
print("Step 4: 汇总输出")
print("="*40)

final = pd.concat(results_list, ignore_index=True)
final = final[["年份", "省代码", "省", "市代码", "市", "diver_c", "link_c"]]
final = final.sort_values(["年份", "市代码"]).reset_index(drop=True)

# 保存为 CSV
out_csv = os.path.join(OUT_DIR, "city_tech_cluster_2010_2012.csv")
final.to_csv(out_csv, index=False, encoding="utf-8-sig")
print(f"结果已保存至:{out_csv}")

print("\n前10行:")
print(final.head(10))

print("\n各年描述统计:")
stats = final.groupby("年份").agg(
n_city = ("市代码", "count"),
diver_mean = ("diver_c", "mean"),
diver_sd = ("diver_c", "std"),
link_mean = ("link_c", "mean"),
link_sd = ("link_c", "std")
).round(4)
print(stats)

点击这里跳转到 RStata 短书平台获取附件:名师讲堂|使用 Python 测算各城市技术集群指标

评论