news 2026/9/13 2:44:24

全球195国数据集处理:从人口清洗到ISO3多源校验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
全球195国数据集处理:从人口清洗到ISO3多源校验

简介:面向数据分析师、研究人员及统计学师生的全球195个国家指标信息数据集2023,以CSV格式汇总了人口统计、经济、环境、医疗、教育等数十项关键指标,字段包含国家名称、人口密度、农业用地占比、GDP、消费价格指数、预期寿命、婴儿死亡率、产妇死亡比、医生密度、失业率、城市人口比例及坐标等,能够支撑多维度的国家对比研究。压缩包内共3个文件,包括结构化数据表、可直接运行的Python加载示例以及数据说明文档,整体大小仅25KB,便于快速下载与读取。目前已有444人学习,适合用于跨国比较分析、数据可视化练习、统计建模教学及学术研究。借助示例脚本,可快速将数据载入环境,结合字段说明开展深度探索,节省数据采集与清洗时间,是开展量化研究的高效起点。

1. 打开这份 195 国数据集前,先搞清楚它到底在统计什么

一份名为“全球195个国家指标信息数据集2023”的表格文件,听起来像是把一堆国家名字加人口数字堆在一起。实际上它解决的是做全球化分析时最头大的问题:你需要的不是一两个字段,而是把人口、面积、GDP、预期寿命、互联网普及率、城市化率这类横截面指标放在同一张表里,并且保证"一行一个国家"的主键干净可直接 join。数据集可以把世界银行 WDI、UNDP 人类发展报告、CIA World Factbook 等公开源各自分散的发布口径收拢成结构一致的年度快照。适合谁用呢?做数据产品原型、BI 看板、地理可视化和统计建模的人,不想为了查 3 个指标去爬 5 个不同格式的 Excel 和 PDF。

但拿到手先不要急着pd.read_csv后画图。这类聚合数据集最常见的坑在于:各国数据不是同一天上报的,人口和 GDP 在 2023 年快照里可能分别来自 2021 年和 2022 年;总量校验过不过关,决定了你后续做占比分析时结论成不成立。下面用 Python 生态的标准流程,把这份 195 国数据集从原始读入到多源校验走一遍。

2. 字段表结构与人口数据的预处理:读入后先做列名、类型和单位三件事

如果这份 2023 数据集是 CSV 或 Excel 格式,第一步不是急着算全球总人口,而是先了解字段构成。常见做法是把第一行表头读出来,观察列名风格——这类数据集经常混着Country Namecountry_name人口2023几种命名,还有一列ISO3国家代码。做任何处理前,把所有列名统一为小写加下划线的snake_case,省得后面写过滤条件时被大小写反复坑。

2.1 最小读入命令与第一轮“体检”

import pandas as pd df = pd.read_csv("national_indicators_2023.csv", encoding="utf-8") print(df.shape) print(df.columns.tolist()) print(df.head(3).T) # 转置看前几行的全部字段

这段代码会把维度打印成类似(195, 28):195 行对上了标题里的“195 个国家”,28 个字段则要看具体包含了哪些内容,通常有iso3countryregionpopulationpopulation_densitygdp_usdgdp_per_capitaurban_pctlife_expectancymedian_agefertility_rateinternet_pct等。head(3).T转置输出是为了在一屏内看清每个字段对应的前 3 个值,比横向滚动表格更直观。

2.2 人口列的三种“脏”形态

人口字段几乎不可能是干净的 int 类型,我见过三种形态:

  • 带千分位逗号,字符串,如"1,425,000,000"
  • 带缩写单位,如"1.4B""58.3M"
  • 浮点数但单位是千人或百万人,需要乘以对应倍数。

针对前两种,用一个自定义转换函数,比反复replace靠谱得多:

def parse_population(value): """把常见人口字符串转成整数,无法解析返回 None""" if pd.isna(value): return None s = str(value).strip().replace(",", "") if s.endswith("B"): return int(float(s[:-1]) * 1e9) if s.endswith("M"): return int(float(s[:-1]) * 1e6) if s.endswith("K"): return int(float(s[:-1]) * 1e3) try: return int(float(s)) except ValueError: return None df["population_clean"] = df["population"].apply(parse_population)

解析逻辑按优先顺序处理:先去掉千分位逗号,再检查后缀B/M/K(分别对应十亿、百万、千),最后尝试直接转整数。float(s)而不是int(s)是为了兼容"1000.0"这类带小数的写法。None会被 pandas 识别为缺失值,方便下一节统一处理。

2.3 数值字段的整型与浮点检查

