跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python算法

Python 复现 FactSet Revere 供应链断裂与重构变量测度方法

基于丁浩员等(2024)《经济研究》论文,利用 Python 处理 FactSet Revere 全球供应链数据库,实现跨国供应链断裂与重构变量测度。流程包含原始数据清洗、沪深 A 股供应商筛选、关系标记调整、月度数据展开及断裂恢复转移指标计算。代码提供 Pandas 处理逻辑,解决时间序列衔接问题,支持不同恢复标记策略。

GopherDev发布于 2026/3/24更新于 2026/7/2739 浏览
Python 复现 FactSet Revere 供应链断裂与重构变量测度方法

1 对 FactSet 全球供应链数据库的简单解读

数据库可通过 WRDS 官网获取,包含 company.dta、relations.dta 两个数据文件及变量说明文档。

重要变量解读

company.dta

  • start_和 end_: 公司信息的时间段数据。end_若为 01jan4000 默认视为至今。
  • id: 企业在该套数据库中的唯一标识符,用于与 relations.dta 匹配。
  • ticker: 上市企业代码。中国沪深 A 股为六位代码,需注意补齐深交所代码前的 0,结合年份可与国泰安数据库匹配。
  • cusip 和 isin: 国际通用唯一标识符,北美地区为 cusip,其他为 isin。
  • country: 公司所处地区(注意区分国家与地区,如 TW、HK、MO)。

FactSet Company Data

relations.dta

  • 时间段数据:表示公司在 start_至 end_期间的特征属性。
  • rel_type: 供应链关系类型,包括供应商 (supplier)、客户 (customer) 等。该变量表示 target 企业是 source 企业的 rel_type。
  • source/target id: 各自在数据库中的唯一标识符,可与 company.dta 匹配。
  • source/target isin/cusip: 同上。

FactSet Relations Data

2 丁浩员等测度方式解读

2.1 断裂和恢复指标

数据为月度频次,以'供应链关系 - 月份'为单元。例如,若供应链关系在 2019 年 1 月至 6 月存在,则生成六条数据。

断裂 (Break) 若同一供应链关系对在 2019 年 1 月至 6 月存在,7 月至 9 月不存在,10 月至 12 月存在:

  • 1 月至 5 月、10 月至 11 月,Break 为 0。
  • 6 月和 12 月,Break 为 1,代表发生断裂行为。
  • 7 月至 9 月期间无数据。

断裂指标示例

恢复 (Recover) 若供应链在 2019 年 6 月断裂后于 10 月恢复,论文注释中显示在 2019 年 6 月的 Recover 标'1'。

恢复指标示例

另一种标注逻辑是将恢复标记在恢复行为发生的当月(如 2019 年 10 月),下文将展示两种代码实现。

2.2 转移指标

重构中转移变量的测量逻辑如下: 若一家中国供应商有多个外国客户,以客户彻底断裂时间 T(不再出现恢复的最早时间)为基准,若与其他客户构建新关系的时间晚于 T,则将构建新关系的时间 Transfer 标记为 1。

示例:

  • 供应商有 5 个外国客户 A、B、C、D、E。
  • 与 A 的关系:2019 年 1-2 月、10-12 月。
  • 与 B 的关系:2019 年 3-5 月。
  • 与 C 的关系:2019 年 4-7 月。
  • 与 D 的关系:2019 年 6-8 月。
  • 与 E 的关系:2019 年 9-10 月。

最早彻底断链时间为 2019 年 5 月。则在 D 的 6 月份、E 的 9 月份 Transfer 标 1,其他为 0。

最后将 Recover 和 Transfer 的 1 合并,即为 Refill。

2.3 遗留问题

数据说明中提到筛选所有中国上市公司的跨国供应链关系,但转移指标说明中提及可转移到中国,二者可能存在矛盾,需根据研究需求明确界定。

3 供应链断裂与重构指标测度

目标是以中国沪深 A 股上市企业作为供应商,外国企业作为客户的供应链断裂与重构指标测度。

3.1 原始数据库处理

建议根据研究区间精简数据。例如研究区间为 2018-2024,保留 start_为 2018 年及之后的数据。

gen year=year(start_) 
drop if year<2018

3.2 中国沪深 A 股上市企业作为供应商的筛选与调整

3.2.1 原始数据筛选

在 company.dta 里筛选出中国沪深 A 股上市企业,删除没有股票代码的数据,再删除不是 CN 的公司。

drop if missing(ticker) 
drop if country!="CN"

