资讯动态

WDI与物种档案交叉分析:五年气候与生物多样性数据可视化实践

发布时间:2026/9/14 3:40:16 来源:尧图企业网站定制
简介这是一份基于Python的生物多样性与气候变化可视化分析项目的完整源代码与配套数据集适合具备一定Python基础、从事生态学或环境科学相关数据分析和可视化的学习者。项目围绕生物多样性数据和气候因子展开包含数据处理、图表绘制与分析流程代码结构清晰。资源包共707个文件压缩后约148MB主要包含Python脚本与Jupyter Notebookpy/ipynb、生物多样性数据集csv、可视化图片png/jpg以及交互式HTML报告等。各类文件按模块存放原始数据置于DataGather目录生成图表统一输出至ImageResource目录每个分析单元有独立目录便于逐项复现与对照学习。目前页面已有144人浏览学习适合需要上手实战练习、参考完整项目流程的读者通过该项目可以掌握从数据读取、清洗到可视化展示的完整路径并可基于已有数据和图表模板扩展自己的分析需求。1. 从 WDI 到物种档案这个可视化项目到底在分析什么打开项目目录第一眼看到的不是代码而是五个年份的SpeciesProfile.csv和一份WDIData.csv这种文件排布方式说明它不是一个以算法为核心的工程而是一个以数据对齐为核心的实证分析项目。WDIData是世界银行 WDI 数据库的截面快照覆盖全球两百多个经济体的发展指标而SpeciesProfile连续五年存放意味着作者想做的事情是把气候相关指标气温、降水、CO₂ 排放、森林面积等和生物多样性状态物种丰度、濒危等级计数等放在同一把时间尺度和同一套国家代码体系下做交叉观察。数据文件放在DataGather、图表输出到ImageResource每一个分析单元一个目录这套约定意味着项目可以被切成多个独立任务分别跑而不是一个从头到尾的大脚本。适合阅读这份代码的人是那些手里有截面数据、想把环境变量与生态变量拼在一起做趋势判断的分析师和研究者因为项目真正值钱的是它处理两类异构数据时的关键取舍。2. 数据管道WDIData 与 SpeciesProfile 的预处理与关联2.1 先看文件结构宽表、长表与脚注表的分工进入DataGather目录WDIData.csv是典型的世界银行宽表每一行是一个国家在某年的若干指标列名里同时混着国家代码、指标名称以及 1960 到 2023 的年份列。WDIFootNote.csv则是脚注表存放每个指标的统计口径、数据来源与特殊说明。而SpeciesProfile系列文件的结构通常是长表每一行代表某个分类单元在某年的评估状态包含物种名、分类等级、濒危等级字段比如 IUCN 的 LC/VU/EN/CR、所属国家或地区。这种结构差异决定了第一件要做的事是统一坐标系。宽表适合人读但不适合matplotlib直接绘图也不适合与物种表做关联。先写一个通用的读取与整形函数把 WDI 数据从宽表转成长表同时保留脚注信息作为元数据。import pandas as pd def load_wdi_long(path: str, start_year: int 2000) - pd.DataFrame: df pd.read_csv(path) id_vars [Country Name, Country Code, Indicator Name, Indicator Code] # 保留固定的标识列把年份列全部转为长表行 long_df df.melt( id_varsid_vars, var_nameYear, value_nameValue, ) long_df[Year] long_df[Year].astype(int) long_df long_df[long_df[Year] start_year] # 剔除空值占比过高的指标按行保留可分析窗口 valid long_df.dropna(subset[Value]) valid valid[valid[Value] ! 0] return validmelt的作用是把宽度接近 60 列的年份字段折叠成两列Year和Value这样后续按国家、按指标过滤时只需要对Indicator Name做字符串匹配不必记住每个指标在第几列。start_year参数用于裁剪早期数据稀疏的年份WDI 在 1960 年代的覆盖度很低如果直接全量保留后面做时序对齐时会产生大量空值。这里的Value ! 0过滤要谨慎部分指标如森林面积净变化率本身就可能是 0更稳妥的只过滤NaN是否过滤 0 取决于具体指标口径。2.2 物种数据的标准化与年份补齐SpeciesProfile文件每年一份但年份信息在文件名里而不是在表内所以读取时要手动注入年份列。另一个关键问题是物种表的粒度同一个物种可能在不同年份、不同国家下出现多条记录如果直接用merge和气候数据拼接会出现一对多万向爆炸。标准做法是先把物种表聚合到国家 年份 濒危等级计数的粒度再和其他表做关联。import glob def load_species_profiles(profile_dir: str) - pd.DataFrame: frames [] for fp in sorted(glob.glob(f{profile_dir}/2*_SpeciesProfile.csv)): year int(fp.split(/)[-1][:4]) df pd.read_csv(fp) df[Year] year frames.append(df) species pd.concat(frames, ignore_indexTrue) # 按国家、年份、濒危等级统计物种数 summary ( species.groupby([Country Code, Year, Red List Category]) .size() .reset_index(nameSpecies Count) ) return species, summaryglob用文件名前缀2*直接匹配 2018 到 2022 这几个年份文件好处是新增一年数据时不需要改代码。groupby后得到的summary是最小可用粒度既保留物种多样性信息不同濒危等级的数量分布又压缩了数据量。注意这里Country Code是关联 WDI 的关键字段如果物种表里没有国家代码而只有国家名需要先用 ISO 3166-1 alpha-3 映射表做转换这一步省略会导致后续 merge 失败。2.3 关联策略以国家代码为主键以年份为内连接WDI 和物种数据都有国家代码但覆盖集合不同。WDI 覆盖全球而物种数据往往集中在部分热点区域。直接取交集会丢掉样本量但取并集又会出现大段空值。实际项目中推荐的做法是以 WDI 的国家集合为基准物种表为右表做左连接然后按指标维度做去空判断。def build_analysis_frame(wdi_long: pd.DataFrame, species_summary: pd.DataFrame): merged wdi_long.merge( species_summary, on[Country Code, Year], howinner, validateone_to_many, ) return merged这里用inner而不是left是因为绘图和趋势分析中残留空值会干扰回归和均值计算宁可样本少一些也要保证每个数据点都是完整的。validateone_to_many是防止 WDI 侧因为同一个国家年份出现重复指标行导致笛卡尔积属于廉价但很有用的防御性编程。3. 指标交叉气候变量与生物多样性指标的时序对齐方法3.1 先做时序完整性检查跨年份分析2018–2022最怕的是某些国家只有部分年份有数据。可视化做出来是一条断折线看不出是数据缺失还是真实下降。做法是先对Country Code Indicator Name做透视检查每个序列的年份覆盖度coverage ( wdi_long.groupby([Country Code, Indicator Name]) .agg( available_years(Year, nunique), first_year(Year, min), last_year(Year, max), ) .reset_index() ) full_coverage coverage[coverage[available_years] 4]nunique统计的是年份种类数而不是行数能防止同一年份多行记录导致的假性完整。first_year和last_year用来确认序列是否覆盖完整区间如果某国家从 2021 年才开始有数据那五年趋势图上就会出现前端缺失。过滤出available_years 4的国家和指标组合是画趋势图前的最后一道门槛低于门槛的数据做出来的线性回归和斜率比较没有统计意义。3.2 宽表交叉与滚动窗口计算时序对齐做完之后把关键的几个指标从长表里抽出做成宽表每行是国家 年份每列是一个指标值。这样既方便算相关性也方便直接喂给seaborn画散点图矩阵。项目中常见的做法是同时计算气候变量的 3 年滚动均值因为生物多样性对气候变化的响应有滞后性用当年值匹配当年物种数据往往看不到明显规律。def pivot_indicators(wdi_long: pd.DataFrame, indicators: list[str]) - pd.DataFrame: subset wdi_long[wdi_long[Indicator Name].isin(indicators)] wide subset.pivot_table( index[Country Code, Year], columnsIndicator Name, valuesValue, aggfuncmean, ).reset_index() wide wide.sort_values([Country Code, Year]).groupby(Country Code).transform( lambda x: x.rolling(3, min_periods1).mean() ) wide[[Country Code, Year]] subset[[Country Code, Year]].drop_duplicates().values return wide这里pivot_table的aggfuncmean是为了防止同一国家年份下同一个指标出现多行比如 WDI 有时会同时记录区域值和国家值。rolling(3, min_periods1)是处理前两年前值不足的窗口边缘情况min_periods1表示至少有一个窗口值就计算结果这样不会在序列开头引入 NaN。滞后对齐是环境数据分析里最容易忽略的一步——气候对物种的影响通常要一到三年才能体现直接用当年值拟合相关性结果往往弱于预期。3.3 缺失值的层次化处理交叉表里可能出现三种缺失气候数据有但物种数据无、物种数据有但气候数据无、两者都没有。第一种最常见发生在某些小岛屿国家——WDI 有碳排放记录但 IUCN 物种评估没覆盖。第二种出现在物种热点区域如马达加斯加物种评估齐全但部分气候站点数据缺失。处理策略不是统一填充而是分场景。def fill_missing(df: pd.DataFrame, max_interp_gap: int 2) - pd.DataFrame: df df.sort_values([Country Code, Year]) df[[CO2_emissions, Temperature, Precipitation]] ( df.groupby(Country Code)[ [CO2_emissions, Temperature, Precipitation] ] .transform(lambda s: s.interpolate(limitmax_interp_gap, limit_directionboth)) ) return dfinterpolate只对相邻年份做线性插值limit2表示连续缺失超过两年就不插保留 NaN避免在数据稀疏区域用外推制造出平滑的假曲线。limit_directionboth允许对序列开头和结尾的缺失值做填充这在 WDI 数据里很关键——某些国家 2018 年才加入统计但 2019、2020 的物种数据齐全序列开头的缺失不做处理就会丢掉整个国家。对物种数据侧的缺失不做插值因为物种评估有周期性两轮评估之间的缺失不代表物种消失插值会掩盖评估频率本身的信息。4. 可视化呈现多国多年份趋势图的绘制与参数调优4.1 单指标时间序列各国趋势叠放项目把生成图表统一存到ImageResource目录每个分析单元一个子目录所以输出路径要事先约定好。画多国趋势时直接叠画所有国家会得到一张杂乱无章的线网实际处理中应该先做国家分组把处于同一地理区域或同一发展水平组别的国家拆开画子图趋势线表示该组均值散点表示当年具体国家值。import matplotlib.pyplot as plt import numpy as np def plot_group_trend(df, group_col, value_col, output_path): fig, ax plt.subplots(figsize(12, 6)) groups df[group_col].unique() for g in groups: subset df[df[group_col] g] trend subset.groupby(Year)[value_col].mean() ax.plot(trend.index, trend.values, labelg, linewidth2) # 用半透明散点画出组内国家分布避免折线掩盖波动 for _, row in subset.iterrows(): ax.scatter(row[Year], row[value_col], s12, alpha0.25) ax.set_xlabel(Year) ax.set_ylabel(value_col) ax.legend(frameonFalse) ax.spines[top].set_visible(False) ax.spines[right].set_visible(False) fig.tight_layout() fig.savefig(output_path, dpi300, bbox_inchestight) plt.close(fig)这里子图内先画组均值折线再叠加散点能同时展示中心趋势和离散度。alpha0.25把单个国家的点压淡避免一个国家的高值主导视觉。bbox_inchestight防止年份坐标轴标签如 2018被截图裁掉。dpi300不是越高越好——网页展示用 150 足够但论文配图需要 300这里作为项目通用值折中。4.2 相关性热力图气候指标与物种状态另一类高频图是气候指标和濒危物种数量之间的相关性矩阵。用seaborn的heatmap可以一次性看清楚温度、降水、CO₂、森林面积与 EN濒危和 CR极危物种数两两之间的线性相关方向。相关性计算之前先对非正态分布的物种计数做对数变换否则个别国家的高物种基数会主导结果。import seaborn as sns def plot_corr_matrix(df, save_path: str): cols [Temperature, Precipitation, CO2_emissions, Forest_area] species_cols [CR Count, EN Count, VU Count] combined df[cols species_cols].copy() combined[species_cols] np.log1p(combined[species_cols]) corr combined.corr(methodspearman) fig, ax plt.subplots(figsize(10, 8)) sns.heatmap( corr, annotTrue, fmt.2f, cmapRdBu_r, center0, vmin-1, vmax1, squareTrue, linewidths0.5, cbar_kws{shrink: 0.8}, axax, ) fig.savefig(save_path, dpi300, bbox_inchestight) plt.close(fig)methodspearman选择秩相关而不是皮尔逊相关因为物种计数分布呈长尾皮尔逊相关容易被少数高值点带偏。log1p是log(x1)的数值稳定写法处理 0 值不报错。RdBu_r色带把负相关映射为蓝色、正相关映射为红色center0保证色带起点居中避免全图色偏。4.3 关键参数表出图前逐项确认图形类型适用场景关键参数常见错误多国折线图趋势对比linewidth2区分主线alpha降噪图例过多超过15条直接弃用相关性热力图指标两两关系methodspearmanlog1p变换目标列不检查分布直接画皮尔逊相关双轴柱线图气候 vs. 物种数twinx()右侧轴加set_ylim左右轴量纲失衡曲线趋势被扭曲散点回归图单指标与单一等级scatter_kws设透明度不标注 R² 和 p 值图不可独立阅读双轴图是最容易被误读的图形两个轴各自缩放视觉上趋势一致可能是缩放后的假象。项目里如果画双轴图建议在图上标注左右轴的相关系数并注明scipy.stats.pearsonr计算出来的显著性水平。5. 工程化落地buildout 依赖管理与 ImageResource 目录约定5.1 buildout.cfg 在项目中的作用项目根目录里有buildout.cfg和setup.cfg这不是常见的requirements.txt工作流。buildout是 zc.buildout 工具链的配置文件它的核心价值不是替代 pip而是把环境变量、路径约定、启动入口一起固化成可复现的构建过程。对于这类数据分析项目buildout.cfg的典型作用是定义部分parts为DataGather和ImageResource这两个数据目录创建固定的文件系统结构。[buildout] parts datadir plotdir [datadir] recipe plone.recipe.command command mkdir -p ${buildout:directory}/DataGather ${buildout:directory}/ImageResource update-command true [plotdir] recipe plone.recipe.command command python -m compileall ${buildout:directory}/src || trueplone.recipe.command会在buildout执行时运行指定的 shell 命令这里用mkdir -p保证项目在全新 clone 之后也能自动创建数据输出目录。compileall做一个语法检查|| true保证即使编译警告也不会中断流程。如果不想引入buildout等效做法是写一个Makefile或init_dirs.sh但buildout的优势在于多环境一致性——团队里有人用 Windows、有人用 Linuxbuildout会把目录创建逻辑统一到一套配置里。5.2 setup.cfg 做包级元数据管理setup.cfg的存在意味着项目支持pip install -e .的开发模式安装。分析项目中常把工具函数如数据加载、预处理、绘图封装抽成包测试和复现时直接 import 而不用到处复制脚本路径。[metadata] name biodiversity-climate-analysis version 0.1.0 description Biodiversity and climate change visualization from WDI and SpeciesProfile [options] packages find: include_package_data True python_requires 3.8 install_requires pandas1.3 matplotlib3.5 seaborn0.11 numpy1.21python_requires 3.8设定了 Python 版本下限seaborn在 0.11 以上的 API 才稳定支持heatmap的square参数。如果在新机器上执行pip install -e .失败优先检查 Python 版本和seaborn是否装成了 0.10 老版本。5.3 目录规范把输出和输入隔离项目要求图表数据统一存到ImageResource这不仅仅是规整问题更是可复现性问题。分析过程中会反复调整参数重跑实验如果输出散落各处旧图和新图混在一起很容易在写报告时引用错误的版本。常见的改良是在ImageResource下按分析单元和时间戳再加一层子目录。from pathlib import Path from datetime import datetime def make_output_dir(analysis_name: str) - Path: base Path(ImageResource) / analysis_name stamp datetime.now().strftime(%Y%m%d_%H%M) out_dir base / stamp out_dir.mkdir(parentsTrue, exist_okTrue) return out_dir时间戳方案显著增加生成的子目录数量但每次重跑都会产生新的快照不用担心覆盖之前的结果。parentsTrue会自动创建多级目录exist_okTrue则允许同一分钟内重复运行时复用目录。对于路径包含中文的项目Path对象比字符串拼接更安全不会因为分隔符或转义问题在 Windows 上报错。6. 扩展把五年截面升级为趋势预警五年的SpeciesProfile数据不只能画出逐年变化还能用来构建简单的物种状态恶化预警。核心思路是对每个国家计算EN濒危 CR极危物种数在 2018–2022 年间的单调变化趋势如果呈显著上升标记为生态压力上升国家再与同期的气候指标变动方向做联合判断。这个逻辑不复杂但需要从五个独立的截面算出一个可跨年比较的指标实现上要小心物种评估周期的影响——物种评级不是每年都更新某个国家 2018 到 2020 年数值完全相同是正常的评估周期现象不代表生物多样性稳定。from scipy.stats import linregress def compute_trend_score(df, country_colCountry Code, year_colYear, value_colEN_CR Count): results [] for country, grp in df.groupby(country_col): grp grp.sort_values(year_col) x grp[year_col].values y grp[value_col].values if len(x) 3: continue slope, intercept, r_value, p_value, std_err linregress(x, y) results.append({ Country Code: country, slope: slope, r_squared: r_value**2, p_value: p_value, annual_rate: slope / max(np.mean(y), 1), }) return pd.DataFrame(results)linregress直接返回斜率、R²、p 值和标准误。实际筛选时用p_value 0.1且slope 0标记为压力上升p_value 0.9且slope 0标记为改善其他为稳定。annual_rate把绝对斜率归一化为相对于均值的变化率解决物种基数大的国家天然斜率值更高的问题。值得注意五年五个点做回归自由度只有 3统计功效很弱p_value实际只适合做排序参考不能当作严格显著性检验。更稳妥的做法是只取排名前 20 的国家做案例展示而不是对所有国家下一个统计学结论。把趋势得分与气温、降水变化做拼接后用散点图绘制temperature_slope与biodiversity_slope的关系右上象限的国家气温上升的同时 ENCR 数量也在上升就是值得优先观察的对象。若某国家的物种数据在五年间没有评估更新散点会落在横轴上需要在图上标注no reassessment避免阅读者误读为稳定。这一步做完项目的产出就从展示了什么升级为下一轮数据来了之后该重点看哪里这也是我建议在复盘时保留的一个模块。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价