人口和面积转成整型,人均 GDP 这类比值指标必须保留浮点。很多人在这一步贪省事,全表astype(float),结果把iso3这种字符串列弄崩。正确做法是显式指定每类字段的dtype

字段类型dtype典型列名
标识字段stringiso3, country, region
总量/计数Int64(可空整型)population, area_sqkm, gdp_usd
比率/均值float64gdp_per_capita, urban_pct, life_expectancy
排名/年份Int64rank, year
df["year"] = 2023 # 如果原文件没有显式年份列 df["area_sqkm"] = pd.to_numeric(df["area_sqkm"], errors="coerce").astype("Int64") df["gdp_per_capita"] = pd.to_numeric(df["gdp_per_capita"], errors="coerce")

pd.to_numeric里的errors="coerce"会把无法解析的值直接变为NaN,而不是抛异常中断整个流程。把面积这类总量列转成Int64而不是int的原因是:缺失值在int下会被 pandas 转成-1或直接报错,而Int64(大写 I)是 pandas 的可空整型扩展类型,允许NaN存在。

3. 缺失值治理与总量校验:用人口数据做第一道质检

195 个国家里如果有 190 行数据完整、5 行缺字段,直接 dropna 会丢掉两三个小国的全部记录。更专业的数据集处理方式是:先看每个字段的缺失率,再决定是填充、保留还是用其他字段推算。

3.1 缺失率速览命令

missing = df.isna().mean().sort_values(ascending=False) print(missing[missing > 0])

输出会是一个按缺失率从高到低排列的 Series。比如看到gdp_usd缺失 18%、internet_pct缺失 12%,这很正常:部分小岛国确实没有每年公布这些数据。反过来,如果population_clean缺失超过 1%,说明解析函数写的有问题,先回到上一节去查是哪几个国家的写法没覆盖到。

3.2 不同的列用不同策略补齐

缺失场景策略理由
人口缺失但 ISO3 存在用该国的上一期增长率推算,或用 UN 数据补录人口是核心列,尽量不要留空
GDP 缺失暂时保留 NaN强行用区域均值和会掩盖经济差异
区域(region)缺失按 ISO3 前两位或官方分类映射补全区域是离散分类,有标准映射表
互联网普及率缺失用“人均 GDP + 中位年龄”做线性回归插补两个变量与互联网渗透率有强相关性

人口缺失但 ISO3 存在时,一个实用的插补做法是找上一年的历史值。不过这份数据集本身是 2023 快照,没有历史时序,所以更稳妥的做法是把它标记为“待补”,在最后输出时单独放一行data_quality_issue列说明,而不是静默填一个可能错得离谱的数字。

3.3 人口总量校验公式

195 个国家的人口加起来应该约等于 2023 年全球人口,也就是80 到 81 亿。这个“总量校验”是第一道质检线:

# 校验:195国人口加总与全球人口参考值的偏差 total_pop = df["population_clean"].sum() reference_pop = 8_045_000_000 # 2023年全球人口粗略值 deviation = (total_pop - reference_pop) / reference_pop print(f"总人口: {total_pop/1e9:.3f}B, 偏差: {deviation:.2%}") if abs(deviation) > 0.02: print("警告:偏差超过2%,需检查是否有国家口径重复或遗漏") else: print("通过:总量在参考值2%以内")

偏差在 2% 以内就算合格,因为各统计机构对“2023 年中人口”的定义有几个月的时间差,且部分国家数字是估算值。如果偏差超过 5%,大概率不是数据质量问题而是结构性错误:某国人口被重复计入、或单位后缀没解析对(比如把"1.4B"误算成 14 亿)。

3.4 异常值不在“缺失”里,要用分布查

population_density突然出现一个 20000 的值,或者median_age出现 0,这类异常不在isna()的职责范围内。最简单的排查是看每个数值列的describe()

print(df[["population_clean", "area_sqkm", "gdp_per_capita", "median_age"]].describe())

重点看max值和25%75%分位数之间的量级差。正常国家数据里population_clean的最大值是 14 亿左右,如果出现 14 万亿这种值,问题几乎都出在单位换算位错。这类异常值的清理原则是“宁可置空也不让脏值参与聚合”,因为一个数量级错误的数字比缺失值的破坏力大得多。

4. 多源对齐与主权键映射:让 2023 指标能和世界银行数据合并

这份数据集自己用没问题,但真正常见的落地场景是把它和其他外部数据源合并——比如把国家指标接到某张公司内部订单表上,或者和最新一期世界银行 API 的实时数据做交叉验证。这时最痛的不是指标本身,而是国家主键对不上

4.1 为什么“国家名”不能当主键

