如何在for循环中为空Pandas DataFrame迭代添加带索引的值
问题分析与修复方案
核心问题:数据存储逻辑错误
你的代码里dT_dt['dT/dt'] = slope这行是把整个列都替换成当前循环的slope,所以最后所有行都会是最后一次循环计算的结果,而不是对应日期存储。
其他潜在问题
- 日期匹配用字符串拼接,不仅繁琐,还容易因为格式问题(比如单双位数的月/日)匹配失败,而且处理Series转字符串的冗余内容(
removeprefix/removesuffix)很脆弱。 - 每次循环都重复转换
raw_data['valid']为datetime,完全没必要,提前做一次就行。 - 循环内定义
nearest函数,会重复创建函数,浪费资源。 - 循环day从1到31,但像2月、4月等没有31天的月份,会找不到对应日期的日出日落数据,直接报错。
修复后的代码
import pandas as pd from scipy import stats from datetime import datetime # ---------------------- 提前完成准备工作 ---------------------- # 1. 提前转换raw_data的时间列,避免循环内重复操作 raw_data['valid'] = pd.to_datetime(raw_data['valid'], format='%m/%d/%Y %H:%M') # 2. 把sunrise_sunset的Date列转成datetime类型,匹配更可靠 sunrise_sunset['Date'] = pd.to_datetime(sunrise_sunset['Date'], format='%m/%d/%Y') # 3. 将nearest函数移到循环外,仅定义一次 def nearest(items, pivot): return min(items, key=lambda x: abs(x - pivot)) # ---------------------- 初始化存储结构 ---------------------- # 用字典暂存日期与对应slope,最后转DataFrame更高效 dT_dt_dict = {} # ---------------------- 循环处理每个日期 ---------------------- for month in range(1,13): # 根据月份设置最大天数,避免循环无效日期 if month in [4,6,9,11]: max_day = 30 elif month == 2: max_day = 28 # 若需处理闰年可改为29,根据实际数据调整 else: max_day = 31 for day in range(1, max_day+1): current_date = datetime(2021, month, day) # 匹配当日日出日落数据,为空则跳过 day_data = sunrise_sunset[sunrise_sunset['Date'] == current_date] if day_data.empty: print(f"无{current_date.strftime('%m/%d/%Y')}的日出日落数据,跳过") continue sunrise_time_str = day_data['Sunrise'].iloc[0] sunset_time_str = day_data['Sunset'].iloc[0] # 转换为完整datetime对象 sunrise_time = datetime.strptime(f"{current_date.strftime('%m/%d/%Y')} {sunrise_time_str}", "%m/%d/%Y %I:%M:%S %p") sunset_time = datetime.strptime(f"{current_date.strftime('%m/%d/%Y')} {sunset_time_str}", "%m/%d/%Y %I:%M:%S %p") # 查找最近的ASOS时间索引 valid_times = raw_data['valid'].tolist() nearest_sunrise = nearest(valid_times, sunrise_time) raw_sunrise_index_time = raw_data[raw_data['valid'] == nearest_sunrise].index[0] nearest_sunset = nearest(valid_times, sunset_time) raw_sunset_index_time = raw_data[raw_data['valid'] == nearest_sunset].index[0] # 提取当日温度数据并计算斜率 raw_data_day = raw_data.iloc[raw_sunrise_index_time+2:raw_sunset_index_time] raw_t = raw_data_day['tmpf'] raw_t_values = raw_t.astype(float).values raw_t_index = raw_t.index.astype(float).values slope, _, _, _, _ = stats.linregress(raw_t_index, raw_t_values) # 将日期和slope存入字典,日期格式转为需求样式 dT_dt_dict[current_date.strftime('%m/%d/%Y')] = slope # 将字典转为目标DataFrame,设置索引与列名 dT_dt = pd.DataFrame.from_dict(dT_dt_dict, orient='index', columns=['dT/dt']) dT_dt.index.name = 'Date'
关键改动说明
- 存储逻辑修正:用字典先收集所有日期的slope,最后一次性转成DataFrame,避免循环中覆盖整列的问题,同时提升性能。
- 日期处理优化:用datetime类型匹配数据,避免字符串拼接的错误,同时处理不同月份的最大天数,防止无效日期报错。
- 性能与容错:提前转换时间列、复用函数,增加空数据判断,减少无效操作与报错风险。
内容的提问来源于stack exchange,提问作者Tyler D
相关产品推荐
相关产品推荐

