尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

2014-2025上市公司员工持股计划全量数据分析:从SQLite到Spark实践

2014-2025上市公司员工持股计划全量数据分析:从SQLite到Spark实践 简介面向金融数据分析、学术研究与投研建模人员提供一套上市公司员工持股计划与高管薪酬数据集的网盘索引文档。资源包内仅1个docx文件大小12KB打开即可获取百度网盘链接与提取码网盘压缩包约50多MB收纳员工持股计划变动明细、持有人信息、基础信息、进度明细、行业统计、资管信息以及高管人数、员工结构与薪酬水平等十余个zip表格。数据基于上市公司年报、公告及相关省、市数据整理覆盖沪深北证A股主板、中小企业板、创业板、科创板、北交所服务板块超过5000只个股时间跨度覆盖员工持股计划2014-2025、员工结构2006-2024、高管与员工薪酬1990-2024等区间可用于员工持股参与度、董监高认购比例、薪酬激励效应等专题分析。目前已有87人学习适合需要结构化金融数据并希望省去手工整理的投资者、高校师生与券商研究员。1. 员工持股计划数据为什么值得做一次全量分析上市公司员工持股计划从2014年集中试点到现在已超过十年刚好覆盖完整的政策周期与市场周期。做金融领域的数据分析只看单一年份或单一公司容易得出偏差结论而把2014到2025年的公告数据拉通后可以回答几个业务方真正关心的问题哪些行业的员工持股参与度最高、高管与普通员工的持股成本差多少、锁定期结束后股价表现如何、薪酬与持股之间是否存在对冲关系。这篇文章就以证券监督管理机构披露的上市公司员工持股计划草案、实施公告和定期报告为数据基础带着你用可复现的方式走一遍从采集、清洗到统计建模的完整流程。无论你是做金融数据分析、企业治理研究还是薪酬绩效设计这篇内容都能直接落成一套可运行的本地分析脚手架。2. 2014-2025员工持股计划数据的采集来源与数据库建模2.1 为什么数据源选择交易所官网与定期报告交叉验证员工持股计划数据在金融领域的公开渠道主要有四类证券交易所官网的披露公告、上市公司年报与半年报、Wind或Choice这类商用终端、以及第三方数据商的API接口。商用终端虽然字段齐全但历史数据存在口径调整和复权问题尤其是早期计划中经常出现“认购价格待定”这类非标字段。我一般选择交易所官网披露的原始PDF与巨潮资讯的XBRL结构化数据做交叉验证再用年报中的“股份变动情况表”校对实际过户数量。这样做的原因是员工持股计划从董事会预案到非交易过户完成中间存在至少三到六个月的窗口期如果只抓预案数据会导致持股规模明显高估。采集层我用Python的requests加BeautifulSoup来抓取公告列表页再用pdfplumber解析PDF中的关键信息。交易所官网的公告列表接口反爬策略比较温和每两次请求间隔两到三秒即可但需要注意分页参数的偏移量不是简单的页数乘以条数部分年份的公告编号存在跳号。对于这部分原始采集逻辑建议维护一张增量表记录已抓取的公告编号避免重复解析。2.2 SQLite建模把非结构化公告转成可统计的宽表拿到原始文本后需要设计存储结构。金融领域的员工持股数据分析通常要做三类查询按时间维度看计划数量趋势、按公司维度看持股与薪酬关系、按员工类型看参与结构。用SQLite作为本地分析库足够支撑这些场景且零运维成本。我先建三张核心表schema如下CREATE TABLE plan ( plan_id TEXT PRIMARY KEY, company_code TEXT NOT NULL, company_name TEXT NOT NULL, announce_date TEXT, plan_status TEXT, total_shares INTEGER, total_amount REAL, source_price REAL, employee_count INTEGER ); CREATE TABLE participant ( plan_id TEXT, category TEXT, person_name TEXT, position TEXT, shares INTEGER, amount REAL, FOREIGN KEY (plan_id) REFERENCES plan(plan_id) ); CREATE TABLE salary ( company_code TEXT, year INTEGER, exec_name TEXT, position TEXT, total_salary REAL, stock_shares INTEGER, PRIMARY KEY (company_code, year, exec_name) );plan表存放每个计划的主体信息participant表记录董监高及核心员工的认购明细salary表从定期报告的“董事、监事和高级管理人员报酬情况”章节解析而来。需要说明的是participant表中的shares字段在部分公告里是以“万股”为单位披露的解析时我会统一换算为股数据处理中这个单位不一致问题在2016年前后的公告中尤其常见同一家公司前后年份口径都会变化所以在ETL的清洗环节必须先做单位标准化否则后续聚合结果会差几个数量级。3. 员工结构统计用Python与Excel透视拆解参与率与认购集中度3.1 员工持股计划的参与结构分析维度员工结构分析是衡量计划激励效果的第一层指标。常见做法是先把计划的总参与人数与公司当年年报披露的员工总数做比对算出覆盖率。这个指标在金融行业尤其值得关注——券商和银行的员工基数大、分支机构多但一线业务人员与总部中后台的参与意愿差异明显单纯看覆盖率会掩盖结构性问题。我把员工结构拆成四个维度进行数据分析人数占比、人均认购金额、高管认购占比、以及认购金额的基尼系数。最后一个指标能有效识别出“高管拿大头、普通员工陪跑”的失衡计划。要实现这四个维度的计算最直接的方式是用pandas做分组聚合import pandas as pd import numpy as np # 读取participant表 participant_df pd.read_sql(SELECT * FROM participant, conn) plan_df pd.read_sql(SELECT * FROM plan, conn) # 合并计划信息 merged participant_df.merge(plan_df[[plan_id, company_code, announce_date]], onplan_id, howleft) # 计算高管认购占比和普通员工人均金额 category_stats merged.groupby([company_code, category]).agg( person_count(person_name, count), total_shares(shares, sum), total_amount(amount, sum) ).reset_index() # 计算每家公司的高管认购集中度 exec_stats category_stats[category_stats[category] 高管] normal_stats category_stats[category_stats[category] 普通员工] pivot_result pd.pivot_table(merged, indexcompany_code, columnscategory, valuesamount, aggfuncsum, fill_value0) pivot_result[exec_ratio] pivot_result.get(高管, 0) / pivot_result.sum(axis1)这段代码的核心逻辑是先按公司和人员类别分组统计人数与金额再用pivot_table生成宽表计算高管认购占比。参数说明aggfuncsum表示对金额做加总fill_value0解决部分公司不存在高管认购记录时产生的空值问题。这里有一个金融数据处理的细节——部分2020年后的公告不再区分“高管”和“普通员工”而是按“董事、监事、高级管理人员”和“其他员工”披露所以category字段在建表时需要用正则表达式做一次归一化映射把这两种口径统一成同一种标签。3.2 基于Excel的交叉验证方法数据库层面的计算结果还必须回到原始Excel表单中做抽样核对。通常操作是打开原始公告表格用Excel的数据透视表按“员工类型”和“认购金额区间”拉交叉表与SQL查询结果响应比对。这里有个经验值抽5家公司每家核对三个字段——参与人数、员工持股总数、高管认购比例如果全部一致则视为ETL流程正确。如果发现SQL结果与Excel不一致优先检查participant表中有没有同一名高管因职务变动在年内被披露两次这会造成人数虚增。4. 高管持股薪酬水平统计锁定价格、杠杆倍数与信息披露口径4.1 高管持股与薪酬的联动分析框架员工持股计划中高管持股的特殊性在于资金来源。从计划草案披露的信息看员工持股计划的资金来源一般有四种合法薪酬、自筹资金、股东借款、以及杠杆结构化资金。在金融领域的上市公司中使用杠杆资金的比例要高于一般制造业企业这与金融机构本身对资本运作工具更熟悉有关。这部分数据直接反映在计划的“资金来源”字段里做统计分析时我会生成这样一张汇总表计划代码、公司简称、公告年份、员工资金总额、杠杆资金比例、高管认购占比。通过相关性矩阵可以识别杠杆比例与高管认购之间是否存在正向联动。更进一步把高管在员工持股计划中的获授股份与年报披露的薪酬水平放在同一张表里可以计算“薪酬持股比”这个指标——即高管年度薪酬总额与当年参与持股计划认购金额的倍数关系。这个指标用来衡量激励的长期绑定效应比值越低说明高管越倾向于通过持股来获取收益而非依赖短期薪酬。金融监管机构在审查计划合理性时也常常关注高管认购金额是否显著超过其年度薪酬水平。4.2 薪酬数据批量提取与比例计算薪酬数据存放于年报的PDF与XBRL实例文件中很难直接读到便捷格式。我通常采用跳过PDF解析、直接抓取巨潮资讯的XBRL数据包的方式因为交易所要求上市公司从2020年起同步报送标准化数据而XBRL在“报酬情况”节点下具有固定的元素名。下面是一个从XBRL提取高管薪酬的简化实现import requests import xml.etree.ElementTree as ET # XBRL文件的命名空间 ns {xbrl: http://www.xbrl.org/2003/instance, link: http://www.xbrl.org/2003/linkbase} def parse_salary_from_xbrl(xbrl_url, company_code, year): resp requests.get(xbrl_url, timeout15) root ET.fromstring(resp.text) salary_data [] # 遍历所有context为当年高管的薪酬节点 for elem in root.iter(): tag elem.tag.split(})[-1] if tag in [SalaryOfDirectors, RemunerationOfTopManagers]: context_ref elem.get(contextRef) # 通过contextRef过滤出目标年度与目标公司 if company_code in context_ref and str(year) in context_ref: salary_data.append({ name: elem.attrib.get(name, ), value: float(elem.text), unit: elem.attrib.get(unitRef, ) }) # 按人汇总年度薪酬 salary_df pd.DataFrame(salary_data) salary_summary salary_df.groupby(name).agg( annual_salary(value, sum), paid_currency(unit, first) ).reset_index() return salary_summary这段代码里contextRef是XBRL中关联上下文的关键属性代表了某个数据点所属的期间与实体。需要注意年度过滤逻辑——有些公司披露的是“报告期内从公司获得的报酬总额”而有些公司额外披露了“期末持股数”这两个概念不可直接加总。在做“高管薪酬与持股”这类统计时正确方式是把年度薪酬和计划认购金额视为两个独立变量分别做描述性统计并计算Pearson相关系数而不是相除得到一个误导性的倍数。5. Spark大数据分析员工持股与薪酬数据的进阶能力5.1 为什么当数据量增长时需要迁移到Spark当把时间跨度拉长到十年以上、且同时纳入全市场五千余家上市公司的高管薪酬明细后单机pandas在应对全内存聚合时会明显力不从心。尤其在做“多家公司连续多年持股计划与薪酬数据”的关联分析时数据规模会从几十万条膨胀到千万级。此时把数据导入Spark做分布式处理是标准的进阶路径。相比数据库与单机脚本Spark的强项在于多阶段转换和宽表关联时能够将中间结果缓存于内存避免频繁读写磁盘。金融领域做员工持股计划和薪酬数据时我通常用Spark完成两部分工作第一步是十亿行级别的大宽表构建把员工明细、薪酬、股价行情三张事实表做全量左连接第二步是滚动窗口聚合计算“过去三年高管股权激励累计值”。5.2 用Spark SQL完成全量关联统计的关键步骤Spark支持直接读取SQLite的表文件但为了获得最佳性能我会先把数据目录指定为Parquet格式存储。下面的代码演示了如何在Spark环境中计算每年各行业高管薪酬与持股比例的汇总值from pyspark.sql import SparkSession from pyspark.sql.functions import col, year, sum as spark_sum spark SparkSession.builder \ .appName(ESOP_Executive_Analysis) \ .config(spark.sql.shuffle.partitions, 200) \ .getOrCreate() # 读取Parquet格式的历史数据 salary_sdf spark.read.parquet(data/salary/*.parquet) plan_sdf spark.read.parquet(data/plan/*.parquet) employee_sdf spark.read.parquet(data/participant/*.parquet) # 关联计划与参与人计算高管份额 exec_participation employee_sdf.filter(col(category) 高管) \ .join(plan_sdf.select(plan_id, company_code, announce_date), plan_id) \ .withColumn(year, year(announce_date)) # 关联薪酬和持股数据按年度与行业聚合 analytics_result salary_sdf.alias(s) \ .join(exec_participation.alias(e), [col(s.company_code) col(e.company_code), col(s.year) col(e.year)]) \ .groupBy(col(s.year), col(s.industry)) \ .agg( spark_sum(e.amount).alias(exec_purchase_amount), spark_sum(s.total_salary).alias(total_salary) ) analytics_result.orderBy(year, industry).show(50, truncateFalse)关键参数的说明spark.sql.shuffle.partitions控制shuffle阶段的并行度默认200对金融数据这种千万级规模是合理的起点如果集群内存紧张可调低到120。两表关联时使用复合键[company_code, year]能够避免把同一公司不同年度的数据错误关联由于历史原因同一股票代码在2014到2025年间存在极少数退市后重新上市的情况因此复合键不要只用公司代码。5.3 用Spark弥补报表层面的统计空白Spark计算结果通过write.mode(overwrite).parquet(...)落到分析服务器上的共享目录这样Excel与Python脚本都可以读取同时避免了单机内存溢出的问题。在金融数据分析场景中这条链路比直接在关系型数据库里跑大JOIN要快得多——磁盘读写的瓶颈不会成为约束。6. 验证与进阶技巧用净收益还原法校验统计口径员工持股计划在锁定到期后的实际表现是回溯检验整个数据分析流程质量的最有效手段。常见的验证算法是做一次“净收益还原法”以计划公告时的认购价格加杠杆成本为基准计算锁定期结束后按市价计算的总收益率扣除资金成本后得到员工的实际激励水平。这个结果反过来可以验证前面采集的source_price字段是否准确——如果批量计算出的收益率分布中出现极端值比如年化超过500%基本可以判定原始价格字段存在单位错误或复权遗漏。用Python实现的核心逻辑如下# 净值还原法验证 def validate_esop_profile(plan_row, market_prices): cost plan_row[employee_total_amount] # 杠杆型计划需计算融资成本设定7%年化 leverage_ratio plan_row.get(leverage_ratio, 1.0) years_held (plan_row[unlock_date] - plan_row[announce_date]).days / 365.0 if leverage_ratio 1: borrowed cost * (leverage_ratio - 1) / leverage_ratio finance_cost borrowed * (pow(1.07, years_held) - 1) else: finance_cost 0.0 total_invest cost finance_cost # 解锁日均价为参考卖出价 unit_price market_prices.loc[plan_row[unlock_date], close] proceeds plan_row[total_shares] * unit_price net_return (proceeds - total_invest) / total_invest return net_return plan_df.apply(lambda r: validate_esop_profile(r, price_table), axis1)这段脚本中的关键参数是年化融资成本7%它应当根据当年市场利率水平做动态调整2021年后建议使用同期贷款市场报价利率加200个基点。当net_return分布呈现双峰形态时前一个峰对应完全自有资金的计划后一个峰对应高杠杆计划这种结构本身就是金融领域员工持股计划运营特征的直接证据。将验证结果与薪酬数据合并画散点图还能观察出一个盈利能力强的公司是否倾向于设计更高杠杆的持股计划——这是判断长期激励与公司业绩真实关联度的重要视角。本文还有配套的精品资源点击获取
返回列表