2023 年前后有好几个国家改了官方名称,典型如 Swaziland 改名为 Eswatini、Turkey 改名为 Türkiye、以及捷克共和国在部分场合使用 Czechia。如果你用英文全名去 join,数据源之间只要一个叫Turkey一个叫Türkiye,匹配记录就直接掉了。所以第一条准则是:内部用 ISO3 三位字母码作为主键,不信任任何全名。

# 准备标准对照表:国家名 -> ISO3 # 这里用 pycountry 做兜底映射,手动字典覆盖它识别不了的变体 import pycountry name_to_iso3 = {} for entry in pycountry.countries: name_to_iso3[entry.name.lower()] = entry.alpha_3 # 部分数据源用的是 official_name,也要映射 if hasattr(entry, "official_name"): name_to_iso3[entry.official_name.lower()] = entry.alpha_3 # 手动补几个常见变体 overrides = { "türkiye": "TUR", "eswatini": "SWZ", "czech republic": "CZE", "south korea": "KOR", "russia": "RUS", } name_to_iso3.update(overrides) df["iso3_py"] = df["country"].str.lower().map(name_to_iso3) flag = df["iso3_py"].isna() print(df.loc[flag, ["country", "iso3"]])

这段代码最后会打印出pycountry无法匹配的国家行,供你检查是数据集里的国家名写法太偏,还是该名称确实不在标准库里。逻辑上先尝试标准库,再用覆盖字典补常见变体,最后用flag显式暴露漏网之鱼,不要偷偷吞掉。

4.2 与世界银行 API 的指标交叉验证

世界银行提供公开的指标 API,不需要密钥。拿 2023 年人口做一次对照最实际,因为世界银行的人口数据是按年中估计的:

import requests url = "https://api.worldbank.org/v2/country/all/indicator/SP.POP.TOTL" params = { "format": "json", "date": "2023", "per_page": 300, } resp = requests.get(url, params=params, timeout=30) data = resp.json() # 注意:data[0] 是分页信息,data[1] 才是指标记录列表 rows = [] for item in data[1]: rows.append({ "iso3": item["countryiso3code"], "wb_pop_2023": item["value"], }) wb_df = pd.DataFrame(rows) print(wb_df.shape)

请求参数date=2023限定年份、per_page=300保证一次拉全,避免默认 50 条分页造成数据截断。拿到wb_df后,先检查里面的国家数和本地数据集差多少——世界银行口径通常包含所有经济体而不只是主权国家,所以数量比 195 大是正常的。然后与本地数据做一次彻底的比对:

merged = df.merge(wb_df, left_on="iso3", right_on="iso3", how="left", suffixes=("_local", "_wb")) # 找出本地有值但世行缺值的行,以及两边数值显著不一致的行 not_found = merged[merged["wb_pop_2023"].isna()]["iso3"].tolist() print(f"本土数据集有但世行不返回的ISO3: {not_found}") merged["pop_ratio"] = merged["population_clean"] / merged["wb_pop_2023"] bad_rows = merged[(merged["pop_ratio"] > 1.05) | (merged["pop_ratio"] < 0.95)] print(bad_rows[["country", "population_clean", "wb_pop_2023", "pop_ratio"]])

merge(..., how="left")的意思是以左表(本地数据集)全部行数为准,右边能匹配上的填值,匹配不上的留空。pop_ratio在 0.95 到 1.05 之间视为正常口径差异;一旦跑出 1.2 以上的比例,基本可以断定是本地数据漏了后缀解析,或者世界银行把该国 2022 年的最终值放进来了。注意处理wb_pop_2023为 NaN 的行再算pop_ratio,因为任何数除以 NaN 都是 NaN,不会误报。

4.3 多源对齐时的区域重分组

把区域字段(region)与标准地理分类对齐也是个常被忽略的坑。常见分组标准就有五个,包括世界银行的七大区域、联合国的 M49 编码、IMF 的发达/发展中二分法等。如果你要把这份 195 国数据集和别人分享,最省事的做法是直接用 ISO3 前两位映射到 UN M49 区域编码,而不是保留下载来源里的自定义分组,因为自定义分组经常拼错减字、前后不一致,比如把"Sub-Saharan Africa"写成"SSA""SubSaharan Africa"

# UN M49区域代码简表,只做示意,完整版看官方发布 m49_region = { "NAM": "Americas", "SAU": "Asia", "FJI": "Oceania", # ... 真实使用时应是全量映射 } df["region_std"] = df["iso3"].map(m49_region)

映射函数本身没有魔法:map遇到没有对应键的 ISO3 会返回 NaN,所以映射完后随手用df["region_std"].isna().sum()检查漏网行,漏掉 1 到 2 个小国立即补上。

