今天给大家分享使用 Stata 测算上市公司人力资本流动、创新产出及流动方向的方法。该指标来源于「空气污染、人力资本流动与创新活力 —— 基于个体专利发明的经验证据」,附件中也提供了该文献的 pdf 文件。
在下面的代码中,上市公司专利数据使用的是之前分享的:
1985~2024 年上市公司与专利数据匹配结果(版本3, 含申请、授权信息):https://rstata.duanshu.com/#/brief/course/04100321f88b411f90429be934934bff
论文中提到使用 AQI 作为空气质量的测度,不过这个指标通常只有 2014 年之后的,平台上也有分享:
2014~2024 年中国各省市区县分年、分月、逐日 AQI 面板数据:https://rstata.duanshu.com/#/brief/course/aa737515f4234c89bcc593a85ad50bc2
如果想进行更长年度的研究,也可以考虑使用 PM2.5 代替,例如这里我使用的就是:
1980 年 1 月~2024 年 12 月各省市区县地表 PM2.5 质量浓度:https://rstata.duanshu.com/#/brief/course/76698bc838ef49c5ab57633aa64b4e06
首先我们读取专利数据进行初步处理:
仅保留授权专利;
根据公开公告号和申请号去除重复专利(专利数据里面同时包含了很多专利的申请和授权公告);
去除外观设计专利;
只保留需要的变量。
实际上原论文也保留了外观设计专利。如果想把外观设计专利纳入分析中,可以保留该部分专利,然后外观设计专利分类号采用 LOC 分类,结构为大类(两位数字)-小类(两位数字)。可以使用前两位数字作为下面的 class 变量。另外也有一些论文认为发明专利的创新性更强,仅选择发明专利进行研究,这样也是不错的,更有说服力,也可以节省一些计算量。
cd "~/Desktop/使用 Stata 测算上市公司人力资本流动、创新产出及流动方向" clear allimport delimited "2010~2014年上市公司与专利数据匹配结果.csv" , clear bindquotes(strict) maxquotedrows(unlimited) stringcols(_all) foreach i of varlist _all { replace `i' = "" if `i' == "NA" } destring 年份, replace drop if missing (授权公告号) | 授权公告号 == "" | 授权公告号 == "NA" keep newipzlid 股票代码 公开公告号 申请号 ipc 年份 专利类型 市 发明人keep if index (专利类型, "发明" ) | index (专利类型, "实用新型" )replace 公开公告号 = ustrregexra(公开公告号, "[A-Z]$" , "" )duplicates drop 股票代码 公开公告号, forceduplicates drop 申请号, forcedrop 公开公告号 申请号 专利类型save dfall, replace
每个专利都可能包含多个 IPC 以及多个申请人,下面使用 split + reshape 进行拆分:
use dfall, clear split ipc, parse (";" ) gen (ipc_)drop ipcgen long_id = _nreshape long ipc_, i (long_id) j (ipc_no)drop if missing (ipc_)ren ipc_ ipcreplace ipc = subinstr (ipc, " " , "" , .)replace ipc = subinstr (ipc, "." , "" , .)gen class = substr (ipc, 1, 3)drop ipc_no long_idsplit 发明人, parse (";" ) gen (inventor_)drop 发明人gen long_id = _nreshape long inventor_, i (long_id) j (inventor_no)drop if missing (inventor_)rename inventor_ 发明人replace 发明人 = subinstr (发明人, " " , "" , .)drop inventor_no long_iddrop ipcduplicates drop _all, forcesave patent_data, replace
再计算创新产出前,我们需要先去除发明人重名的。
根据原文逻辑:同一年、同一发明人、不同城市、不同IPC大类 -> 视为重名:
use patent_data, clear bysort 年份 发明人: egen city_count = nvals(市)bysort 年份 发明人: egen class_count = nvals(class )drop if city_count > 1 & class_count > 1drop city_count class_countsave patent_clean, replace use patent_data, clear count local original_count = r (N )use patent_clean, clear count local clean_count = r (N )disp "原始数据量:`original_count'" disp "剔除重名后数据量:`clean_count'" use patent_data, clear duplicates drop 发明人, forcecount local original_inventors = r (N )use patent_clean, clear duplicates drop 发明人, forcecount local clean_inventors = r (N )local removed_ratio = (`original_inventors' - `clean_inventors' ) / `original_inventors' display "重名的人占:" `removed_ratio'
然后分组统计每年每位发明人申请的专利总数即为创新产出:
*- 此处代码需下载讲义材料查看~ list in 1/10 *> +------------------------------+ *> | 发明人 年份 patent | *> |------------------------------| *> 1. | A·R·纳戈帕尔 2012 1 | *> 2. | A·仁加萨米 2010 2 | *> 3. | A·德特默斯 2013 1 | *> 4. | A·德特默斯 2014 3 | *> 5. | A·查克拉 2014 3 | *> |------------------------------| *> 6. | A·米勒 2013 1 | *> 7. | A·维斯戈尔 2013 1 | *> 8. | A·维斯戈尔 2014 3 | *> 9. | A·马赛拉 2011 2 | *> 10. | B.A.彼得斯 2014 1 | *> +------------------------------+ save innovation_output, replace
如果同一个发明人在不同的年份(如 2005 年和 2006 年)出现在两个不同的上市公司(A 和 B),如果 2006 年后该发明人不再出现 在 A 企业,同时 2006 年前 B 企业也没有该发明人,则认为发明人在 A 和 B 之间发生了流动:
use patent_clean, clear drop if regexm (发明人, "不公开" ) | regexm (发明人, "不公布" )keep 发明人 年份 股票代码 市duplicates drop gsort 发明人 年份bysort 发明人 (年份): gen prev_firm = 股票代码[_n-1]bysort 发明人 (年份): gen next_firm = 股票代码[_n+1]bysort 发明人 (年份): gen prev_city = 市[_n-1]bysort 发明人 (年份): gen next_city = 市[_n+1]gen flow = 0replace flow = 1 if 股票代码 != prev_firm & 股票代码 != next_firm & !missing (prev_firm) & !missing (next_firm)save flow_data, replace
结合空气质量数据就可以构造流动方向了。Flow_up 表示发明人 流向空气质量较好的城市,此时 Flow_up 取值为 1,否则为 0:
import excel "1980年1月~2024年12月各城市地表PM2.5质量浓度(微克每立方米).xlsx" , firstrow clear gen 年份 = year (month)collapse (mean ) pm25 = 地表PM25质量浓度, by (市 年份)ren 市 merge_citykeep if 年份 >= 2010 & 年份 <= 2014save city_air_quality, replace use flow_data, clear rename prev_city merge_citymerge m :1 merge_city 年份 using "city_air_quality.dta" , keepusing(pm25) keep (match master)rename pm25 prev_pm25rename merge_city prev_citydrop _mrename 市 merge_citymerge m :1 merge_city 年份 using "city_air_quality.dta" , keepusing(pm25) keep (match master)rename pm25 curr_pm25rename merge_city 市drop _mgen flow_up = 0gen flow_down = 0replace flow_up = 1 if flow == 1 & curr_pm25 < prev_pm25 & !missing (curr_pm25, prev_pm25)replace flow_down = 1 if flow == 1 & curr_pm25 > prev_pm25 & !missing (curr_pm25, prev_pm25)replace flow_up = 0 if missing (flow_up)replace flow_down = 0 if missing (flow_down)save flow_direction, replace
再添加公司信息,方便下面的分公司汇总:
use patent_clean, clear merge m :1 发明人 年份 using innovation_output, keep (match master) nogen
分公司、年份统计流入流出人员数量。继续使用前面的 flow_data 或 final_data,这里可以根据需要分三种方法汇总:
基于流动数据直接统计;
根据发明人进行精确的流动识别;
按流动方向进一步细分。
方法一:基于流动数据直接统计
use flow_data, clear keep if flow == 1bysort 股票代码 年份: egen inflow_count = count (发明人)keep 股票代码 年份 inflow_countduplicates drop save inflow_by_firm, replace use flow_data, clear keep if flow == 1rename 股票代码 target_firmrename prev_firm 股票代码bysort 股票代码 年份: egen outflow_count = count (发明人)keep 股票代码 年份 outflow_countduplicates drop save outflow_by_firm, replace
方法二:使用更精确的流动识别
use flow_data, clear keep if flow == 1gen flow_year = 年份gen source_firm = prev_firmgen target_firm = 股票代码keep 发明人 flow_year source_firm target_firm 市 prev_citysave precise_flow_records, replace
方法三:按流动方向进一步细分
use flow_direction, clear keep if flow == 1bysort 股票代码 年份: egen inflow_total = count (发明人)bysort 股票代码 年份: egen inflow_up = sum (flow_up)bysort 股票代码 年份: egen inflow_down = sum (flow_down)keep 股票代码 年份 inflow_total inflow_up inflow_downduplicates drop save directional_inflow, replace use flow_direction, clear keep if flow == 1rename 股票代码 target_firmrename prev_firm 股票代码bysort 股票代码 年份: egen outflow_total = count (发明人)bysort 股票代码 年份: egen outflow_up = sum (flow_up)bysort 股票代码 年份: egen outflow_down = sum (flow_down)keep 股票代码 年份 outflow_total outflow_up outflow_downduplicates drop save directional_outflow, replace
最后还可以计算一些统计信息:
use firm_mobility_detailed, clear summarize inflow_countlocal avg_inflow = r (mean )summarize outflow_countlocal avg_outflow = r (mean )count if net_flow > 0local positive_net_ratio = r (N )/_N * 100display "企业流动统计摘要:" display "平均每年流入发明人数量:`avg_inflow'" display "平均每年流出发明人数量:`avg_outflow'" display "净流动为正的企业比例:`positive_net_ratio'%" collapse (mean ) avg_inflow = inflow_count avg_outflow = outflow_count (sum ) total_inflow = inflow_count total_outflow = outflow_count, by (年份) list
点击这里跳转到 RStata 短书平台获取附件:名师讲堂|使用 Stata 测算上市公司人力资本流动、创新产出及流动方向
评论