数据分析项目报告B站风格世界人口动态排序轮播图1. 项目概述1.1 项目背景动态排序轮播图Bar Chart Race是数据可视化领域的经典形式尤其在 B 站等视频平台广受欢迎。本项目旨在通过 Python 数据分析与可视化技术完整复刻高质量的世界人口年度动态排序轮播图展示 1960 年至 2024 年间世界各国人口总数的历史变迁。1.2 项目目标数据纯净完整剔除大洲、收入组、地区汇总等非国家数据仅保留 195 个真实主权国家。动态展示图表自动按年份轮播每年严格按人口总数降序排列人口越多的国家越靠图表上方。全交互体验支持悬浮显示具体人口数值、暂停/播放控制、手动切换年份。商业级美化采用深色背景、动态配色、圆角数值标签及丝滑轮播节奏达到 B 站专业级可视化标准。2. 技术栈与运行环境编程语言Python 3.x数据处理 pandas (用于数据读取、清洗、宽长表转换)数据可视化 pyecharts (Bar 柱状图, Timeline 时间线轮播组件)前端配置 JsCode (用于实现动态颜色映射), CDN 镜像配置 (解决国内网络加载空白问题)\# 1. 导入核心工具importpandasaspd# 数据处理库frompyecharts.chartsimportBar,Timeline# 柱状图、时间线轮播组件frompyechartsimportoptionsasopts# 配置项工具frompyecharts.globalsimportThemeType,CurrentConfig# 内置主题、CDN配置frompyecharts.commons.utilsimportJsCode# 动态颜色JS工具# 修复CDN解决HTML空白问题国内网络必加CurrentConfig.ONLINE_HOSThttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/3. 数据获取与探查 (阶段 1)3.1 数据加载项目读取本地 CSV 文件 世界人口数据-中文版1960-2024.csv 由于包含中文字符指定编码为gbk 。# 2. 读取中文版人口数据集dfpd.read_csv(E:\jupeyter code\VS code\data\世界人口数据-中文版1960-2024.csv,encodinggbk)df.head()Country NameCountry CodeIndicator NameIndicator Code196019611962196319641965...20162017201820192020202120222023202420250阿鲁巴ABW人口总数SP.POP.TOTL54922.055578.056320.057002.057619.058190.0...108727.0108735.0108908.0109203.0108587.0107700.0107310.0107359.0107995.0NaN1NaNAFE人口总数SP.POP.TOTL130075728.0133534923.0137171659.0140945536.0144904094.0149033472.0...623369401.0640058741.0657801085.0675950189.0694446100.0713090928.0731821393.0750491370.0769280888.0NaN2阿富汗AFG人口总数SP.POP.TOTL9035043.09214083.09404406.09604487.09814318.010036008.0...34700612.035688935.036743039.037856121.039068979.040000412.040578842.041454761.042647492.0NaN3NaNAFW人口总数SP.POP.TOTL97630925.099706674.0101854756.0104089175.0106388440.0108772632.0...429454743.0440882906.0452195915.0463365429.0474569351.0485920997.0497387180.0509398589.0521764076.0NaN4安哥拉AGO人口总数SP.POP.TOTL5231654.05301583.05354310.05408320.05464187.05521981.0...29183070.030234839.031297155.032375632.033451132.034532429.035635029.036749906.037885849.0NaN5 rows × 70 columns3.2 数据结构探查通过 df.info() 探查数据集基础结构如下样本量266 行包含国家及各类汇总区域。特征量70 列。属性列 (4列) Country Name (国家名称), Country Code (国家代码), Indicator Name(指标名称), Indicator Code (指标代码)。时间序列列 (66列) 1960 至 2025 年的数值列。其中 2025 年数据全为 NaN 缺失有效数据区间为 1960-2024 年。df.info()class pandas.core.frame.DataFrame RangeIndex: 266 entries, 0 to 265 Data columns (total 70 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Country Name 264 non-null object 1 Country Code 266 non-null object 2 Indicator Name 266 non-null object 3 Indicator Code 266 non-null object 4 1960 264 non-null float64 5 1961 264 non-null float64 6 1962 264 non-null float64 7 1963 264 non-null float64 8 1964 264 non-null float64 9 1965 264 non-null float64 10 1966 264 non-null float64 11 1967 264 non-null float64 12 1968 264 non-null float64 13 1969 264 non-null float64 14 1970 264 non-null float64 15 1971 264 non-null float64 16 1972 264 non-null float64 17 1973 264 non-null float64 18 1974 264 non-null float64 19 1975 264 non-null float64 20 1976 264 non-null float64 21 1977 264 non-null float64 22 1978 264 non-null float64 23 1979 264 non-null float64 24 1980 264 non-null float64 25 1981 264 non-null float64 26 1982 264 non-null float64 27 1983 264 non-null float64 28 1984 264 non-null float64 29 1985 264 non-null float64 30 1986 264 non-null float64 31 1987 264 non-null float64 32 1988 264 non-null float64 33 1989 264 non-null float64 34 1990 265 non-null float64 35 1991 265 non-null float64 36 1992 265 non-null float64 37 1993 265 non-null float64 38 1994 265 non-null float64 39 1995 265 non-null float64 40 1996 265 non-null float64 41 1997 265 non-null float64 42 1998 265 non-null float64 43 1999 265 non-null float64 44 2000 265 non-null float64 45 2001 265 non-null float64 46 2002 265 non-null float64 47 2003 265 non-null float64 48 2004 265 non-null float64 49 2005 265 non-null float64 50 2006 265 non-null float64 51 2007 265 non-null float64 52 2008 265 non-null float64 53 2009 265 non-null float64 54 2010 265 non-null float64 55 2011 265 non-null float64 56 2012 265 non-null float64 57 2013 265 non-null float64 58 2014 265 non-null float64 59 2015 265 non-null float64 60 2016 265 non-null float64 61 2017 265 non-null float64 62 2018 265 non-null float64 63 2019 265 non-null float64 64 2020 265 non-null float64 65 2021 265 non-null float64 66 2022 265 non-null float64 67 2023 265 non-null float64 68 2024 265 non-null float64 69 2025 0 non-null float64 dtypes: float64(66), object(4) memory usage: 145.6 KB4. 数据清洗与预处理 (阶段 2)原始数据为“宽格式”一行一个国家多年份平铺为多列且包含大量非主权国家的汇总数据无法直接用于绘图。预处理分为以下核心步骤4.1 提取目标列通过列表推导式筛选出所有列名为纯数字的列作为 year_cols 保留 4 个属性列作为 attr_cols 。year_cols[iforiindf.columnsifi.isdigit()]#通过递推式筛选出所有列名为纯数字的列作为 year_cols#import numpy as np# year_colsnp.arange(1960,2026)attr_cols[Country Name,Country Code,Indicator Name,Indicator Code]#保留 4 个属性列作为 attr_cols4.2 剔除无效与汇总数据 (核心清洗)删除空值直接删除 Country Name 为 NaN 的行此类行通常为 AFE/AFW 等大洲代码汇总。dfdf.dropna(subset[Country Name])黑名单过滤定义包含 40 项的 black_list 涵盖全球及大洲汇总如“世界”、“东亚与太平洋地区”、“撒哈拉以南非洲地区”等。收入等级分类如“高收入国家”、“中等收入国家”等。非主权地区/领地如“阿鲁巴”、“中国香港特别行政区”、“波多黎各”等。使用 ~df[“Country Name”].isin(black_list) 进行反向过滤最终精准保留 195 个 真实主权国家。# 2.黑名单剔除大洲、收入等级、发展区域汇总black_list[# 全球 大洲汇总世界,北美,东亚与太平洋地区,欧洲与中亚地区,东亚与太平洋地区不包括高收入,欧洲与中亚地区不包括高收入,拉丁美洲与加勒比海地区,拉丁美洲与加勒比海地区不包括高收入,中东、北非、阿富汗与巴基斯坦,中东与北非地区不包括高收入,撒哈拉以南非洲地区,撒哈拉以南非洲地区不包括高收入,南亚,小国,加勒比小国,太平洋岛国,其他小国,未分类国家,阿拉伯联盟国家,欧洲联盟,欧洲货币联盟,经合组织成员,重债穷国 (HIPC),脆弱和受衝突影響的情況下,# 收入等级高收入国家,低收入国家,中等收入国家,中高等收入国家,中低等收入国家,中低收入国家,# 人口红利阶段早人口紅利,後期人口紅利,預人口紅利,人口紅利之後,# 发展水平分类最不发达国家联合国分类,# 世界银行分组IBRD与IDA,只有IBRD,只有IDA,IDA總,IDA混合,东亚与太平洋地区 (IBRD与IDA),欧洲与中亚地区 (IBRD与IDA),拉丁美洲与加勒比海地区 (IBRD与IDA),中东与北非地区 (IBRD与IDA),南亚 (IBRD与IDA),撒哈拉以南非洲地区 (IBRD与IDA),# 地区/领地/非主权地区阿鲁巴,美属萨摩亚,百慕大,库拉索,开曼群岛,海峡群岛,法罗群岛,直布罗陀,格陵兰,关岛,中国香港特别行政区,中国澳门特别行政区,圣马丁法属,圣马丁(荷属),北马里亚纳群岛,新喀里多尼亚,波多黎各,约旦河西岸和加沙,法属波利尼西亚,特克斯科斯群岛,英屬維爾京群島,美属维京群岛,科索沃]dfdf[~df[Country Name].isin(black_list)].reset_index(dropTrue)print(过滤后剩余国家数量,df[Country Name].nunique())过滤后剩余国家数量 1954.3 宽表转长表 (Reshape)使用 pd.melt() 函数将数据结构转换为适合时序分析的“长格式”id_vars : 保持不变的属性列。value_vars : 需要展开的年份列。生成新列 Year (年份) 和 Population (人口数值)# melt宽转长df_longpd.melt(df,id_varsattr_cols,# 不变字段国家名称、编码等value_varsyear_cols,# 需要拆开的年份列var_nameYear,# 拆分成成新列的列名年份value_namePopulation# 对应值的新列名人口)df_long.head()Country NameCountry CodeIndicator NameIndicator CodeYearPopulation0阿富汗AFG人口总数SP.POP.TOTL19609035043.01安哥拉AGO人口总数SP.POP.TOTL19605231654.02阿尔巴尼亚ALB人口总数SP.POP.TOTL19601608800.03安道尔共和国AND人口总数SP.POP.TOTL19609510.04阿拉伯联合酋长国ARE人口总数SP.POP.TOTL1960131334.04.4 数据类型转换与最终清理将 Year 列转换为 int 类型。将 Population 列转换为 numeric 类型并使用 dropna 剔除转换后产生的空值如 2025 年的 NaN 数据。最终得到包含 12,675 条有效记录的干净数据集仅保留 Country Name , Year , Population 三列。df_cleandf_long[[Country Name,Year,Population]]# 仅保留国家名称、年份、人口列df_clean[Year]df_clean[Year].astype(int)# 将年份列转换为整数类型df_clean[Population]pd.to_numeric(df_clean[Population])# 将人口列转换为数值类型df_clean.dropna(inplaceTrue)# 剔除包含 NaN 的行df_clean.head()C:\Users\na\AppData\Local\Temp\ipykernel_23984\3147925960.py:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df_clean[Year]df_clean[Year].astype(int) # 将年份列转换为整数类型 C:\Users\na\AppData\Local\Temp\ipykernel_23984\3147925960.py:3: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df_clean[Population]pd.to_numeric(df_clean[Population]) # 将人口列转换为数值类型 C:\Users\na\AppData\Local\Temp\ipykernel_23984\3147925960.py:4: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df_clean.dropna(inplaceTrue) # 剔除包含 NaN 的行Country NameYearPopulation0阿富汗19609035043.01安哥拉19605231654.02阿尔巴尼亚19601608800.03安道尔共和国19609510.04阿拉伯联合酋长国1960131334.05. 数据可视化与迭代优化 (阶段 4 - 6)5.1 单年份横向柱状图测试 (阶段 4)以 1990 年为例进行原型测试筛选 1990 年数据按人口降序排列并取前 20 名。使用 pyecharts.Bar 绘制启用 reversal_axis() 将柱状图横向放置。配置深色主题 ( ThemeType.DARK )确保标签显示在柱子右侧 ( position“right” )验证基础渲染逻辑无误。# 数据准备test_dfdf_clean[df_clean[Year]1990]test_dftest_df.sort_values(byPopulation,ascendingFalse).head(20)#按人口排序,取前20名#绘制柱状图bar_test(Bar(init_optsopts.InitOpts(themeThemeType.DARK))#设置主题为深色.add_xaxis(test_df[Country Name].tolist())#国家名字作为横轴.add_yaxis(人口,test_df[Population].tolist())#人口作为纵轴.reversal_axis()#将柱状图横向放置.set_global_opts(title_optsopts.TitleOpts(title1990年世界人口排名,pos_leftcenter),#设置标题legend_optsopts.LegendOpts(is_showFalse),#隐藏图例框).set_series_opts(label_optsopts.LabelOpts(positionright))#设置标签显示在柱子右侧)#bar_test.render(bar_test.html) #将图表渲染为html文件,在浏览器中查看bar_test.render_notebook()div id504c2a09894c44e99f38a924fa62473d stylewidth:900px; height:500px;/div5.2 Timeline 轮播基础版 (阶段 5)遍历清洗后的所有唯一 Year 。每年动态生成一个 Bar 实例并通过 Timeline.add() 方法将其按年份追加到时间轴中。配置基础轮播参数 is_auto_playTrue , play_interval700 (毫秒), is_loop_playTrue 。导出为 人口轮播_中文_基础版.html 验证时序动画连贯性。year_listdf_clean[Year].unique().tolist()#获得年份列表#初始化时间线timelineTimeline(init_optsopts.InitOpts(width1500px,height820px,themeThemeType.DARK,bg_color#0a0a0a))#遍历年份列表,每个年份画一个柱状图添加到时间线中foryearinyear_list:# 数据准备data_dfdf_clean[df_clean[Year]year]data_dfdata_df.sort_values(byPopulation,ascendingFalse).head(20)#按人口排序,取前20名data_dfdata_df.sort_values(byPopulation,ascendingTrue)#再次升序排序保证大的在上countrydata_df[Country Name].tolist()#国家名字列表populationdata_df[Population].tolist()#人口列表#绘制柱状图bar(Bar(init_optsopts.InitOpts(themeThemeType.DARK))#设置主题为深色.add_xaxis(country)#国家名字作为横轴.add_yaxis(人口,population)#人口作为纵轴.reversal_axis()#将柱状图横向放置.set_global_opts(title_optsopts.TitleOpts(titlef{year}年世界人口排名,pos_leftcenter),#设置标题legend_optsopts.LegendOpts(is_showFalse),#隐藏图例框).set_series_opts(label_optsopts.LabelOpts(positionright))#设置标签显示在柱子右侧)#将柱状图添加到时间线中timeline.add(bar,str(year))#配置基础轮播参数:自动播放、播放间隔600毫秒、循环播放timeline.add_schema(is_auto_playTrue,play_interval600,is_loop_playTrue)timeline.render(基础轮播图.html)timeline.render_notebook()div idadc22ca8bf5b4439a9e433e9d8ff3b26 stylewidth:1500px; height:820px;/div
世界人口排序轮播图
数据分析项目报告B站风格世界人口动态排序轮播图1. 项目概述1.1 项目背景动态排序轮播图Bar Chart Race是数据可视化领域的经典形式尤其在 B 站等视频平台广受欢迎。本项目旨在通过 Python 数据分析与可视化技术完整复刻高质量的世界人口年度动态排序轮播图展示 1960 年至 2024 年间世界各国人口总数的历史变迁。1.2 项目目标数据纯净完整剔除大洲、收入组、地区汇总等非国家数据仅保留 195 个真实主权国家。动态展示图表自动按年份轮播每年严格按人口总数降序排列人口越多的国家越靠图表上方。全交互体验支持悬浮显示具体人口数值、暂停/播放控制、手动切换年份。商业级美化采用深色背景、动态配色、圆角数值标签及丝滑轮播节奏达到 B 站专业级可视化标准。2. 技术栈与运行环境编程语言Python 3.x数据处理 pandas (用于数据读取、清洗、宽长表转换)数据可视化 pyecharts (Bar 柱状图, Timeline 时间线轮播组件)前端配置 JsCode (用于实现动态颜色映射), CDN 镜像配置 (解决国内网络加载空白问题)\# 1. 导入核心工具importpandasaspd# 数据处理库frompyecharts.chartsimportBar,Timeline# 柱状图、时间线轮播组件frompyechartsimportoptionsasopts# 配置项工具frompyecharts.globalsimportThemeType,CurrentConfig# 内置主题、CDN配置frompyecharts.commons.utilsimportJsCode# 动态颜色JS工具# 修复CDN解决HTML空白问题国内网络必加CurrentConfig.ONLINE_HOSThttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/3. 数据获取与探查 (阶段 1)3.1 数据加载项目读取本地 CSV 文件 世界人口数据-中文版1960-2024.csv 由于包含中文字符指定编码为gbk 。# 2. 读取中文版人口数据集dfpd.read_csv(E:\jupeyter code\VS code\data\世界人口数据-中文版1960-2024.csv,encodinggbk)df.head()Country NameCountry CodeIndicator NameIndicator Code196019611962196319641965...20162017201820192020202120222023202420250阿鲁巴ABW人口总数SP.POP.TOTL54922.055578.056320.057002.057619.058190.0...108727.0108735.0108908.0109203.0108587.0107700.0107310.0107359.0107995.0NaN1NaNAFE人口总数SP.POP.TOTL130075728.0133534923.0137171659.0140945536.0144904094.0149033472.0...623369401.0640058741.0657801085.0675950189.0694446100.0713090928.0731821393.0750491370.0769280888.0NaN2阿富汗AFG人口总数SP.POP.TOTL9035043.09214083.09404406.09604487.09814318.010036008.0...34700612.035688935.036743039.037856121.039068979.040000412.040578842.041454761.042647492.0NaN3NaNAFW人口总数SP.POP.TOTL97630925.099706674.0101854756.0104089175.0106388440.0108772632.0...429454743.0440882906.0452195915.0463365429.0474569351.0485920997.0497387180.0509398589.0521764076.0NaN4安哥拉AGO人口总数SP.POP.TOTL5231654.05301583.05354310.05408320.05464187.05521981.0...29183070.030234839.031297155.032375632.033451132.034532429.035635029.036749906.037885849.0NaN5 rows × 70 columns3.2 数据结构探查通过 df.info() 探查数据集基础结构如下样本量266 行包含国家及各类汇总区域。特征量70 列。属性列 (4列) Country Name (国家名称), Country Code (国家代码), Indicator Name(指标名称), Indicator Code (指标代码)。时间序列列 (66列) 1960 至 2025 年的数值列。其中 2025 年数据全为 NaN 缺失有效数据区间为 1960-2024 年。df.info()class pandas.core.frame.DataFrame RangeIndex: 266 entries, 0 to 265 Data columns (total 70 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Country Name 264 non-null object 1 Country Code 266 non-null object 2 Indicator Name 266 non-null object 3 Indicator Code 266 non-null object 4 1960 264 non-null float64 5 1961 264 non-null float64 6 1962 264 non-null float64 7 1963 264 non-null float64 8 1964 264 non-null float64 9 1965 264 non-null float64 10 1966 264 non-null float64 11 1967 264 non-null float64 12 1968 264 non-null float64 13 1969 264 non-null float64 14 1970 264 non-null float64 15 1971 264 non-null float64 16 1972 264 non-null float64 17 1973 264 non-null float64 18 1974 264 non-null float64 19 1975 264 non-null float64 20 1976 264 non-null float64 21 1977 264 non-null float64 22 1978 264 non-null float64 23 1979 264 non-null float64 24 1980 264 non-null float64 25 1981 264 non-null float64 26 1982 264 non-null float64 27 1983 264 non-null float64 28 1984 264 non-null float64 29 1985 264 non-null float64 30 1986 264 non-null float64 31 1987 264 non-null float64 32 1988 264 non-null float64 33 1989 264 non-null float64 34 1990 265 non-null float64 35 1991 265 non-null float64 36 1992 265 non-null float64 37 1993 265 non-null float64 38 1994 265 non-null float64 39 1995 265 non-null float64 40 1996 265 non-null float64 41 1997 265 non-null float64 42 1998 265 non-null float64 43 1999 265 non-null float64 44 2000 265 non-null float64 45 2001 265 non-null float64 46 2002 265 non-null float64 47 2003 265 non-null float64 48 2004 265 non-null float64 49 2005 265 non-null float64 50 2006 265 non-null float64 51 2007 265 non-null float64 52 2008 265 non-null float64 53 2009 265 non-null float64 54 2010 265 non-null float64 55 2011 265 non-null float64 56 2012 265 non-null float64 57 2013 265 non-null float64 58 2014 265 non-null float64 59 2015 265 non-null float64 60 2016 265 non-null float64 61 2017 265 non-null float64 62 2018 265 non-null float64 63 2019 265 non-null float64 64 2020 265 non-null float64 65 2021 265 non-null float64 66 2022 265 non-null float64 67 2023 265 non-null float64 68 2024 265 non-null float64 69 2025 0 non-null float64 dtypes: float64(66), object(4) memory usage: 145.6 KB4. 数据清洗与预处理 (阶段 2)原始数据为“宽格式”一行一个国家多年份平铺为多列且包含大量非主权国家的汇总数据无法直接用于绘图。预处理分为以下核心步骤4.1 提取目标列通过列表推导式筛选出所有列名为纯数字的列作为 year_cols 保留 4 个属性列作为 attr_cols 。year_cols[iforiindf.columnsifi.isdigit()]#通过递推式筛选出所有列名为纯数字的列作为 year_cols#import numpy as np# year_colsnp.arange(1960,2026)attr_cols[Country Name,Country Code,Indicator Name,Indicator Code]#保留 4 个属性列作为 attr_cols4.2 剔除无效与汇总数据 (核心清洗)删除空值直接删除 Country Name 为 NaN 的行此类行通常为 AFE/AFW 等大洲代码汇总。dfdf.dropna(subset[Country Name])黑名单过滤定义包含 40 项的 black_list 涵盖全球及大洲汇总如“世界”、“东亚与太平洋地区”、“撒哈拉以南非洲地区”等。收入等级分类如“高收入国家”、“中等收入国家”等。非主权地区/领地如“阿鲁巴”、“中国香港特别行政区”、“波多黎各”等。使用 ~df[“Country Name”].isin(black_list) 进行反向过滤最终精准保留 195 个 真实主权国家。# 2.黑名单剔除大洲、收入等级、发展区域汇总black_list[# 全球 大洲汇总世界,北美,东亚与太平洋地区,欧洲与中亚地区,东亚与太平洋地区不包括高收入,欧洲与中亚地区不包括高收入,拉丁美洲与加勒比海地区,拉丁美洲与加勒比海地区不包括高收入,中东、北非、阿富汗与巴基斯坦,中东与北非地区不包括高收入,撒哈拉以南非洲地区,撒哈拉以南非洲地区不包括高收入,南亚,小国,加勒比小国,太平洋岛国,其他小国,未分类国家,阿拉伯联盟国家,欧洲联盟,欧洲货币联盟,经合组织成员,重债穷国 (HIPC),脆弱和受衝突影響的情況下,# 收入等级高收入国家,低收入国家,中等收入国家,中高等收入国家,中低等收入国家,中低收入国家,# 人口红利阶段早人口紅利,後期人口紅利,預人口紅利,人口紅利之後,# 发展水平分类最不发达国家联合国分类,# 世界银行分组IBRD与IDA,只有IBRD,只有IDA,IDA總,IDA混合,东亚与太平洋地区 (IBRD与IDA),欧洲与中亚地区 (IBRD与IDA),拉丁美洲与加勒比海地区 (IBRD与IDA),中东与北非地区 (IBRD与IDA),南亚 (IBRD与IDA),撒哈拉以南非洲地区 (IBRD与IDA),# 地区/领地/非主权地区阿鲁巴,美属萨摩亚,百慕大,库拉索,开曼群岛,海峡群岛,法罗群岛,直布罗陀,格陵兰,关岛,中国香港特别行政区,中国澳门特别行政区,圣马丁法属,圣马丁(荷属),北马里亚纳群岛,新喀里多尼亚,波多黎各,约旦河西岸和加沙,法属波利尼西亚,特克斯科斯群岛,英屬維爾京群島,美属维京群岛,科索沃]dfdf[~df[Country Name].isin(black_list)].reset_index(dropTrue)print(过滤后剩余国家数量,df[Country Name].nunique())过滤后剩余国家数量 1954.3 宽表转长表 (Reshape)使用 pd.melt() 函数将数据结构转换为适合时序分析的“长格式”id_vars : 保持不变的属性列。value_vars : 需要展开的年份列。生成新列 Year (年份) 和 Population (人口数值)# melt宽转长df_longpd.melt(df,id_varsattr_cols,# 不变字段国家名称、编码等value_varsyear_cols,# 需要拆开的年份列var_nameYear,# 拆分成成新列的列名年份value_namePopulation# 对应值的新列名人口)df_long.head()Country NameCountry CodeIndicator NameIndicator CodeYearPopulation0阿富汗AFG人口总数SP.POP.TOTL19609035043.01安哥拉AGO人口总数SP.POP.TOTL19605231654.02阿尔巴尼亚ALB人口总数SP.POP.TOTL19601608800.03安道尔共和国AND人口总数SP.POP.TOTL19609510.04阿拉伯联合酋长国ARE人口总数SP.POP.TOTL1960131334.04.4 数据类型转换与最终清理将 Year 列转换为 int 类型。将 Population 列转换为 numeric 类型并使用 dropna 剔除转换后产生的空值如 2025 年的 NaN 数据。最终得到包含 12,675 条有效记录的干净数据集仅保留 Country Name , Year , Population 三列。df_cleandf_long[[Country Name,Year,Population]]# 仅保留国家名称、年份、人口列df_clean[Year]df_clean[Year].astype(int)# 将年份列转换为整数类型df_clean[Population]pd.to_numeric(df_clean[Population])# 将人口列转换为数值类型df_clean.dropna(inplaceTrue)# 剔除包含 NaN 的行df_clean.head()C:\Users\na\AppData\Local\Temp\ipykernel_23984\3147925960.py:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df_clean[Year]df_clean[Year].astype(int) # 将年份列转换为整数类型 C:\Users\na\AppData\Local\Temp\ipykernel_23984\3147925960.py:3: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df_clean[Population]pd.to_numeric(df_clean[Population]) # 将人口列转换为数值类型 C:\Users\na\AppData\Local\Temp\ipykernel_23984\3147925960.py:4: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df_clean.dropna(inplaceTrue) # 剔除包含 NaN 的行Country NameYearPopulation0阿富汗19609035043.01安哥拉19605231654.02阿尔巴尼亚19601608800.03安道尔共和国19609510.04阿拉伯联合酋长国1960131334.05. 数据可视化与迭代优化 (阶段 4 - 6)5.1 单年份横向柱状图测试 (阶段 4)以 1990 年为例进行原型测试筛选 1990 年数据按人口降序排列并取前 20 名。使用 pyecharts.Bar 绘制启用 reversal_axis() 将柱状图横向放置。配置深色主题 ( ThemeType.DARK )确保标签显示在柱子右侧 ( position“right” )验证基础渲染逻辑无误。# 数据准备test_dfdf_clean[df_clean[Year]1990]test_dftest_df.sort_values(byPopulation,ascendingFalse).head(20)#按人口排序,取前20名#绘制柱状图bar_test(Bar(init_optsopts.InitOpts(themeThemeType.DARK))#设置主题为深色.add_xaxis(test_df[Country Name].tolist())#国家名字作为横轴.add_yaxis(人口,test_df[Population].tolist())#人口作为纵轴.reversal_axis()#将柱状图横向放置.set_global_opts(title_optsopts.TitleOpts(title1990年世界人口排名,pos_leftcenter),#设置标题legend_optsopts.LegendOpts(is_showFalse),#隐藏图例框).set_series_opts(label_optsopts.LabelOpts(positionright))#设置标签显示在柱子右侧)#bar_test.render(bar_test.html) #将图表渲染为html文件,在浏览器中查看bar_test.render_notebook()div id504c2a09894c44e99f38a924fa62473d stylewidth:900px; height:500px;/div5.2 Timeline 轮播基础版 (阶段 5)遍历清洗后的所有唯一 Year 。每年动态生成一个 Bar 实例并通过 Timeline.add() 方法将其按年份追加到时间轴中。配置基础轮播参数 is_auto_playTrue , play_interval700 (毫秒), is_loop_playTrue 。导出为 人口轮播_中文_基础版.html 验证时序动画连贯性。year_listdf_clean[Year].unique().tolist()#获得年份列表#初始化时间线timelineTimeline(init_optsopts.InitOpts(width1500px,height820px,themeThemeType.DARK,bg_color#0a0a0a))#遍历年份列表,每个年份画一个柱状图添加到时间线中foryearinyear_list:# 数据准备data_dfdf_clean[df_clean[Year]year]data_dfdata_df.sort_values(byPopulation,ascendingFalse).head(20)#按人口排序,取前20名data_dfdata_df.sort_values(byPopulation,ascendingTrue)#再次升序排序保证大的在上countrydata_df[Country Name].tolist()#国家名字列表populationdata_df[Population].tolist()#人口列表#绘制柱状图bar(Bar(init_optsopts.InitOpts(themeThemeType.DARK))#设置主题为深色.add_xaxis(country)#国家名字作为横轴.add_yaxis(人口,population)#人口作为纵轴.reversal_axis()#将柱状图横向放置.set_global_opts(title_optsopts.TitleOpts(titlef{year}年世界人口排名,pos_leftcenter),#设置标题legend_optsopts.LegendOpts(is_showFalse),#隐藏图例框).set_series_opts(label_optsopts.LabelOpts(positionright))#设置标签显示在柱子右侧)#将柱状图添加到时间线中timeline.add(bar,str(year))#配置基础轮播参数:自动播放、播放间隔600毫秒、循环播放timeline.add_schema(is_auto_playTrue,play_interval600,is_loop_playTrue)timeline.render(基础轮播图.html)timeline.render_notebook()div idadc22ca8bf5b4439a9e433e9d8ff3b26 stylewidth:1500px; height:820px;/div