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

sklearn MinMaxScaler分组转换未映射至0-1范围问题排查

问题分析与修复方案

原代码的核心问题

  1. 未按分组独立缩放:当前代码实际是对整列数据进行全局缩放,而非按field_id+year分组单独处理。groups[column].transform(lambda x: x.values)仅返回原列的所有值(未做分组转换),随后scaler.fit_transform基于整列的全局最值计算缩放比例,这就是特定分组的NDVI值范围不符合预期的根本原因。
  2. 列选择逻辑错误:column_range = list(df.columns[1:range])是无效代码——range是Python内置函数,不能直接用作索引切片。且你定义了columns参数却未使用,应通过该参数指定需要缩放的列。
  3. 修改输入数据副作用:原代码直接在输入df上添加year列,会修改原始数据,应操作副本避免此问题。
  4. NaN处理不完整:仅检查整列是否有非空值,未处理分组内存在NaN的情况,可能导致缩放报错或结果异常。

修复后的代码

import pandas as pd
from sklearn.preprocessing import MinMaxScaler

def normalise_by_year(df, columns):
    # 创建副本避免修改原数据
    df_copy = df.copy()
    df_copy['date'] = pd.to_datetime(df_copy['date'], dayfirst=True)
    df_copy['year'] = df_copy['date'].dt.year
    
    # 定义分组缩放的辅助函数
    def scale_group(x):
        non_null_vals = x.dropna()
        if len(non_null_vals) == 0:
            return x  # 无有效数据时返回原值
        # 为每个分组单独创建并拟合缩放器
        scaler = MinMaxScaler()
        scaled_vals = scaler.fit_transform(non_null_vals.values.reshape(-1, 1)).flatten()
        # 将缩放后的值映射回原索引,保留NaN
        result = pd.Series(index=x.index)
        result.loc[non_null_vals.index] = scaled_vals
        return result
    
    # 按field_id和年份分组
    groups = df_copy.groupby(['field_id', 'year'])
    
    # 对指定列逐一进行分组缩放
    for col in columns:
        df_copy[col] = groups[col].transform(scale_group)
    
    return df_copy

关键修复点说明

  • 分组独立缩放:通过groupby.transform结合辅助函数,确保每个field_id+year分组使用自身的最值进行缩放,严格实现预期的(0,1)范围映射。
  • 无副作用操作:基于输入DataFrame的副本进行处理,不会修改原始数据。
  • 清晰的列指定:直接使用传入的columns参数定义需要缩放的列,逻辑更明确。
  • 完善的NaN处理:辅助函数会跳过全NaN的分组,同时保留分组内的NaN值,避免空值导致的报错。

内容的提问来源于stack exchange,提问作者Barbara Perez de Araújo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:48:07