导出至 Excel 进行粗略筛选,仅保留在沪深 A 股上市的企业(代码范围:000001-099999 深证,300000-399999 创业板,600000-699999 上证)。将 id 和股票代码保存为 CNcompany.xlsx。

在 relations.dta 中仅保留 customer 和 supplier 的关系。

keep if rel_type=="CUSTOMER" | rel_type=="SUPPLIER"
3.2.2 供应链数据标记

运行 Python 代码读取 relations.dta,筛选与中国沪深 A 股上市公司相关的供应链关系对。

import pandas as pd

unique = pd.read_excel('CNcompany.xlsx', header=[0])
IDlist = unique['id'].tolist()

df = pd.read_stata('relations.dta')
result = pd.DataFrame(columns=['start_', 'end_', 'id', 'rel_type', 'source_company_id', 'source_ticker', 'source_cusip', 'target_company_id', 'target_cusip', 'flag'], index=range(1, 200000))

index = 1
for i in range(len(df)):
    # 如果 source 和 target 都是中国沪深 A 股上市公司,标记为 S&T
    if int(df['source_company_id'][i]) in IDlist and int(df['target_company_id'][i]) in IDlist:
        result.loc[index, 'start_'] = df['start_'][i]
        result.loc[index, 'end_'] = df['end_'][i]
        result.loc[index, 'id'] = df['id'][i]
        result.loc[index, 'rel_type'] = df['rel_type'][i]
        result.loc[index, 'source_company_id'] = df['source_company_id'][i]
        result.loc[index, 'source_ticker'] = df['SOURCE_ticker'][i]
        result.loc[index, 'source_cusip'] = df['SOURCE_cusip'][i]
        result.loc[index, 'target_company_id'] = df['target_company_id'][i]
        result.loc[index, 'target_cusip'] = df['TARGET_cusip'][i]
        result.loc[index, 'flag'] = 'S&T'
        index += 1
    # 如果 source 是中国沪深 A 股上市公司,标记为 S
    elif int(df['source_company_id'][i]) in IDlist:
        result.loc[index, 'start_'] = df['start_'][i]
        result.loc[index, 'end_'] = df['end_'][i]
        result.loc[index, 'id'] = df['id'][i]
        result.loc[index, 'rel_type'] = df['rel_type'][i]
        result.loc[index, 'source_company_id'] = df['source_company_id'][i]
        result.loc[index, 'source_ticker'] = df['SOURCE_ticker'][i]
        result.loc[index, 'source_cusip'] = df['SOURCE_cusip'][i]
        result.loc[index, 'target_company_id'] = df['target_company_id'][i]
        result.loc[index, 'target_cusip'] = df['TARGET_cusip'][i]
        result.loc[index, 'flag'] = 'S'
        index += 1
    # 如果 target 是中国沪深 A 股上市公司,标记为 T
    elif int(df['target_company_id'][i]) in IDlist:
        result.loc[index, 'start_'] = df['start_'][i]
        result.loc[index, 'end_'] = df['end_'][i]
        result.loc[index, 'id'] = df['id'][i]
        result.loc[index, 'rel_type'] = df['rel_type'][i]
        result.loc[index, 'source_company_id'] = df['source_company_id'][i]
        result.loc[index, 'source_ticker'] = df['SOURCE_ticker'][i]
        result.loc[index, 'source_cusip'] = df['SOURCE_cusip'][i]
        result.loc[index, 'target_company_id'] = df['target_company_id'][i]
        result.loc[index, 'target_cusip'] = df['TARGET_cusip'][i]
        result.loc[index, 'flag'] = 'T'
        index += 1
    else:
        continue

result.to_excel('result.xlsx')
3.2.3 根据 rel_type 关系和 flag 标记进行调整

创建 CN_supplier 和 CN_customer 两个工作表。

  • rel_type 为 customer:target 是 source 的客户。flag 为 S 的不动放 CN_supplier,flag 为 T 的调换位置放 CN_customer。
  • rel_type 为 supplier:target 是 source 的供应商。flag 为 S 的调换位置放 CN_supplier,flag 为 T 的不动放 CN_customer。
  • 列标题 source 改为 supplier,target 改为 customer。

对于 flag 标记为 S&T(两端均为中国沪深 A 股上市公司),若做跨国供应链分析,直接删除即可。

3.3 供应链关系的时间顺序调整与变量测度

3.3.1 时间顺序调整

