尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Zephyr中国跨国并购数据清洗与分析:从解压到入库全流程指南

发布时间:2026/9/26 12:43:55

资讯中心
01
ARTICLE

Zephyr中国跨国并购数据清洗与分析:从解压到入库全流程指南

Zephyr中国跨国并购数据清洗与分析:从解压到入库全流程指南
简介Zephyr是全球企业并购领域常用数据库这份数据包收录了其中2000—2024年中国跨国并购交易的完整导出结果面向高校师生、券商研究员及企业战略分析人员可用于学术论文撰写、行业趋势研判与投资决策参考。压缩包共2个文件主体为一个xls格式数据表包含交易双方、所属行业、交易金额、宣布日期等关键字段可直接导入Excel或统计软件进行筛选与建模另附一个html格式的来源说明页便于核对数据口径和检索条件。数据覆盖24年长周期有助于观察中国跨境并购的规模变化与行业分布目前已有121人学习下载。借助这份数据读者可省去逐条检索国际数据库的繁琐流程快速获得标准化的并购样本并在此基础上开展描述统计、回归分析或案例深挖。1. 拿到zephyr中国跨国并购数据包第一件事不是解压做跨境并购研究的人对 zephyr 中国跨国并购数据2000-2024年.zip 这个文件名应该不陌生。它背后是 BvD 出品的 Zephyr 并购数据库专门记录全球并购、合资、入股、资产收购等交易。这个离线包能解决的核心问题只有一个在不继续烧数据库订阅费的前提下拿到一份时间跨度长、字段基本规范的中国企业跨境交易样本用来做学术回归、行业白皮书或者内部尽调的历史参照。适合三类人——写论文的研究生、做境外标的筛选的分析师、需要维护并购历史底稿的数据工程师。但打开这个 zip 之前你要先有个心理准备里面的数据远不是“解压就能跑”的状态乱码、缺失金额、重复记录是常态真正的活儿从清洗才开始。2. 拆解 zip 结构与 Zephyr 数据库的通用布局先把字段背景摸透2.1 交易主表deal与各方角色为什么一个交易可能有多行记录Zephyr 的底层逻辑走的是“一笔交易一条主记录”但中国跨国并购这个主题把场景拉复杂了。常见导出包里会区分交易主表deals和参与方表deal/company link。拿 A 公司收购德国 B 公司 100% 股权这个例子来说交易主表里 deal id、公告日期、交易金额、状态都在一行里,但参与方表会有多行一行是买方 A一行是卖方 C一行是目标公司 B甚至还有财务顾问、法律顾问。如果你直接把两表 join 起来一条交易就可能展开成三五行这在按数量统计时非常容易翻车。另一个要注意的角色字段是买方是否实际控制人或最终受益人。Zephyr 数据里通过 target global ultimate owner目标公司全球最终控制人和 acquirer global ultimate owner买方全球最终控制人两个字段来标记真正的决策主体。做跨国并购分析时建议以这两个字段去重而不是看表面公司名。表面公司名经常是“壳”比如买方登记名是香港子公司最终控制人却是内地集团。这个字段在跨国研究里几乎是必用项如果你只按公司法律名称统计会得出“香港是最大买家”这类偏颇结论。2.2 公司表、股东表与公告记录关联查询的基本路径离线包里除了 deal 相关表通常还会带公司基本信息表companies与股东表shareholders。公司表字段一般包括 BvD IDBvD 的公司唯一编号、公司名称、注册地国家、行业代码NAICS 或 NACE、上市状态、员工人数、营业额、最终控制人等。这张表的核心价值在于给每个参与方补国籍、补行业不补的话跨国维度、行业维度的统计没法做。例如你拿到一个买方公司的 BvD ID先在 companies 表里查出它注册地是开曼再去查 ultimate owner 的国家才是真正的地域归属。这两查一换统计口径就完全不同。股东表的用途在“股权穿透”场景下非常关键。中国跨境并购里大量是 50:50 合资、分阶段收购、先入股再控股交易形态不是一次买断。股东表记录了交易发生时各参与方对标的公司的持股比例你可以用它在清洗时进行二次校验——如果一条交易宣称“取得控制权”但股东表里买方增持后只有 30%那这条记录的 deal status 或 deal type 大概率有标注意外。做这种校验不需要写入分析报告但能帮你发现哪批记录的质量不可信。2.3 跨国并购数据集的时间跨度与口径变化2000-2024年数据要小心的问题2000-2024 这个区间跨越了互联网泡沫、2008 年金融危机、2015 年中资出海高峰、疫情后的结构性调整。这么多年里Zephyr 的口径有过数次调整直接拿早期数据与近期数据对比会得出诡异的结论。最常见的口径变化是dealmaking 金额的币种单位。早期的记录大量默认以百万美元计后期逐步统一为千美元如果你不查字段字典直接求和一个“1.20”在早期代表 120 万美元在后期代表 1200 美元差 1000 倍。再一个典型变化是dealing status 的取值2005 年前很多交易会在完成后不更新 status至今显示“Announced”导致完成率向下扭曲2015 年以后 Zephyr 加强了公告回溯把不少旧交易重新标记为“Completed”。处理时间序列时我一般会在年度报告处加注释2008 年前完成状态偏保守趋势分析要多看数量少看绝对金额。3. 解压、加载与清洗用 pandas 跑通数据从 zip 到整洁表3.1 解压 CSV 并处理中文乱码与 UTF-8 BOM 问题拿到 zephyr 中国跨国并购数据2000-2024年.zip 先别急着 extractall先用 Python 把 zip 列表打印出来确认每个文件的大小。文件 0 字节的直接扔掉文件超过百兆的强制 UTF-8 编码读取很可能会中途报错报错信息最常见的就是UnicodeDecodeError。原因是 Zephyr 导出 CSV 虽然标着 UTF-8但实际用了 UTF-8 BOM 且字段里混入了 GBK 编码的中文公司名。解压和初读的代码我会这样写import zipfile import pandas as pd from pathlib import Path zip_path Path(zephyr_cn_cross_border_2000-2024.zip) extract_dir Path(zephyr_raw) extract_dir.mkdir(exist_okTrue) with zipfile.ZipFile(zip_path, r) as zf: namelist zf.namelist() print(namelist) zf.extractall(extract_dir) # 预测编码并读取第一个CSV csv_path extract_dir / namelist[0] with open(csv_path, rb) as f: raw f.read(2000) # 检查是否带UTF-8 BOM if raw.startswith(b\xef\xbb\xbf): enc utf-8-sig else: enc utf-8 df pd.read_csv(csv_path, encodingenc, low_memoryFalse) print(df.head())encodingutf-8-sig的作用是自动把文件头部的 BOM 吃掉不至于第一列字段名变成\ufeffdeal_id。low_memoryFalse让 pandas 一次性推断所有列类型而不是按块推断——按块推断时金额列如果前几块全是空值后面有数字会被误判成 object 类型这是离线大数据集里特别隐蔽的问题。第一步读完后我先打三张表列名清单、每列非空数量、每列 dtype。这比看 any 数据都管用能快速发现哪些列是真正可用的核心字段哪些是导出时自带但全空的辅助字段。全空列直接 drop别让它在后面 join 时制造行数膨胀。3.2 标准化日期、金额、交易状态三类字段清洗的核心只有三类字段日期、金额、状态。日期字段一般是 announcement date、completed date、effective date 三个并存。Zephyr 的日期格式常见两种03/11/2015月日年和2015-11-03ISO同一个文件里两种都有。一个稳健的标准化做法是先把所有日期列统一转为字符串然后按格式逐个用pd.to_datetime解析from datetime import datetime def parse_zephyr_date(series): # 先转字符串统一空格与斜杠 s series.astype(str).str.strip().str.replace(/, -) # 用errorscoerce把解析不了的挤成NaT再回头排查 parsed1 pd.to_datetime(s, format%d-%m-%Y, errorscoerce) parsed2 pd.to_datetime(s, format%Y-%m-%d, errorscoerce) parsed parsed1.fillna(parsed2) # 还有可能是 15/03/2011 00:00:00 这种带时间尾的 parsed3 pd.to_datetime(s, format%d-%m-%Y %H:%M:%S, errorscoerce) return parsed.fillna(parsed3) df[ann_date_dt] parse_zephyr_date(df[announcement date]) df[comp_date_dt] parse_zephyr_date(df[completed date])errorscoerce是处理脏日期数据的本命参数。它不抛异常而是把解析不了的值置为 NaT事后可以用df[df[ann_date_dt].isna()]精准查看问题行而不是整个任务崩掉。格式判断顺序上先试%d-%m-%Y再试%Y-%m-%d是因为 Zephyr 旧数据里月日年在前面出现的频率更高试错命中率也高一些。金额字段的标准处理是拆分出数值和货币两列。常见字段名是 deal value / deal currency。注意deal value 列里偶尔会出现字符串如1.2bn或者not disclosed。要先把这类文本捞出来单独处理def clean_value(val): if isinstance(val, str): v val.strip().lower() if bn in v: return float(v.replace(bn, ).strip()) * 1e3 # 统一到百万美元后再转千美元 if m in v: return float(v.replace(m, ).strip()) if not disclosed in v or na in v: return None return float(val) return val df[deal_value_mn_clean] df[deal value].apply(clean_value)到这一步金额数值已经归一化到“百万”单位后面再结合 currency 列做汇率换算。但提前说一句汇率的处理别在 pandas 里用当年汇率直接乘详情见第 5 章专门讲坑的地方。3.3 实体去重与合并同一交易多记录怎么归并Zephyr 离线包最大的性格特点是“数据全但要按业务规则去重”。一个 deal id 在参与方表里有多行很正常但交易主表也有多行的情况多半是阶段化交易第一期购 20%第二期再购 80%两期共用同一个 group deal id。这种情况下如果你只是单纯的df.drop_duplicates(deal id)可能留下的是第一期那笔小额记录而金额分析想要的总交易额是两期之和。常见去重逻辑是# 按group_deal_id分组金额取最近一期公告的值日期取首期公告日 df_sorted df.sort_values([group deal id, ann_date_dt]) dedup df_sorted.groupby(group deal id).agg( deal_id(deal id, last), ann_date(ann_date_dt, first), deal_value_clean(deal_value_mn_clean, last), deal_currency(deal currency, last), deal_status(deal status, last), acquirer_guo(acquirer global ultimate owner, last), target_name(target company name, last), target_guo(target global ultimate owner, last), ).reset_index().agg里用last取阶段的末期记录是因为分期交易的最后一期才是最终对价比如“20% 收购对价 3000 万一年后 80% 对价 1.2 亿”整体价值应该是末期的deal_value。first取公告日期则保证了交易时间跨度的起点一致。如果你的研究主题更关注交易数量而不是金额建议以group deal id为单位计数否则分期交易会被数成两条。4. 构建分析指标年度趋势、行业分布与国别流向的复现代码4.1 按公告日期聚合年度交易金额与数量清洗完成态后第一个常规动作就是画年度交易额统计。需要注意两类正确做法金额缺失的记录要不要纳入计数我通常分两个口径输出——一个只看金额非空记录的总额另一个统计所有完成交易的数量避免“2020 年金额暴跌”其实是“金额披露率下降”造成的假象。import pandas as pd df[year] df[ann_date_dt].dt.year has_value df[deal_value_mn_clean].notna() annual_amount df[has_value].groupby(year)[deal_value_mn_clean].sum().rename(ann_amount) annual_count df.groupby(year)[deal_id].nunique().rename(deal_count) annual pd.concat([annual_amount, annual_count], axis1) annual[avg_deal_size] annual[ann_amount] / annual[deal_count] annual.to_csv(annual_trend.csv, encodingutf-8-sig)这里用deal_id的nunique而不是size是因为参与方表 join 后同一笔交易会展开成多条行如果用size计数交易数量会被虚增且不建议用df.drop_duplicates()之后再计数那样会把两笔不同交易误删。画图时建议对数纵轴因为金额跨度从几百万到两三百亿美元线性轴会直接把早期年份压成一条直线。4.2 买方国别与目标国别透视做中外双向并购对比跨国并购研究绕不开“谁在买、买哪国”的分析。正确做法是用“全球最终控制人所属国”字段而不是注册地字段。这里往往会发现一个有意思的现象大量标着中国央企的买方 BvD ID 其注册地是香港或百慕大但 ultimate owner 指向北京母公司。而境外资本进入中国也会出现买方是新加坡注册公司但背后是欧美基金的情况。pivot pd.crosstab( df[df[target country].isin([China, 中国])][acquirer guo country], df[year], valuesdf[deal_value_mn_clean], aggfuncsum, ) pivot_in pivot.fillna(0) # 外资收购中国标的 outbound df[df[acquirer guo country].isin([China, 中国])] pivot_out pivot_out pd.crosstab( outbound[target country], outbound[year], valuesoutbound[deal_value_mn_clean], aggfuncsum, ) pivot_out pivot_out.fillna(0) # 中国资本收购境外标的pd.crosstab比groupby pivot更省事参数顺序是index放分析维度比如买方国别columns放时间维度values放金额aggfunc用sum。跑完后再把两个表写进 Excel用透视表做条件格式比直接画图更能看清行业异动。实战里我还会额外生成一个“交易数量”版本的透视表因为金额集中在几笔特大交易数量分布才能反映大众化并购节奏。4.3 按行业与交易类型分组的价值分布行业分组这个环节数据里常见的行业字段是 primary sector主要行业和 primary industry细分行业用的分类体系一般是 NACE。Zephyr 的 primary sector 粒度大约二十几个适合做宏观分布细分 industry 有几百个适合做热点挖掘。建议两个维度都建好sector_grp df[has_value].groupby([primary sector, year])[deal_value_mn_clean].sum() sector_grp sector_grp.reset_index() # 找出历年前10大行业 top sector_grp.groupby(primary sector)[deal_value_mn_clean].sum().nlargest(10).index top_data sector_grp[sector_grp[primary sector].isin(top)] top_data.to_csv(top10_sector_trend.csv, encodingutf-8-sig)交易类型deal type字段里常见取值包括acquisition收购、minority stake少数股权、JV formation成立合资、buyback回购、privatisation私有化。做中国跨境并购时有两类交易容易引起误解一个是“JV formation”中资出海常常先成立合资公司再逐步增资合资本身不算“并购完成”但如果只看 deal type 不关联后续增资记录会低估实际控制权转移的交易数量另一个是“privatisation”主要发生在中国境外标的中概股回归场景回归交易在实际分析里应该单独建一个 flag避免与常规跨境收购混在一起统计。5. 常见坑位排查处理 zephyr 离线包时最容易翻车的几个问题5.1 问题一交易金额缺失率高达四成怎么补救现象清洗完成后发现 2000-2010 年区间有将近四分之一的记录没有 deal value有些年份甚至超过四成缺失导致年度趋势图断崖式下跌。原因早年公告对交易金额披露不充分很多并购协议只写明“收购不超过 X 股”、或压根不披露价格Zephyr 也就没有录入准确金额。解决先不要手工补数。常见做法是看股东表里有没有股本变化数配合 companies 表的实缴资本估算最低对价研究用途的建议单独建一个“有无金额”二值变量进回归模型把缺失当作信息而不是错误。如果要画总额趋势图就在图注里写明披露率避免读者误读成交易额骤降。5.2 问题二同一交易出现多条记录且金额不同现象一个 deal id 在交易主表里存在两行一行金额是 500 万美元另一行是 700 万美元公告日期分别相差半年。原因这大概率是分期收购或对赌调整earn-out导致的阶段记录。Zephyr 会把调整后的新记录和新金额一起导入而不更新旧记录。解决先按group deal id分组如果同一个 group 内金额相差不超过 20%取最大值而非平均值——平均值在样本里没有任何经济含义如果金额差一倍以上多半是“先参股、后控股”直接以末期的金额和状态为最终值。计算完成成功率时也要以每组的最后一条状态为准。5.3 问题三货币与汇率口径不一致直接汇总就错现象统计总金额时发现 2018 年的总额异常巨大单年超过相邻年份一个量级。查明细发现不少记录的deal currency是人民币数值是几十亿但如果没有按当年平均汇率折算到美元直接和美元金额相加就会把小数点位置推高。原因Zephyr 金额原币和美元折算后并存export 时默认原币显示。解决写一个年度汇率映射表用人民币兑美元年度平均汇率做折算。注意两个细节一是用年度平均汇率不用年末即期汇率并购交易分散在全年都用年末汇率会系统性高估人民币升值年份的交易额二是在输出的数据集里保留原始货币列方便复核不要在内存里直接覆盖原币字段。5.4 问题四中文公司名编码错乱导致匹配失败现象目标公司是中文名时读取后显示乱码或者是正常的汉字但跟同一公司出现在另一行的英文名匹配不上导致 join 后丢失大量参与方信息。原因离线包导出时使用 UTF-8,但随后被某些工具重新以 GBK 保存再回到 pandas 读就成了乱码。解决解压后先用chardet或charset-normalizer自动识别每个文件的编码识别出 GBK 后用encodinggbk读。另一条更省事的路线不直接匹配中文名而是通过 BvD ID 做关联中文名只作为展示字段。5.5 问题五公告状态与实际完成状态不一致现象显示“Completed”的交易股东表里买方持股比例并没有超过目标公司总股本的一半。原因交易是对赌完成或表决权委托安排实际控制权已转移但不以股权过半为标志。解决写五条校验规则用股东表里交易后的买方持股比例去映射一个“推测控制权状态”。如果推测状态与 deal status 冲突把冲突标记为“status_conflict”。这份冲突记录值得单独存 Excel写报告时能快速找到有争议的交易而不是在文本里逐步手工核对。6. 进阶收尾把清洗后的数据落进 SQLite做月度滚动验证6.1 建表与批量导入告别 pandas 长驻内存工作流离线包数据动辄几十万行老是驻留在 pandas DataFrame 里切视角要反复重跑脚本效率低。常见的做法是清洗完成后直接转进 SQLite把它当本地数据仓库后续验证和交叉查询都用 SQL 来做启动快到几乎零成本。import sqlite3 conn sqlite3.connect(zephyr_cn_clean.db) df.to_sql(deals, conn, if_existsreplace, indexFalse) df_company.to_sql(companies, conn, if_existsreplace, indexFalse)to_sql不需要手动建表pandas 会自动根据 dtype 映射字段类型。但 float 列会被映射成 REAL日期列会变成 TEXT做范围查询时注意WHERE year BETWEEN 2008 AND 2015这类比较先确认年字段存的是整数还是字符串。如果存成字符串比较时要补CAST(year AS INTEGER)。6.2 用 SQL 校验数据重复率、缺失率、时间断层一条语句查清入库后常用一组校验 SQL 把数据质量量化出来这三条语句基本能覆盖数据健康度的 80%-- 1. 重复交易检查 SELECT group deal id, COUNT(*) AS cnt FROM deals GROUP BY group deal id HAVING cnt 1 ORDER BY cnt DESC; -- 2. 金额缺失率按年统计 SELECT CAST(strftime(%Y, ann_date_dt) AS INTEGER) AS yr, ROUND(AVG(deal_value_mn_clean IS NOT NULL), 2) AS value_coverage FROM deals GROUP BY yr ORDER BY yr; -- 3. 时间断层检查抽查2018年每月公告数 SELECT strftime(%Y-%m, ann_date_dt) AS ym, COUNT(*) AS cnt FROM deals WHERE ann_date_dt 2018-01-01 AND ann_date_dt 2019-01-01 GROUP BY ym;重复检查里用group deal id而不是deal id因为阶段性交易在不同 deal id 下会重复出现。时间断层检查则是为了发现有没有某个月全部丢失——这种“整月消失”几乎都是导出脚本漏了数据块不是交易市场上的真实波动。6.3 验证数据完整性的经验拿公告价格与支付倍数对账最后做一次保险意义上的验证挑 10 笔你熟悉的知名交易比如某个中国集团收购海外矿业项目或外资收购消费品牌用清理后的数据里的公告金额、目标公司的营业额算出 EV/Sales 倍数再和你从公开新闻里看到的倍数做对比。如果倍数差超过两三倍说明金额没逃过币种折算坑如果倍数差不多说明这批数据的核心字段基本可信。这里也是我对这套数据包最深的体会Zephyr 离线包的数据覆盖率再高都需要自己建一套验证基准不然你都不知道错误在哪一列。我自己的习惯是保留一个只有十行的小文件validation_trades.csv每次处理完新一批数据就把那十行对应交易重新对一遍不匹配就回查清洗脚本而不是继续往模型里灌。这样维护下来后面写报告基本不会因为数据来源被质疑而翻车。希望这整套从解压到入库验证的流程能帮你在面对 zephyr 中国跨国并购数据2000-2024年.zip 时少走几步弯路。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。