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

带DatetimeIndex的DataFrame用字典替换NaN失效,求高效实现方案

高效填充带DatetimeIndex的DataFrame缺失值

我有一个存储小时级测量数据的字典,其中部分条目缺失(存在数据间隙)。当前做法是创建一个带小时级DatetimeIndex、预填充NaN的DataFrame,再尝试用字典替换DataFrame中的值,后续还要插值消除NaN。但之前尝试的几种方法都无效,只有循环赋值能成功,但效率极低(字典约有10000条数据),求高效实现方案。

原代码及运行结果:

import pandas as pd
import numpy as np

dataRange = pd.date_range(pd.to_datetime('2023-01-01 01:00:00'), pd.to_datetime('2023-01-01 05:00:00'), freq='H')
df = pd.DataFrame(np.nan, index=dataRange, columns=['gas'])
df['gas'] = pd.to_numeric(df['gas'], errors='coerce')

gasDict = {'2023-01-01 01:00:00' : 40,
           '2023-01-01 03:00:00' : 20  
          }

# 以下3种方法均无效
# 方法来自stackoverflow:remap-values-in-pandas-column-with-a-dict-preserve-nans
df1 = df['gas'].map(gasDict).fillna(df['gas']) 
print(df1)

df2 = df['gas'].map(gasDict)
print(df2)

df3 = df.replace({'gas': gasDict})
print(df3)

# 此方法正确但效率极低:
for key, value in gasDict.items():
    df.at[pd.to_datetime(key)] = value    

print(df) 

运行结果:

2023-01-01 01:00:00   NaN
2023-01-01 02:00:00   NaN
2023-01-01 03:00:00   NaN
2023-01-01 04:00:00   NaN
2023-01-01 05:00:00   NaN
Freq: H, Name: gas, dtype: float64
2023-01-01 01:00:00   NaN
2023-01-01 02:00:00   NaN
2023-01-01 03:00:00   NaN
2023-01-01 04:00:00   NaN
2023-01-01 05:00:00   NaN
Freq: H, Name: gas, dtype: float64
                     gas
2023-01-01 01:00:00  NaN
2023-01-01 02:00:00  NaN
2023-01-01 03:00:00  NaN
2023-01-01 04:00:00  NaN
2023-01-01 05:00:00  NaN
                      gas
2023-01-01 01:00:00  40.0
2023-01-01 02:00:00   NaN
2023-01-01 03:00:00  20.0
2023-01-01 04:00:00   NaN
2023-01-01 05:00:00   NaN

问题原因

之前的方法无效是因为:

  • map()和replace()都是基于列值进行匹配替换,但原DataFrame的gas列全是NaN,字典的键是日期字符串,和列值完全不匹配,所以无法替换。
  • 循环赋值效率低是因为每次df.at[]都是单条操作,处理10000条数据时会产生大量IO开销。

高效解决方案

方法1:字典转Series后用combine_first()赋值

把字典转换成带DatetimeIndex的Series,利用pandas的索引对齐特性,通过combine_first()填充原DataFrame的NaN值:

import pandas as pd
import numpy as np

dataRange = pd.date_range(pd.to_datetime('2023-01-01 01:00:00'), pd.to_datetime('2023-01-01 05:00:00'), freq='H')
df = pd.DataFrame(np.nan, index=dataRange, columns=['gas'])
df['gas'] = pd.to_numeric(df['gas'], errors='coerce')

gasDict = {'2023-01-01 01:00:00' : 40,
           '2023-01-01 03:00:00' : 20  
          }

# 高效方法:字典转Series,利用索引对齐填充
gas_series = pd.Series(gasDict, index=pd.to_datetime(list(gasDict.keys())))
df['gas'] = df['gas'].combine_first(gas_series)

print(df)

运行结果:

gas
2023-01-01 01:00:00  40.0
2023-01-01 02:00:00   NaN
2023-01-01 03:00:00  20.0
2023-01-01 04:00:00   NaN
2023-01-01 05:00:00   NaN

方法2:用update()直接更新

update()方法会根据索引匹配,用新数据覆盖原DataFrame对应位置的值,同样依赖索引对齐,效率极高:

# 另一种高效方法:使用update
gas_series = pd.Series(gasDict, index=pd.to_datetime(list(gasDict.keys())))
df.update(gas_series)

print(df)

运行结果与方法1完全一致。

两种方法的区别

  • combine_first():保留原DataFrame中非NaN的值,仅用新Series的值填充原NaN的位置(索引匹配时)。
  • update():直接用新Series的值覆盖原DataFrame中对应索引的位置,不管原位置是否为NaN。

对于你的场景,两种方法效果相同,因为原DataFrame全是NaN。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 12:42:03