You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现按区域和年份循环计算NDVI绿化进度差?

问题描述

我拥有16个区域的NDVI数据,需找出各区域每年绿化面积达5%和95%对应的日序(doy),计算两者差值。此前通过手动重复代码完成,现希望用Python循环实现该流程,将所有区域、年份的结果整合为一个大型DataFrame。

手动处理的代码片段如下:

import pandas as pd
import numpy as np

x = pd.read_csv('D:/data.csv')
x = x[x['means'] > 0]
x = x[x['diff'] > -1.5]
x = x[x['area'] > 9318]
x = x.sort_values(by = 'doy')

AKB = x[x['name'] == 'Region1'].drop_duplicates(subset=['ID', 'Year'], keep = 'first')
AKB['cummulative_area'] = AKB.groupby(['Year'])['area'].cumsum()
AKT = x[x['name'] == 'Region2'].drop_duplicates(subset=['ID', 'Year'], keep = 'first')
AKT['cummulative_area'] = AKT.groupby(['Year'])['area'].cumsum()

# 找出5%和95%绿化面积对应的日序并计算差值
AKB01 = AKB[AKB['Year'] == 2001]
AKB01fifth = AKB01[AKB01['cumulative_area'] > AKB01['area'].sum() * 0.05]
AKB01ninefifth = AKB01[AKB01['cumulative_area'] > AKB01['area'].sum() * 0.95]
AKB01 = AKB01ninefifth.doy.min() - AKB01fifth.doy.min()
AKB02 = AKB[AKB['Year'] == 2002]
AKB02fifth = AKB02[AKB02['cumulative_area'] > AKB02['area'].sum() * 0.05]
AKB02ninefifth = AKB02[AKB02['cumulative_area'] > AKB02['area'].sum() * 0.95]
AKB02 = AKB02ninefifth.doy.min() - AKB02fifth.doy.min()
# ... 后续年份重复代码省略
AKB19 = AKB[AKB['Year'] == 2019]
AKB19fifth = AKB19[AKB19['cumulative_area'] > AKB19['area'].sum() * 0.05]
AKB19ninefifth = AKB19[AKB19['cumulative_area'] > AKB19['area'].sum() * 0.95]
AKB19 = AKB19ninefifth.doy.min() - AKB19fifth.doy.min()

# ... 其他区域重复代码省略

AKBign = pd.DataFrame()
AKBign['year'] = np.arange(2001,2020,1)
AKBign['difference'] = [AKB01,AKB02,AKB03,AKB04,AKB05,AKB06,AKB07,AKB08,AKB09,AKB10,AKB11,AKB12,AKB13,AKB14,AKB15,AKB16,AKB17,AKB18,AKB19]
循环实现方案

以下是用Pandas分组和自定义函数实现的自动化流程,无需手动重复代码:

import pandas as pd
import numpy as np

# 1. 数据预处理
x = pd.read_csv('D:/data.csv')
# 合并过滤条件,减少重复操作
x = x[(x['means'] > 0) & (x['diff'] > -1.5) & (x['area'] > 9318)]
# 按日序排序
x = x.sort_values(by='doy')
# 去重:每个ID和Year保留第一条记录
x = x.drop_duplicates(subset=['ID', 'Year'], keep='first')

# 2. 计算各区域每年的累计绿化面积
x['cumulative_area'] = x.groupby(['name', 'Year'])['area'].cumsum()

# 3. 自定义函数:计算单一年份的5%/95%日序及差值
def calculate_season_metrics(group):
    total_area = group['area'].sum()
    # 找到累计面积达5%的最小日序
    doy_5p = group[group['cumulative_area'] >= total_area * 0.05]['doy'].min()
    # 找到累计面积达95%的最小日序
    doy_95p = group[group['cumulative_area'] >= total_area * 0.95]['doy'].min()
    # 返回结果,缺失值自动填充为NaN
    return pd.Series({
        'doy_5p': doy_5p,
        'doy_95p': doy_95p,
        'difference': doy_95p - doy_5p
    })

# 4. 按区域和年份分组批量计算
result = x.groupby(['name', 'Year']).apply(calculate_season_metrics).reset_index()

# 5. 整理结果列顺序(可选)
result = result[['name', 'Year', 'doy_5p', 'doy_95p', 'difference']]

# 可选:筛选特定年份范围(比如2001-2019)
result = result[result['Year'].between(2001, 2019)]

代码说明

  • 预处理优化:合并过滤条件,一次性完成去重和排序,避免重复编写过滤逻辑。
  • 批量累计计算:直接按name和Year分组计算累计面积,无需单独处理每个区域。
  • 函数封装逻辑:将单一年份的计算逻辑封装成函数,通过groupby.apply自动遍历所有区域和年份,彻底替代手动重复代码。
  • 结果整合:最终result是包含所有区域、年份的完整DataFrame,清晰展示每个区域每年的5%日序、95%日序及两者差值。

内容的提问来源于stack exchange,提问作者Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:20:35