大部分数据按时间顺序排列,但少部分存在接不上的情况(如上一条 end_早于下一条 start_)。需删除中间行或调整顺序以保证时间连续性。

3.3.2 月度数据的生成

在 Excel 中插入'supplier_customer'空列,拼接 source 和 target id 作为唯一标识符。确保非单行供应链关系调到最后边,避免代码报错。

import pandas as pd

dfindex = 1
monthList = ['2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06', '2018-07', '2018-08', '2018-09', '2018-10', '2018-11', '2018-12', '2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06', '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12', '2021-01', '2021-02', '2021-03', '2021-04', '2021-05', '2021-06', '2021-07', '2021-08', '2021-09', '2021-10', '2021-11', '2021-12', '2022-01', '2022-02', '2022-03', '2022-04', '2022-05', '2022-06', '2022-07', '2022-08', '2022-09', '2022-10', '2022-11', '2022-12', '2023-01', '2023-02', '2023-03', '2023-04', '2023-05', '2023-06', '2023-07', '2023-08', '2023-09', '2023-10', '2023-11', '2023-12', '2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12', '4000-01']

DATA = pd.read_excel('SUPPLIER_DATA.xlsx', sheet_name='Sheet1', header=[0])
SCchain = set(DATA['supplier_customer'])
SCchains = list(SCchain)

df = pd.DataFrame(columns=['supplier_customer', 'supplier_id', 'supplier_ticker', 'customer_id', 'TIME', 'BREAK', 'REFILL', 'RECOVER', 'TRANSFER'], index=range(1, 100000))
adjustSC = []
start = 0
end = 1000

for SC in SCchains[start:end]:
    l = SC.split('-')
    supplier_id = l[0]
    customer_id = l[1]
    index = DATA.loc[DATA['supplier_customer'] == SC].index[0]
    count = 1
    while DATA['supplier_customer'][index + count] == SC:
        count += 1

    if count == 1:
        startmonth = DATA['start'][index]
        endmonth = DATA['end'][index]
        for j in range(monthList.index(endmonth) - monthList.index(startmonth) + 1):
            df.loc[dfindex, 'supplier_id'] = supplier_id
            df.loc[dfindex, 'customer_id'] = customer_id
            df.loc[dfindex, 'supplier_customer'] = SC
            df.loc[dfindex, 'TIME'] = monthList[monthList.index(startmonth) + j]
            df.loc[dfindex, 'BREAK'] = 0
            dfindex += 1
        df.loc[dfindex - 1, 'BREAK'] = 1
    elif count >= 2:
        flag = 0
        breaki = 0
        for i in range(1, count + 1):
            if monthList.index(DATA['end'][index + i - 1]) == monthList.index(DATA['start'][index + i]) and i != count:
                continue
            if monthList.index(DATA['end'][index + i - 1]) < monthList.index(DATA['start'][index + i]) or i == count:
                if flag == 0:
                    startmonth = DATA['start'][index]
                else:
                    startmonth = DATA['start'][index + breaki]
                df.loc[index + i - 1, 'RECOVER'] = 1
                endmonth = DATA['end'][index + i - 1]
                for month in monthList[monthList.index(startmonth): monthList.index(endmonth) + 1]:
                    df.loc[dfindex, 'supplier_id'] = supplier_id
                    df.loc[dfindex, 'customer_id'] = customer_id
                    df.loc[dfindex, 'supplier_customer'] = SC
                    df.loc[dfindex, 'TIME'] = month
                    df.loc[dfindex, 'BREAK'] = 0
                    dfindex += 1
                df.loc[dfindex - 1, 'BREAK'] = 1
                flag = 1
                breaki = i
            elif monthList.index(DATA['end'][index + i - 1]) > monthList.index(DATA['start'][index + i]):
                print(SC + " need to adjust")
                adjustSC.append(SC)

adjustSC = set(adjustSC)
print(adjustSC)
print(len(adjustSC))
chain1 = set(df['supplier_customer'])
chains1 = list(chain1)
print(len(chains1))
print(len(SCchains))
df.to_excel(f'result_{start} to {end}.xlsx')

3.4 供应链转移的测量

读取调整好的供应商 Excel 表和断裂恢复变量 Excel 表,新建 Python 文件测量。

import pandas as pd

