
简介面向数据分析师、研究人员及统计学师生的全球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 Name、country_name、人口2023几种命名还有一列ISO3国家代码。做任何处理前把所有列名统一为小写加下划线的snake_case省得后面写过滤条件时被大小写反复坑。2.1 最小读入命令与第一轮“体检”import pandas as pd df pd.read_csv(national_indicators_2023.csv, encodingutf-8) print(df.shape) print(df.columns.tolist()) print(df.head(3).T) # 转置看前几行的全部字段这段代码会把维度打印成类似(195, 28)195 行对上了标题里的“195 个国家”28 个字段则要看具体包含了哪些内容通常有iso3、country、region、population、population_density、gdp_usd、gdp_per_capita、urban_pct、life_expectancy、median_age、fertility_rate、internet_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, yeardf[year] 2023 # 如果原文件没有显式年份列 df[area_sqkm] pd.to_numeric(df[area_sqkm], errorscoerce).astype(Int64) df[gdp_per_capita] pd.to_numeric(df[gdp_per_capita], errorscoerce)pd.to_numeric里的errorscoerce会把无法解析的值直接变为NaN而不是抛异常中断整个流程。把面积这类总量列转成Int64而不是int的原因是缺失值在int下会被 pandas 转成-1或直接报错而Int64大写 I是 pandas 的可空整型扩展类型允许NaN存在。3. 缺失值治理与总量校验用人口数据做第一道质检195 个国家里如果有 190 行数据完整、5 行缺字段直接 dropna 会丢掉两三个小国的全部记录。更专业的数据集处理方式是先看每个字段的缺失率再决定是填充、保留还是用其他字段推算。3.1 缺失率速览命令missing df.isna().mean().sort_values(ascendingFalse) 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, paramsparams, timeout30) 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)请求参数date2023限定年份、per_page300保证一次拉全避免默认 50 条分页造成数据截断。拿到wb_df后先检查里面的国家数和本地数据集差多少——世界银行口径通常包含所有经济体而不只是主权国家所以数量比 195 大是正常的。然后与本地数据做一次彻底的比对merged df.merge(wb_df, left_oniso3, right_oniso3, howleft, 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(..., howleft)的意思是以左表本地数据集全部行数为准右边能匹配上的填值匹配不上的留空。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_coliso3): 把清洗后的DataFrame包装成可查询的dict并打印质量报告 res df.set_index(iso_col).to_dict(orientindex) 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(orientindex)把 DataFrame 转成{行索引: {列名: 值}}的嵌套字典这样按 ISO3 取数的时间复杂度是 O(1)比反复df[df[iso3]CHN]快很多尤其适合嵌入式脚本或小服务里频繁读取。返回值时过滤掉 NaN 字段避免把空值当 0 传给上游。这个技巧的价值在于它把前面所有清洗逻辑收口成一个入口数据更新后只要重跑一遍parse_population和merge质量报告会自动给出结果。实际交付时我会把这个lookup字典缓存成JSON文件配合json.dump(..., ensure_asciiFalse, indent2)导出业务方直接读这个文件不碰原始 CSV减少误操作概率。更精细的校验也可以顺手加进去遍历每一个字段的取值分布与上一版快照对比变化幅度。比如 2023 年人口相对 2022 年变化率常规区间在 -1% 到 3% 之间若出现某个国家突增 10%那么就得检查是不是数据源把“总人口”和“常住人口”口径混用了。这类检查写进同一个工具每次发布数据集之前跑一遍比卡在季度末人工对口径要可靠得多。本文还有配套的精品资源点击获取