使用df.transform时源数据无NaN却出现NaN值的技术问询
df.transform生成NaN值问题排查与修复
问题现象
处理Fire数据集时,执行df.transform后生成的gridid_raw列出现大量NaN值,原始数据源无任何NaN,且该列意外变为浮点型(因NaN存在),报错提示Float64Index包含NaN。
核心原因分析
getlegend函数循环遗漏元素:
原代码中range(0, len(unique_list) - 1)的循环范围会跳过unique_list的最后一个元素,导致该元素对应的date_delta值无法在legend中匹配,getlegendvalue函数找不到匹配项时默认返回None,被pandas解析为NaN。排序操作未生效:
df.sort_values('acq_date')没有将结果赋值回原DataFrame,导致earliestDate取的是原数据集的第一行日期,而非真正的最早日期,可能引发逻辑偏差(虽非NaN直接原因,但影响date_delta计算准确性)。getlegendvalue无默认返回值:
当输入值不在legend中时,函数未定义明确返回值,默认返回None,直接生成NaN。
修复后的代码
import pandas from datetime import datetime def todatetime(datetime_string): return datetime.strptime(datetime_string, '%Y-%m-%d') def getdaysdelta(earlier_date_string, later_date_string): later_date = todatetime(later_date_string) earlier_date = todatetime(earlier_date_string) return (later_date - earlier_date).days def getlegend(initial_list): unique_list = sorted(set(initial_list)) legend = [] # 遍历所有唯一元素,避免遗漏 for i in range(len(unique_list)): # 用类实例创建对象,避免lambda变量绑定陷阱 obj = type('LegendEntry', (), {})() obj.value = unique_list[i] obj.index = i + 1 legend.append(obj) return legend def getlegendvalue(initial_value, legend): for entry in legend: if entry.value == initial_value: return entry.index # 未匹配到值时返回默认值,避免生成NaN return 0 df = pandas.read_csv(r'data/fires/fire_archive_M6_96619.csv') # 排序并覆盖原DataFrame,确保earliestDate为真正的最早日期 df = df.sort_values('acq_date') earliestDate = df['acq_date'].iloc[0] # 用apply处理单元素转换,逻辑更直观 df['date_delta'] = df['acq_date'].apply(lambda x: getdaysdelta(earliestDate, x)) values = df['date_delta'].values legend = getlegend(values) df['gridid_raw'] = df['date_delta'].apply(lambda x: getlegendvalue(x, legend)) # 转换为整数类型,符合业务预期 df['gridid_raw'] = df['gridid_raw'].astype(int)
关键修改说明
- 修正循环范围:
getlegend中改为遍历所有唯一值,确保无遗漏。 - 生效排序操作:将排序结果赋值回df,并用
iloc[0]安全获取最早日期。 - 添加默认返回:
getlegendvalue未匹配时返回0(可按需调整),杜绝NaN生成。 - 规范对象创建:用类实例替代lambda创建对象,避免潜在的变量绑定问题。
- 类型转换:将
gridid_raw转为整数类型,符合“gridid应为整数”的要求。
内容的提问来源于stack exchange,提问作者Jakub Mól
相关产品推荐
相关产品推荐