monthList = ['2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06', '2018-07', '2018-08', '2018-09', '2018-10', '2018-11', '2018-12', '2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06', '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12', '2021-01', '2021-02', '2021-03', '2021-04', '2021-05', '2021-06', '2021-07', '2021-08', '2021-09', '2021-10', '2021-11', '2021-12', '2022-01', '2022-02', '2022-03', '2022-04', '2022-05', '2022-06', '2022-07', '2022-08', '2022-09', '2022-10', '2022-11', '2022-12', '2023-01', '2023-02', '2023-03', '2023-04', '2023-05', '2023-06', '2023-07', '2023-08', '2023-09', '2023-10', '2023-11', '2023-12', '2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12', '4000-01']

DATA = pd.read_excel('SUPPLIER_DATA.xlsx', sheet_name='Sheet1', header=[0])
df = pd.read_excel('result.xlsx', sheet_name='Sheet1', header=[0])

SCchain = set(DATA['supplier_customer'])
SCchains = list(SCchain)
if '8727858-99946865-688223' in SCchains:
    SCchains.remove('8727858-99946865-688223')

df['supplier_id'] = df['supplier_id'].astype(str)
company = set(df['supplier_id'])
companies = list(company)
print(len(companies))

for company_code in companies:
    company_chain = []
    for SC in SCchains:
        if SC.startswith(company_code):
            company_chain.append(SC)
    if len(company_chain) == 1:
        continue
    elif len(company_chain) > 1:
        startDate = {}
        endDate = {}
        for chain in company_chain:
            index = DATA.loc[DATA['supplier_customer'] == chain].index[0]
            count = 1
            while DATA['supplier_customer'][index + count] == chain:
                count += 1
            start = DATA['start'][index]
            end = DATA['end'][index + count - 1]
            startDate[chain] = start
            endDate[chain] = end
        mindate = monthList.index('4000-01')
        for end_val in list(endDate.values()):
            if monthList.index(end_val) < mindate:
                mindate = monthList.index(end_val)
        for chain, start in startDate.items():
            if monthList.index(start) > mindate:
                print(chain)
                index = df.loc[(df['Relation'] == list_of_key[k]) & (df['Time'] == monthList[mindate])].index[0]
                df.loc[index, 'TRANSFER'] = 1

df.to_excel('A.result.xlsx')

目录

  1. 1 对 FactSet 全球供应链数据库的简单解读
  2. 重要变量解读
  3. 2 丁浩员等测度方式解读
  4. 2.1 断裂和恢复指标
  5. 2.2 转移指标
  6. 2.3 遗留问题
  7. 3 供应链断裂与重构指标测度
  8. 3.1 原始数据库处理
  9. 3.2 中国沪深 A 股上市企业作为供应商的筛选与调整
  10. 3.2.1 原始数据筛选
  11. 3.2.2 供应链数据标记
  12. 3.2.3 根据 rel_type 关系和 flag 标记进行调整
  13. 3.3 供应链关系的时间顺序调整与变量测度
  14. 3.3.1 时间顺序调整
  15. 3.3.2 月度数据的生成
  16. 3.4 供应链转移的测量
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 海康视频插件安装后浏览器提示打开 webcontrol 中间件解决方案
  • VS Code 智能提示(IntelliSense)完全配置指南(C++/Python/JavaScript)
  • DeepSeek-R1 本地可视化运行指南:支持多模型接入与 API 配置
  • Java 后端转 Web3 实战路线图
  • WebView 并发初始化竞争风险分析
  • AionUi:首个开源运行时生成式 UI 框架,实现 AI 实时渲染界面
  • OpenClaw 配置 GLM 实现免费 AI 联网搜索
  • Neo4j 5.26 版本下载安装与配置指南
  • Mac Mini M4 本地运行 AI 模型配置指南:Ollama 与 Stable Diffusion
  • Qwen3-VL 模型架构及原理详解
  • gsplat 跨平台安装配置指南:Windows/Linux/Mac
  • 主流 AIGC 检测降重工具实测对比与避坑指南
  • 基于 LLaMA-Factory 微调 Qwen3-VL 视觉模型及 WEBUI 部署
  • WSL2 环境下 Git 与 Gitee 代码管理实战
  • 大型语言模型基础:预训练、生成式模型、提示与对齐技术详解
  • IQuest-Coder-V1 vs Meta-Llama-Code:指令模型精度实测
  • Stable Diffusion 与 Z-Image-Turbo 快速搭建与效果对比方案
  • Xilinx Vivado 2020 版本安装流程及常见问题解析
  • Stable Diffusion 3.5 FP8 模型在 AIGC 平台的应用与优化
  • Windows 下安装 OpenClaw 并接入飞书机器人指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online