今天给大家分享如何使用 Python 测算上市公司技术专业化与技术多样化程度。该方法参考自王慧扬等《知识搜索与科技领军企业关键核心技术突破》,通过变异系数和Shannon 熵指数来分别衡量企业的技术专业化与多样化水平。
附件中提供了该参考文献的 PDF 文件,感兴趣的小伙伴可以阅读原文。
指标来源与计算原理
技术专业化(TSP)

技术多样化(TDI)

计算步骤概述
整个计算过程分为以下几个步骤:
- 数据读取:读取 2020 年上市公司与专利数据匹配结果
- 专利去重:清洗公开公告号并按股票代码+年份+公告号/申请号去重
- IPC 分类提取:提取 IPC 大类(前 3 位)和小类(前 4 位),移除 IPC 为空的记录
- 计算 TSP:基于 IPC 小类专利占比的变异系数
- 计算 TDI:基于 IPC 大类专利占比的 Shannon 熵指数
- 结果保存:输出 CSV 文件
使用 reticulate 创建与管理 Python 虚拟环境
在 R 中通过 reticulate 包来调用 Python,最好的实践是为项目创建一个专属的 Python 虚拟环境,将所需依赖隔离到独立空间,避免与系统 Python(如 Anaconda)发生版本冲突。
重要说明(避免”已初始化”报错):reticulate 在 R 会话中只能绑定一次 Python——一旦某个 {python} 代码块运行,Python 解释器就被锁定,之后再调用 use_virtualenv() 会报错:
ERROR: The requested version of Python cannot be used, as another version has already been initialized.
因此,虚拟环境的激活必须在所有 {python} 代码块之前完成。本文档的解决方案是在 setup chunk 中通过 Sys.setenv(RETICULATE_PYTHON = ...) 提前锁定 Python 路径,这是 reticulate 选取 Python 的最高优先级入口。
安装 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")) }
|
在虚拟环境中安装 Python 包(仅首次)
py_pkgs <- c("numpy", "pandas") 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 包已就绪,无需安装") }
|
验证激活状态
虚拟环境管理常用命令
# 查看所有已创建的虚拟环境 virtualenv_list()
|
详细计算代码
数据读取与预处理
import pandas as pd import numpy as np
df_2020 = pd.read_csv("2020年上市公司与专利数据匹配结果.csv", dtype=str) print(f"原始数据: {len(df_2020)} 行")
|
专利去重
按照以下步骤进行专利去重(与 R 代码逻辑完全一致):
- 清洗公开公告号(去掉末尾字母)
- 按股票代码 + 年份 + 公开公告号去重
- 按股票代码 + 年份 + 申请号去重
# Step 1: 清洗公开公告号(去掉末尾字母) # R: str_remove(公开公告号, "[A-Z]$") df_2020["公开公告号_clean"] = df_2020["公开公告号"].str.replace(r"[A-Z]$", "", regex=True)
# Step 2: 按 股票代码 + 年份 + 公开公告号_clean 去重 # R: distinct(股票代码, 年份, 公开公告号_clean, .keep_all = TRUE) df_2020 = df_2020.drop_duplicates(subset=["股票代码", "年份", "公开公告号_clean"], keep="first") print(f"按公告号去重后: {len(df_2020)} 行")
# Step 3: 按 股票代码 + 年份 + 申请号 去重 # R: distinct(股票代码, 年份, 申请号, .keep_all = TRUE) df_2020 = df_2020.drop_duplicates(subset=["股票代码", "年份", "申请号"], keep="first") print(f"按申请号去重后: {len(df_2020)} 行")
|
关键函数对照:
| R 函数 |
Python 函数 |
说明 |
str_remove(x, "[A-Z]$") |
str.replace(r"[A-Z]$", "", regex=True) |
正则替换 |
distinct(..., .keep_all=TRUE) |
drop_duplicates(subset=..., keep="first") |
去重保留首行 |
提取 IPC 分类信息
# IPC分类层级说明: # 部(Section): A-H(8个大部) # 大类(Class): 如 G06, H04(前3位,含部字母+2位数字) # 小类(Subclass): 如 G06F, H04L(前4位,含部字母+3位数字+可能字母) # # 文献定义: # 技术专业化 → 使用IPC小类(前4位,如G06F) # 技术多样化 → 使用IPC大类(前3位,如G06)
# 检查 IPC主分类 的空值 na_count = df_2020["IPC主分类"].isna().sum() print(f"IPC主分类的NA值数量: {na_count} (占比{na_count/len(df_2020)*100:.2f}%)")
# 提取 IPC 分类层级 # R: str_sub(IPC主分类, 1, 3) / str_sub(IPC主分类, 1, 4) df_2020["IPC大类"] = df_2020["IPC主分类"].str[:3] df_2020["IPC小类"] = df_2020["IPC主分类"].str[:4]
# 移除 IPC 分类为 NA 的观测值 # R: filter(!is.na(IPC大类) & !is.na(IPC小类)) df_2020 = df_2020.dropna(subset=["IPC大类", "IPC小类"]) print(f"移除IPC为NA后的数据维度: {len(df_2020)} 行")
|
计算技术专业化(TSP)
# 技术专业化:变异系数(Coefficient of Variation) # TSP = 标准差(各技术小类专利占比) / 均值(各技术小类专利占比) # TSP越大 → 技术越集中于少数小类 → 专业化程度越高
# 此处代码需下载讲义材料查看~
print(f"技术专业化(TSP)计算完成,共 {len(TSP)} 家企业") print(f"TSP描述性统计:") print(TSP["TSP"].describe())
|
关键函数对照:
| R 函数 |
Python 函数 |
说明 |
group_by() %>% summarise(n()) |
groupby().agg(size) |
分组计数 |
sd(x) |
x.std() |
样本标准差(ddof=1) |
case_when() |
np.where() |
条件分支 |
计算技术多样化(TDI)
# 技术多样化:Shannon熵指数 # TDI = -Σ p_it_a * ln(p_it_a) # TDI越大 → 技术分布越分散 → 多样化程度越高
# 此处代码需下载讲义材料查看~
print(f"技术多样化(TDI)计算完成,共 {len(TDI)} 家企业") print(f"TDI描述性统计:") print(TDI["TDI"].describe())
|
合并结果并保存
result = ( TSP[["股票代码", "技术小类数量", "TSP"]] .merge(TDI[["股票代码", "技术大类数量", "TDI"]], on="股票代码", how="inner") .merge(firm_total_patents, on="股票代码", how="inner") .sort_values("股票代码") .reset_index(drop=True) )
print(f"最终结果: {len(result)} 行, {len(result.columns)} 列")
print("\n--- 描述性统计 ---") print(result[["TSP", "TDI", "总专利数"]].describe())
result.to_csv("技术专业化与多样化_2020年_python.csv", index=False) print("\n结果已保存到: 技术专业化与多样化_2020年_python.csv")
|
结果概览
print("=== 结果预览(前20行) ===") print(result.head(20).to_string(index=False))
|
print("=== 详细描述性统计 ===") for col in ["TSP", "TDI", "总专利数"]: s = result[col] print(f"\n{col}:") print(f" 最小值: {s.min():.4f}") print(f" 25%: {s.quantile(0.25):.4f}") print(f" 中位数: {s.median():.4f}") print(f" 均值: {s.mean():.4f}") print(f" 75%: {s.quantile(0.75):.4f}") print(f" 最大值: {s.max():.4f}")
|
#> #> TSP: #> 最小值: 0.0000 #> 25%: 0.3764 #> 中位数: 0.7071 #> 均值: 0.8015 #> 75%: 1.1326 #> 最大值: 5.6952 #> #> TDI: #> 最小值: -0.0000 #> 25%: 0.6365 #> 中位数: 1.1339 #> 均值: 1.1227 #> 75%: 1.6094 #> 最大值: 3.3103 #> #> 总专利数: #> 最小值: 1.0000 #> 25%: 6.0000 #> 中位数: 13.0000 #> 均值: 47.0864 #> 75%: 31.0000 #> 最大值: 11741.0000
|
点击这里跳转到 RStata 短书平台获取附件:名师讲堂|使用 Python 测算上市公司技术专业化与技术多样化
评论