跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
Python算法

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

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

GopherDev发布于 2026/3/24更新于 2026/5/611 浏览
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 供应链转移的测量
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • VSCode 接入智谱 GLM-4 与自定义大模型配置指南
  • Git clone 速度慢:配置国内镜像、浅克隆的优化方案
  • OpenClaw 实战:基于 Rust+Tauri 构建带安全沙箱的跨平台清理工具
  • 基于 Java 的百度地图驾车路线规划服务集成指南
  • 大数据架构面试核心问题解析:Flink、Spark 与算法
  • 中小团队基于 Ubuntu 的 DooTask 项目管理系统私有化部署实战
  • 文心一言 4.5 开源版本地化部署表现与潜力实测
  • 无人机智能航线规划系统构建指南
  • 微软发布 Phi-3-vision 多模态模型:42 亿参数展现小模型大潜力
  • 攻防世界 Web 题解:SQL 注入与文件包含绕过实战
  • Gemini Pro 实测:多模态、推理与代码能力解析
  • 【机器人】具身导航 VLN 最新论文汇总 | Vision-and-Language Navigation
  • 开源大模型重塑企业 AI 应用:16 个落地案例解析
  • TWIST2:基于 VR 的人形机器人全身遥操与视觉自主策略学习
  • Vivado 工程 Git 版本管理实战指南
  • Docker Compose 部署 OpenClaw 并接入飞书机器人
  • IDEA 创建 Spring Boot 项目配置阿里云 Spring Initializr Server URL
  • Python 使用 Turtle 库实现动态烟花模拟效果
  • Obsidian 配置 Git 插件实现笔记同步到 GitHub(Mac 版)
  • ARM Cortex R52 架构 GICv3 中断控制器详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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