5. 把数据集做成一个自带校验的查询工具:最后的可留用技巧

既然已经完成字段清洗、缺失治理、ISO3 主键映射和多源校验,下一步不是重新导出 CSV 就完事,而是把这份数据集封装成一个小型查询工具,让它既能在后期反复验证数据质量,也能直接让业务方用。我这里有一个很实用的落地方式:把校验逻辑固化成一个函数,让它每次使用数据前自动跑一遍三率(缺失率、异常率、总量偏差率),再暴露一个按国家 ISO3 查询指标的接口。

def make_clean_lookup(df, iso_col="iso3"): """把清洗后的DataFrame包装成可查询的dict,并打印质量报告""" res = df.set_index(iso_col).to_dict(orient="index") missing_rate = df.isna().mean().mean() total_pop = df["population_clean"].sum() pop_ratio = total_pop / 8_045_000_000 print(f"字段缺失率(平均): {missing_rate:.2%}") print(f"人口总量与参考值之比: {pop_ratio:.2%}") # 只允许查询非NaN字段,返回时去掉缺失字段 return { k: {kk: vv for kk, vv in v.items() if pd.notna(vv)} for k, v in res.items() } lookup = make_clean_lookup(df) china = lookup.get("CHN", {}) print(cn.get("population_clean"), cn.get("gdp_per_capita"))

to_dict(orient="index")把 DataFrame 转成{行索引: {列名: 值}}的嵌套字典,这样按 ISO3 取数的时间复杂度是 O(1),比反复df[df["iso3"]=="CHN"]快很多,尤其适合嵌入式脚本或小服务里频繁读取。返回值时过滤掉 NaN 字段,避免把空值当 0 传给上游。这个技巧的价值在于:它把前面所有清洗逻辑收口成一个入口,数据更新后只要重跑一遍parse_populationmerge,质量报告会自动给出结果。

实际交付时我会把这个lookup字典缓存成JSON文件,配合json.dump(..., ensure_ascii=False, indent=2)导出,业务方直接读这个文件,不碰原始 CSV,减少误操作概率。更精细的校验也可以顺手加进去:遍历每一个字段的取值分布,与上一版快照对比变化幅度。比如 2023 年人口相对 2022 年变化率常规区间在 -1% 到 +3% 之间,若出现某个国家突增 10%,那么就得检查是不是数据源把“总人口”和“常住人口”口径混用了。这类检查写进同一个工具,每次发布数据集之前跑一遍,比卡在季度末人工对口径要可靠得多。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 2:44:04

轻奢美甲品牌疗愈体验与合伙人体系构建指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 2:43:25

Kronos免费AI股票预测教程:五步跑通开源K线基础模型

Kronos免费AI股票预测教程&#xff1a;五步跑通开源K线基础模型 【免费下载链接】Kronos Kronos: A Foundation Model for the Language of Financial Markets 项目地址: https://gitcode.com/GitHub_Trending/kronos14/Kronos 从一个CSV到未来的K线曲线 假设你想做一次…

作者头像 李华
网站建设 2026/9/13 2:42:57

硬盘空间直降50%:用CHD压缩给游戏库做一次完整的存储瘦身

硬盘空间直降50%&#xff1a;用CHD压缩给游戏库做一次完整的存储瘦身 【免费下载链接】romm A beautiful, powerful, self-hosted ROM manager and player. 项目地址: https://gitcode.com/GitHub_Trending/rom/romm 把你收藏里那些 PS1、PS2 的光盘 ISO 换成 CHD 压缩镜…

作者头像 李华
网站建设 2026/9/13 2:42:51

PostgreSQL正则提取导致索引失效:View性能优化实战对比

如果你的Angular项目最近遇到一个诡异现象&#xff1a;功能不复杂&#xff0c;接口数据量也不大&#xff0c;可页面就是卡得让人抓狂&#xff0c;先别急着怀疑前端框架。我最近就在一个后台管理系统里踩了一次典型的“数据库视图层性能”坑——PostgreSQL View 里用正则提取出来…

作者头像 李华
网站建设 2026/9/13 2:39:36

30天259个PR:用Claude Code打造高效AI编程工作流的13个技巧

30天259个PR&#xff0c;这个数字一开始我是怀疑的。平均一天8.6个PR&#xff0c;相当于每个工作日要合入差不多9次代码变更&#xff0c;而且每一笔变更都得经得起审查、测试、合并这一整套流程。如果换成一个喜欢憋大招的开发者&#xff0c;可能一个月下来就一两个巨型PR&…

作者头像 李华