简介这份Python人口普查与各省人口数量变化可视化项目源码面向高校学生、数据分析初学者及需要完成期末大作业或课程设计的开发者帮助解决人口数据整理、趋势分析与图表呈现的完整实现问题。压缩包共10个文件约9.24MB包含py主程序、xlsx原始数据表、html交互图表、gif动态演示、mp4讲解视频及png配图等覆盖从数据读取到可视化输出的主要环节。项目围绕1953至2021年七次全国人口普查数据分析不同省份总人口变化并生成动态图表代码结构清晰、可直接运行。目前已有467人学习下载适合作为课程设计参考、数据分析练手或可视化案例拆解便于快速理解人口普查数据的处理流程与展示思路。1. 从一份期末大作业说起Python 人口普查可视化到底在做什么每年期末季总有一批人对着「人口普查数据分析与可视化」这个题目发愁。数据是公开的Python 环境也装好了但真到动手时才发现CSV 里省份名称对不上、年份列格式混乱、地图上色之后一片空白、pyecharts 渲染出来只有坐标轴没有图。这份 95 分以上的期末大作业源码核心其实就三件事——把第七次全国人口普查的省级数据清洗成规整的 DataFrame算出各省十年间的人口增减量和变化率再用地图和柱状图把「谁在流入、谁在流出」讲清楚。它适合两类人一类是正在找 Python 数据分析与可视化课程设计案例的学生需要一套能跑通、能改、能写进报告的完整流程另一类是想用真实数据练手 pandas 和 pyecharts 的入门者比起 Titanic 那种被做烂的数据集人口普查数据更贴近中国实际也更容易做出有说服力的可视化大屏效果。下面我按自己复现这类项目的顺序把数据获取、清洗、计算、可视化、避坑一条线讲透。2. 数据从哪来、怎么读普查数据的获取与 pandas 加载2.1 普查数据的公开来源与字段结构做人口普查可视化第一步不是写代码是搞清楚数据长什么样。第七次全国人口普查2020 年和第六次2010 年的省级汇总数据通常来自公开统计年鉴或统计公报常见格式是 Excel 或 CSV。一份典型的省级普查数据包含这些列省份名称、2020 年常住人口、2010 年常住人口、性别比、城镇人口占比、每十万人拥有大学文化程度人数等。做「各省人口数量变化情况」这个核心需求最少需要三列——省份、年份、人口数。如果拿到的是宽表每个年份一列需要先转成长表再做时间序列对比。我一般会先把原始文件读进来用head()和dtypes确认两件事省份列是不是字符串、人口列是不是数值。很多公开数据的人口列会带「万人」单位或者千分位逗号直接sum()会得到字符串拼接的结果这是新手最容易翻车的地方。2.2 用 pandas 读取并做首次体检import pandas as pd import numpy as np # 读取原始普查数据注意编码中文 CSV 常见 utf-8-sig 或 gbk df pd.read_csv(census_province.csv, encodingutf-8-sig) # 首次体检看形状、列名、前几行、数据类型 print(df.shape) print(df.columns.tolist()) print(df.head()) print(df.dtypes) # 如果人口列是带逗号的字符串先去掉逗号再转数值 # df[2020年人口] df[2020年人口].str.replace(,, ).astype(float)这段代码的逻辑很直接先确认数据规模再确认列名和类型。encodingutf-8-sig是为了处理带 BOM 的中文 CSV用gbk读出来乱码时换这个通常能解决。dtypes输出里如果人口列显示object而不是float64或int64说明里面有非数字字符必须清洗。参数上read_csv的encoding和sep是最常调的两个遇到制表符分隔的文件要把sep改成\t。2.3 省份名称标准化合并前必须做的一步省级数据做地图可视化时省份名称必须和地图组件里的名称完全一致。常见的不一致包括「内蒙古」vs「内蒙古自治区」、「广西」vs「广西壮族自治区」、「新疆」vs「新疆维吾尔自治区」。如果直接拿原始名称去匹配地图结果就是这些省份不上色地图看起来像缺了一块。# 省份名称标准化映射表 name_map { 内蒙古自治区: 内蒙古, 广西壮族自治区: 广西, 新疆维吾尔自治区: 新疆, 宁夏回族自治区: 宁夏, 西藏自治区: 西藏, 北京市: 北京, 上海市: 上海, 天津市: 天津, 重庆市: 重庆 } df[省份] df[省份].replace(name_map) # 检查是否有未匹配的省份 print(df[省份].unique())replace会按字典逐项替换没列出的名称保持不变。替换完一定要打印唯一值检查一遍确认没有漏网的「省」「市」「自治区」后缀。这一步看起来琐碎但它是后面地图能正常渲染的前提省不得。3. 算清楚变化人口增减量、变化率与排名3.1 十年人口变化的三个核心指标「各省人口数量变化情况」这个需求落到指标上就是三个数绝对增减量2020 年人口减 2010 年人口、变化率增减量除以 2010 年人口、以及按变化量排序的名次。绝对量告诉你谁增得多变化率告诉你谁增得快两者结合才能看出真实格局。比如广东绝对增量最大但西藏、新疆的变化率也很高单看一个指标会漏掉信息。# 计算增减量和变化率 df[增减量] df[2020年人口] - df[2010年人口] df[变化率] (df[增减量] / df[2010年人口] * 100).round(2) # 按增减量降序排名 df[增量排名] df[增减量].rank(ascendingFalse, methodmin).astype(int) # 分出人口增长省和人口减少省 grow df[df[增减量] 0].sort_values(增减量, ascendingFalse) shrink df[df[增减量] 0].sort_values(增减量) print(增长省份数量:, len(grow)) print(减少省份数量:, len(shrink)) print(grow[[省份, 增减量, 变化率]].head(10))round(2)保留两位小数避免报告里出现一长串浮点尾数。rank的methodmin表示并列时取最小名次适合做排名展示。把增长和减少分开存后面画图时可以分别用不同颜色视觉上更直观。3.2 用 groupby 做区域汇总除了省级对比很多报告还会要求按东部、中部、西部、东北四大区域汇总。如果数据里有区域列直接groupby就行如果没有需要自己建一个映射字典。# 区域映射按常见四大区域划分 region_map { 北京: 东部, 天津: 东部, 河北: 东部, 上海: 东部, 江苏: 东部, 浙江: 东部, 福建: 东部, 山东: 东部, 广东: 东部, 海南: 东部, 山西: 中部, 安徽: 中部, 江西: 中部, 河南: 中部, 湖北: 中部, 湖南: 中部, 内蒙古: 西部, 广西: 西部, 重庆: 西部, 四川: 西部, 贵州: 西部, 云南: 西部, 西藏: 西部, 陕西: 西部, 甘肃: 西部, 青海: 西部, 宁夏: 西部, 新疆: 西部, 辽宁: 东北, 吉林: 东北, 黑龙江: 东北 } df[区域] df[省份].map(region_map) # 按区域汇总人口变化 region_summary df.groupby(区域).agg( 总增减量(增减量, sum), 平均变化率(变化率, mean), 省份数(省份, count) ).round(2) print(region_summary)map会把字典里没有的键映射成 NaN所以映射完要检查df[区域].isna().sum()是否为 0。agg里可以同时做多种聚合sum看总量mean看平均水平count确认省份数量对不对。区域汇总的价值在于它能帮你在一张图里讲清楚「东北整体流出、东部整体流入」这种宏观结论比三十多个省份的柱状图更容易让读者抓住重点。3.3 把结果导出成可复用的中间文件清洗和计算做完后建议把结果存成新的 CSV后面画图直接读这个文件不用每次从头跑清洗逻辑。# 导出清洗后的结果供可视化脚本使用 df.to_csv(census_cleaned.csv, indexFalse, encodingutf-8-sig) # 同时导出增长和减少两个子集方便分别画图 grow.to_csv(census_grow.csv, indexFalse, encodingutf-8-sig) shrink.to_csv(census_shrink.csv, indexFalse, encodingutf-8-sig)indexFalse避免多出一列无意义的行号encodingutf-8-sig保证用 Excel 打开不乱码。这一步是工程习惯不是必须但它能让你的可视化脚本更干净调试时也不用反复等清洗过程。4. 可视化落地地图、柱状图与变化趋势图4.1 用 pyecharts 画省级人口变化地图地图是这类项目最出效果的部分。pyecharts 的 Map 组件可以直接吃省份名称和数值生成交互式地图。关键参数是maptypechina和is_map_symbol_showFalse去掉地图上的红点标记。from pyecharts import options as opts from pyecharts.charts import Map # 准备地图数据省份-增减量 map_data df[[省份, 增减量]].values.tolist() map_chart ( Map() .add( series_name人口增减量, data_pairmap_data, maptypechina, is_map_symbol_showFalse ) .set_global_opts( title_optsopts.TitleOpts(title各省人口增减量分布), visualmap_optsopts.VisualMapOpts( max_map_data and max(abs(v) for _, v in map_data), min_-max(abs(v) for _, v in map_data), is_piecewiseFalse, pos_left20% ) ) ) map_chart.render(population_map.html)visualmap_opts里的max_和min_控制颜色映射范围设成对称的正负值能让增长和减少的颜色对比更明显。is_piecewiseFalse表示连续渐变改成True会变成分段色块。render输出 HTML 文件浏览器打开就能交互。如果地图一片空白九成是省份名称没对上回到 2.3 节检查标准化映射。4.2 增长与减少省份的对比柱状图柱状图适合展示排名。把增长最多的十个省和减少最多的十个省放在一张图里用不同颜色区分读者一眼就能看出分化。from pyecharts.charts import Bar # 取增长前10和减少前10 top_grow grow.head(10) top_shrink shrink.head(10) bar ( Bar() .add_xaxis(top_grow[省份].tolist()) .add_yaxis(增长省份, top_grow[增减量].tolist(), color#5470c6) .add_xaxis(top_shrink[省份].tolist()) .add_yaxis(减少省份, top_shrink[增减量].tolist(), color#ee6666) .set_global_opts( title_optsopts.TitleOpts(title人口增长与减少省份TOP10), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate45)), yaxis_optsopts.AxisOpts(name增减量万人) ) ) bar.render(population_bar.html)rotate45让省份名称倾斜显示避免重叠。color参数分别给两组数据不同颜色视觉上自然区分。注意 pyecharts 的 Bar 在同一个实例里多次add_xaxis会覆盖如果增长和减少的省份列表不同更稳妥的做法是用两个独立的 Bar 或者改用Tab组件。我一般会先跑一遍看输出如果 x 轴只剩最后一组就改成分别渲染再手动拼。4.3 变化率排名与趋势对比除了绝对量变化率排名也值得单独画。用横向柱状图展示变化率最高的十个省能突出「基数小但增速快」的地区。from pyecharts.charts import Bar # 按变化率排序取前10 rate_top df.sort_values(变化率, ascendingFalse).head(10) bar_rate ( Bar() .add_xaxis(rate_top[省份].tolist()) .add_yaxis(变化率(%), rate_top[变化率].tolist()) .reversal_axis() # 横向柱状图 .set_global_opts( title_optsopts.TitleOpts(title人口变化率TOP10省份), xaxis_optsopts.AxisOpts(name变化率(%)) ) ) bar_rate.render(population_rate.html)reversal_axis()把柱状图转成横向省份名称在左侧数值在右侧适合名称较长的场景。变化率用百分比展示时记得在轴名称里标明单位避免读者误读。5. 避坑与排查这类项目最容易翻车的五个地方5.1 地图渲染空白只有标题没有色块现象render出来的 HTML 打开后地图区域一片灰白省份名称和数值都传了但就是不上色。原因省份名称和 pyecharts 内置地图的名称不匹配。最常见的是「内蒙古」写成「内蒙古自治区」、「新疆」写成「新疆维吾尔自治区」以及「北京」写成「北京市」。pyecharts 的 china 地图用的是简称。解决按 2.3 节的映射表统一替换替换后打印df[省份].unique()逐个核对。如果还有漏的去 pyecharts 文档里查 china 地图支持的名称列表以那个为准。5.2 人口列是字符串计算增减量时报 TypeError现象执行df[2020年人口] - df[2010年人口]时报TypeError: unsupported operand type(s) for -: str and str。原因原始 CSV 里人口数字带了千分位逗号如126,012,510或者单位后缀如12601万人pandas 读进来默认是 object 类型。解决先str.replace(,, )去掉逗号再用pd.to_numeric(..., errorscoerce)转数值。errorscoerce会把无法转换的值变成 NaN方便你定位是哪几行有问题。转换后检查df[2020年人口].isna().sum()如果有 NaN回去看原始数据对应行。5.3 变化率出现 inf 或极大值现象计算增减量 / 2010年人口时某些省份的变化率显示为inf或者几万。原因2010 年人口列里有 0 或空值除法产生了无穷大。也可能是数据里混入了汇总行如「全国」它的数值远大于省级数据。解决计算前先过滤掉 2010 年人口为 0 或 NaN 的行同时检查有没有「全国」「合计」这类汇总行混在省级数据里有的话用df df[df[省份] ! 全国]剔除。变化率算完后用df[变化率].describe()看分布超过合理范围比如 ±50%的要单独核查。5.4 pyecharts 图表在 Jupyter 里不显示现象在 Jupyter Notebook 里调用render()后没有输出或者只显示一行文字。原因pyecharts 默认render()输出 HTML 文件在 Notebook 里需要用render_notebook()或者把图表对象放在单元格最后一行。解决在 Jupyter 里改用chart.render_notebook()或者确认已安装pyecharts的 Notebook 扩展。如果是在 VS Code 的 Python 环境里跑直接render()生成 HTML 再用浏览器打开更稳。这也是为什么我建议把清洗和可视化分成两个脚本可视化脚本独立跑不依赖 Notebook 环境。5.5 中文显示成方块现象图表里的中文标题、轴标签显示为方框或乱码。原因matplotlib 默认字体不含中文pyecharts 生成的 HTML 如果浏览器字体正常一般没事但用 matplotlib 画图时必现。解决matplotlib 里设置plt.rcParams[font.sans-serif] [SimHei]和plt.rcParams[axes.unicode_minus] False。pyecharts 的 HTML 输出通常不需要额外设置如果乱码检查 HTML 的meta charset是不是 utf-8。用 pandas 导出 CSV 时统一用utf-8-sig避免 Excel 打开乱码。6. 进阶技巧把静态图变成可交互大屏以及验证数据可信度6.1 用 Page 组件拼装多图大屏单张地图或柱状图只能讲一个点期末大作业如果想拿高分通常需要把地图、柱状图、变化率排名拼成一个页面。pyecharts 的Page组件可以做到而且支持拖拽布局。from pyecharts.charts import Page page Page(layoutPage.DraggablePageLayout) page.add(map_chart, bar, bar_rate) page.render(census_dashboard.html)layoutPage.DraggablePageLayout允许在浏览器里拖动调整图表位置调好后点击「保存配置」再把生成的chart_config.json用Page.save_resize_html固化下来。这个流程我用了很多次比手写 HTML 布局省事得多。注意Page里的图表对象必须是已经add完数据的不能传空实例。6.2 用交叉验证确认数据没算错可视化做得再漂亮数据算错就是零分。我一般会做两个交叉验证一是用df[增减量].sum()看全国总增减量是否和公开的全国总数对得上省级加总应该接近全国总数差值是统计口径差异二是挑几个已知情况的省份手动核对比如广东应该大幅增长、东北三省应该减少。如果对不上回去查清洗步骤。# 交叉验证省级增减量加总 total_change df[增减量].sum() print(f省级增减量加总: {total_change:.0f} 万人) # 检查是否有异常值 print(df[df[变化率].abs() 50][[省份, 变化率]])abs() 50是筛出变化率绝对值超过 50% 的省份正常省级十年变化率很少超过这个数出现的话大概率是数据问题。这一步花不了几分钟但能帮你避免在答辩时被问「你这个数怎么和公布的不一样」的尴尬。6.3 一个我踩过的坑别在可视化脚本里重复清洗最早做这类项目时我把清洗、计算、画图全写在一个脚本里每次调图表参数都要等前面几十行跑完。后来改成三个文件clean.py负责读原始数据、清洗、导出census_cleaned.csvanalyze.py负责计算指标、导出结果visualize.py只读清洗后的 CSV 画图。这样调图表时秒出结果清洗逻辑改了也只跑一次。这个习惯看起来简单但它是把「能跑」变成「好调」的关键。希望帮到你。本文还有配套的精品资源点击获取
