1960-2024年中国执业医师数据趋势分析与可视化实践

发布时间:2026/10/2 3:30:07
1960-2024年中国执业医师数据趋势分析与可视化实践 1. 这个数据集到底装了什么1.1 一个字段拆解就能看懂的核心内容第一次拿到1960年-2024年中国执业(助理)医师数数据集这份文件时我其实没有急着画图而是先做了一件很枯燥但特别重要的事把表头和字段一个个看了个遍。这份数据集本质上就是一张长表或者宽表常见字段无非这么几个年份、地域全国或各省、指标名称执业医师、执业助理医师、两者合计、数值、单位以及可能的数据来源备注。千万别小看这些字段它们决定了你后面能做什么分析。比如只有年份合计两列你只能画一条总量趋势线但如果有执业医师和执业助理医师分列你就能进一步拆结构如果再带上省份维度那就能做区域差异、收敛性分析、甚至人口密度匹配。我见过的多数公开整理版数据集都会至少保留年份、执业医师数、执业助理医师数、合计数值这四个字段有的还会额外附上每千人口执业助理医师数这个字段是衡量医疗服务可及性的重要指标后面我会专门展开讲。这类数据集的直接用途说白了就是回答三个问题中国医生到底多了没有多到什么速度分布是均衡还是集中1960年到现在六十多年跨越了多个经济发展阶段医疗卫生体系也经历过好几轮结构性调整但从数据集的视角看最核心的分析对象始终是医师资源总量与结构的变化趋势。拿来做时间序列图、增长率计算、区域对比、甚至预测未来五年医师需求量都是顺手的事。1.2 64年跨度里最有价值的几个分析切口一份时间跨度这么长的数据最怕的就是只会对着最后一年的数字感慨现在医生真多。说真的64年数据能挖的点至少有这么几个第一是分段趋势。1960年代初到现在医师数的增长节奏不是均匀的。早期基数小增长缓慢中间某个阶段出现了明显加速近几年增速又趋于平稳。把整个曲线分成几段去看每一段的斜率变化背后都对应着卫生投入、培养规模、准入门槛的变化。我一般不建议直接对全序列做线性拟合因为拟合出来的一个斜率会把这几十年的阶段性差异全抹平信息损失太大。第二是结构变化。执业医师和执业助理医师虽然都挂在医师名下但两者的培养路径和执业权限差别很大。执业医师通常要经过更完整的医学院校教育和规范化培训而执业助理医师主要面向基层承担基础诊疗任务。这两者的比例变化其实反映了医疗队伍的整体素质结构和基层医疗的补充逻辑非常值得单独拉出来看。第三是相对密度。总量涨不代表医疗服务一定变好还要看人口盘子怎么变。1960年全国人口总量跟2024年完全不是一个量级所以把医师数除以人口数得到的每千人口医师数才是更能横向、纵向比较的指标。这个指标完成从低到高的跃迁过程才是这个数据集里最有故事感的一条线。如果能在分析里把这三个切口都照顾到这份数据就不只是一条向上的曲线而是一面能看出中国医疗卫生人力变迁的镜子。2. 数据口径为什么同一年不同渠道数字对不上2.1 执业医师与执业助理医师到底差在哪拿到数据之后第一个需要较真的就是执业助理医师这个括号里的词。很多人做分析时稀里糊涂把两列加起来当总数用但这两类人并不是完全同质化的。执业医师指的是通过国家医师资格考试、取得执业医师资格并注册在医疗机构执业的人员通常具备独立处方权能够独立开展诊疗活动。执业助理医师同样要考取资格但在执业范围和处方权限上受到更多限制必须在执业医师指导下工作主要分布在社区卫生服务机构、乡镇卫生院和村卫生室这些基层场景里。所以如果数据集里把这两类分列你千万不要只说一句总数变多了就完事而应该关注执业医师在合计中的占比。占比稳步上升说明医师队伍的整体素质在提升如果某些年份占比下降大概率不是退步而是基层助理医师扩招的阶段性结果。分析时两种解释方向都要考虑到不能一刀切。至于有些年份只提供卫生技术人员数或者医生数那就更要多留个心眼。不同历史阶段统计指标的边界并不完全一致。有的年份数据源用的是医师口径有的用的是医生口径后者可能包含中医、口腔、公共卫生等不同类别的执业人员。这些细节直接决定趋势图里那年是凸还是凹不查清楚就画图容易得出错误结论。2.2 统计年鉴和统计公报的口径差异做这类年份跨度很长的数据分析几乎绕不开一个尴尬2010年前后的数字在《中国卫生健康统计年鉴》和《全国卫生健康事业发展统计公报》里存在一定出入。年鉴里的数字一般更严谨是对上一年度卫生资源、服务利用、费用等数据进行系统核算后的结果发布周期也更晚。公报则偏向快报性质通常在次年发布强调初步统计结果。两者之间的差值来源可能包括统计时点不同、注册口径调整、行政区划变更后的回溯修订以及个别省份补报后对全国总量造成的修订。我的建议是一个数据集里尽量只锁定一个主数据源不要今天用年鉴、明天用公报。如果确实需要混用那就要在年份列旁边加一个数据来源标记列并且在图表里用不同的点形或者注释标出断点。否则你画出的趋势线上出现一个莫名其妙的台阶别人问起来你解释不清。2.3 缺失年份与数据缺失的处理思路1960年到2024年听起来是连续64年但实际上很多整理版数据集中间是有缺口的。我见过最典型的缺失情况有两种早期部分年份没找到原始统计资料个别年份因为统计制度调整只有卫生技术人员数、没有单独的执业医师数。处理缺失年份千万不要用Excel里的连接空单元格或者Python里直接dropna()前者会画出一条穿越多年的直线给你造成平稳增长的错觉后者会把数据切成几段。正确做法是分情况如果缺失年份较少且前后数字差异不大可以考虑线性插值如果缺失年份集中在某个长区间那就不插值直接把那段断开分段展示。另外数据文件里有时会有1970年-1974年数据暂缺之类的注释保留在你的清洗脚本注释和数据集说明文档里比直接删掉这些信息负责任得多。做长周期数据研究最重要的不是把数据补满而是清清楚楚知道哪里缺了、为什么缺、补了什么进去。3. 上手实操从原始表到第一张趋势图3.1 数据准备与清洗的几个关键步骤拿到原始CSV或Excel文件第一步永远是把文件用文本编辑器或者pandas.read_csv打开先看前五行。我经常遇到的情况是文件第一行是标题说明1960-2024年全国执业助理医师数第二行才是真正的表头再往下才是数据。直接read_csv默认第一行当表头数据就会整体错位。清洗时我按这个顺序操作统一表头命名中英文都用比如year、doctor_total、doctor_licensed、doctor_assistant方便后续写代码处理千分位逗号很多从网页复制出来的数字是1,234,567这种格式需要先转成数值型缺失年份标记为NaN但不主动删除除非缺失比例高到没法用检查重复行尤其当数据是用多个Excel sheet合并出来的经常出现年末和年初各被录入一次的情况。这一步做完你会得到一张干净的、可分析的DataFrame。不要小看这半小时的活它决定了后续所有分析是否可信。3.2 用Python快速画出1960-2024年趋势图画趋势图我个人最常用的是Matplotlib加Seaborn组合简单直接出图速度快。下面给一段我实际用的模板数据列名以我清洗后的字段为例import pandas as pd import matplotlib.pyplot as plt import seaborn as sns df pd.read_csv(doctor_data_clean.csv) plt.figure(figsize(12, 6)) sns.set_style(whitegrid) plt.plot(df[year], df[doctor_total], markero, markersize4, linewidth2, label执业(助理)医师合计) plt.plot(df[year], df[doctor_licensed], markers, markersize3, linewidth1.5, label执业医师) plt.plot(df[year], df[doctor_assistant], marker^, markersize3, linewidth1.5, label执业助理医师) plt.title(1960-2024年中国执业(助理)医师数变化趋势, fontsize14) plt.xlabel(年份) plt.ylabel(人数) plt.legend() plt.tight_layout() plt.show()你大概率画出来会看到一条整体向上的曲线但如果仅仅向上就结束那这份数据等于白拿。我会继续用numpy分段计算年均增长率确定哪一段斜率最陡哪一段相对平缓。import numpy as np segments [(1960, 1980), (1980, 2000), (2000, 2024)] for start, end in segments: y_start df.loc[df[year] start, doctor_total].values[0] y_end df.loc[df[year] end, doctor_total].values[0] cagr (y_end / y_start) ** (1 / (end - start)) - 1 print(f{start}-{end} 年复合增长率: {cagr:.2%})这里有个操作细节year列要确保是整数索引找对应年份时最好先set_index(year)否则容易出现索引错位。分段区间的选择不要完全拍脑袋可以先把整条曲线的转折点标出来再根据转折点切段这样出来的结论更有说服力。3.3 用ECharts做交互式仪表盘静态图适合写报告动态交互图适合做展示。我经常用pyecharts把同样数据做成一个可缩放的时间序列图鼠标悬停能看具体数值拖拽缩放能锁定1960年代初期那段相对平缓的区域。from pyecharts.charts import Line from pyecharts import options as opts line ( Line() .add_xaxis(df[year].astype(str).tolist()) .add_yaxis(执业(助理)医师合计, df[doctor_total].tolist(), is_smoothTrue) .set_global_opts( title_optsopts.TitleOpts(title1960-2024年医师数量趋势), tooltip_optsopts.TooltipOpts(triggeraxis), datazoom_opts[opts.DataZoomOpts(range_start0, range_end100)], ) ) line.render(doctor_trend.html)生成的HTML文件可以直接用浏览器打开也可以嵌入到网页里。实际做演示时这个交互图比静态图更能让人直观感受早期平缓、后期陡增的节奏差异。前端能力强的也可以直接写原生ECharts配置数据格式逻辑完全一样。4. 从数字里能读出什么三个必做的分析维度4.1 总量增长背后的阶段节奏把64年的数据按阶段拆开之后能看到一个很有意思的事实总量增长并不是匀速的而是有明显的加速期。以我处理过的类似数据来看大致可以分三个阶段早期基数小每年增加的数量非常有限后来随着医学院校恢复招生和培养规模扩大年增量开始显著提升曲线斜率明显变陡近几年增量依然可观但增速已经趋于稳定。当然具体年份节点以你手头实际数据为准我不在这里拍死数字关键是分析方法。我在分析时常用滚动五年增量这个指标对每一年的总数减去五年前的总数得到每五年的净增量。这样可以过滤掉单年波动看清长期动能。操作上就是df[diff_5y] df[doctor_total].diff(5)然后画一条柱状图哪几年是增量高峰一下子就清楚了。这个方法同样适合分析执业医师、执业助理医师的分项增量。4.2 每千人口医师数比总量更值得看总量会受人口基数影响所以做横向国际比较或者纵向长期比较时我更习惯看相对指标。每千人口执业助理医师数的计算公式很简单df[doctor_per_1000] df[doctor_total] / df[population] * 1000这里需要你另外准备一份历年人口数数据常见来源是全国人口普查资料和统计年鉴。如果数据集里已经给了这个字段那就省事了。有了每千人口医师数之后很多分析都能展开。比如可以画一条线与部分发达国家做对比或者做城乡结构下的分区对比。这个指标的长期上升趋势比总量增长更能反映医疗服务可及性的改善。做这个指标时要注意人口数的统计口径有的年份是常住人口有的是户籍人口混用会导致比值失真。4.3 结构比执业医师与助理医师的占比变化第三个必做维度是结构比。我用下面这行代码计算执业医师占合计的比重df[licensed_share] df[doctor_licensed] / df[doctor_total]这个比重如果总体呈现上升趋势说明执业医师在医师队伍里的主导地位在增强如果某段时期略有下降则通常与助理医师快速补充到基层有关。不要简单解读为素质下降而是要从基层医疗需求的角度去理解。我个人通常会把结构比趋势图和总量趋势图放在同一个仪表盘里左边看总盘子右边看结构这样汇报时更有说服力。你可以加一个副标题医师资源不仅总量在扩结构也在优化。没有这张结构图好多结论都会显得单薄。5. 常见坑与排查实录5.1 五年一跳跃的假象缺失年份别直接连线我第一次拿这份数据画图时因为没有提前检查缺失值直接plt.plot(year, total)结果在1970年代初出现了一段陡直上升非常扎眼。后来一查那段因为原始统计资料缺失数据文件里直接跳过了几个年份而Matplotlib默认会把缺失值两侧的点连成直线。解决这个问题有两个办法一个是把缺失年份置为NaNMatplotlib遇到NaN会自动断开线段另一个是干脆只对实际有数据的年份做散点加线。我倾向于后一种因为它保留了哪些年份确实没有数据这个信息别人看图时会自然注意到不连续段。5.2 口径切换导致的断点还有一次我遇到的情况是2002年前后突然有一个台阶式下降当时差点误判成医师数负增长。查了数据源注释才发现2002年后统计口径从卫生技术人员中的医生调整成了执业助理医师把一部分没有注册资格的人员踢出了统计范围。这类口径切换造成的断点在长周期数据里非常常见。最好是在图里加一条垂直参考线并用注释标注此处统计口径调整比如plt.axvline(x2002, colorgray, linestyle--, alpha0.7) plt.text(2002, plt.ylim()[0], 口径调整, rotation90)不要试图去修复这个断点更不要把它强行抹平。真实数据有断点很正常分析报告里写清楚原因比画一条光鲜但虚假的曲线重要得多。5.3 数据文件合并时容易翻车的编码问题做多源数据合并时我踩过最多次的坑是编码。CSV文件有的用utf-8有的用gbk在Windows上尤其容易乱码。代码里统一加encodingutf-8-sig能解决大多数Excel导出文件的BOM问题。另外年份列有时会被读成带逗号的字符串比如2,024pd.to_numeric会直接报错。稳妥做法是先把所有数字列里的逗号去掉再转数值df[year] df[year].astype(str).str.replace(,, ).astype(int)还有合并时注意年份类型一致性一个DataFrame里年份是int另一个是str直接merge会匹配不上。每次合并前统一检查dtypes能帮你省掉很多莫名其妙的行数丢失。5.4 数据来源标注一定要保留到最后一版这份数据我会建议你保留一个单独的说明列哪怕是整理版也一定不要把原始来源备注删除。我吃过这个亏当时图省事把来源列删了结果几个月后再看数据完全想不起来某几个年份为什么数值异常只能重新回去翻原始文件。做长周期数据分析元信息就是你的命根子。数据来源、统计口径、缺失情况、修订记录每一项都值得留档。这些信息不直接出现在图表里但它们保证了你的分析可以复现、可以被信任。6. 还能怎么用这个数据集的衍生价值6.1 与人口数据、床位数据关联分析医师数据单独看是一条线但放进更大的卫生健康资源框架里价值会成倍放大。比如把执业助理医师数、医疗机构床位数、人口数三个数据放一起可以计算出每千人医师数、每千人床位数、医师人均负担床位数等派生指标。在IPython里简单的merge就能完成关联population pd.read_csv(population_data.csv) beds pd.read_csv(hospital_beds_data.csv) merged df.merge(population, onyear, howleft).merge(beds, onyear, howleft)有了合并后的宽表你可以进一步画散点图看医师数与床位数的协同增长关系也可以算医疗资源协调指数。在调研报告里这种交叉维度分析通常比单列指标更受关注。6.2 做预测模型的前期准备另一个我很推荐的应用方向是用这部分历史数据做未来医师资源需求的简单预测。不要一上来就上LSTM先用线性模型或者指数平滑把历史增长趋势拟合出来看看未来五年的医师数大概落在什么区间。from sklearn.linear_model import LinearRegression X df[[year]].values y df[doctor_total].values model LinearRegression() model.fit(X, y) future_years np.array([2025, 2026, 2027, 2028, 2029]).reshape(-1, 1) pred model.predict(future_years)当然这种预测只算基线情景忽略了医学院校扩招、执业资格考试通过率、退休潮等因素所以使用时要注明局限。但作为决策参考已经足够有价值。把预测值和历史真实值画在一张图上加上置信区间展示效果会很好。6.3 作为数据可视化教学的极佳素材最后说一个更轻的用途这份数据集非常适合拿来教数据可视化。时间跨度长、趋势明显、有缺失值、有口径调整点、有多个分组指标几乎涵盖了时间序列可视化里能遇到的所有典型问题。我用它带过入门数据分析的同学练习内容包括数据清洗、缺失值处理、趋势图绘制、双轴图、分组柱状图、仪表盘搭建。因为数据本身是真实公开数据学员分析起来比用模拟数据有动力得多。你也可以把最终图表整理成一份PDF报告直接给非技术背景的同学或者业务方看解释医疗资源的历史演变。我个人在实际操作中的体会是这类长周期公开数据最怕的不是数字不准而是使用者不去追问数字背后的口径和结构。把执业助理医师这个括号里的差异弄清楚把缺失年份和口径断点老老实实在图里标注出来这张曲线才算真正能站得住脚。后续如果再往上加人口、床位、教育培养、地区分布等维度一份数据集就能撑起一整个系列的医疗卫生资源分析价值远远超出那一列数字本身。