【发布时间】:2017-09-17 19:05:09
【问题描述】:
我有一个大熊猫数据框df_gen包含 10000 个客户的时间序列数据。这些数据与能源使用有关。这是它的小版本
In[1]: df_gen
Out[2]:
10053802 10053856 10053898 10058054
2013-01-01 00:00:00 0.196 1.493 0.332 0.278
2013-01-01 00:30:00 0.155 1.497 0.336 0.275
2013-01-01 01:00:00 0.109 1.487 NaN 0.310
2013-01-01 01:30:00 0.703 1.479 0.331 0.272
2013-01-01 02:00:00 0.389 1.533 0.293 0.313
我有一个填充缺失数据的流程:对于特定客户 ID,它在特定时间戳有缺失数据,找到在整个数据集中具有最相似数据的时间戳,并使用它来填补空白。
使用这种方法的原因是能源使用取决于外部因素,例如外部温度,因此,例如在炎热的日子里,很多顾客都开着空调。如果我们找到大多数其他客户的能源使用与丢失数据点的日期和时间相似的日期和时间,那么这是填补缺失数据的好地方。
它使用一个函数通过计算每行的方差来识别数据与缺失数据的时间戳最匹配的时间戳:
def best_ts(df,ts_null,null_row):
# finds the timestamp for which the load is closest to the missing load at ts_null across the dataset df
# null_row is the row with the null data to be filled
var_df = pd.Series(index=df.index)
var_df.fillna(value=0, inplace=True)
if pd.isnull(null_row).all():
logging.info('No customer data at all for %s ',str(ts_null))
var_df = ((df-null_row).fillna(value=0)**2).sum(axis=1)
smallest = var_df.idxmin()
return smallest
该脚本然后为每个客户和每个时间戳进行迭代,当它找到空数据时,它会调用 best_ts 并从该时间戳填充:
for id in df_gen.columns:
for ts in df_gen.index:
if pd.isnull(df_gen.loc[ts,id]):
# slice df to remove rows that have no filling data for this customer and use this to fill from
fill_ts = best_ts(df_gen[df_gen[id].notnull()],ts, df_gen.loc[ts])
df_gen.loc[ts].fillna(df_gen.loc[fill_ts], inplace=True)
工作示例
使用上面的示例 df,当找到NaN 数据时,best_ts 被传递 3 个参数:删除缺失数据行的 df、缺失数据的时间戳以及作为 pandas Series
In: df_gen[df_gen[id].notnull()]
Out:
10053802 10053856 10053898 10058054
2013-01-01 00:00:00 0.196 1.493 0.332 0.278
2013-01-01 00:30:00 0.155 1.497 0.336 0.275
2013-01-01 01:30:00 0.703 1.479 0.331 0.272
2013-01-01 02:00:00 0.389 1.533 0.293 0.313
In: ts
Out:
datetime.datetime(2013, 1, 1, 1, 0)
In: df_gen.loc[ts]
Out:
10053802 0.109
10053856 1.487
10053898 NaN
10058054 0.310
在函数中,使用与数据帧相同的 DateTimeIndex 创建了一个熊猫系列 var_df。每个值都是方差,即每个客户的能量值与时间戳ts 的能量值之间的平方差之和。
例如,var_df 中的第一个值由 ((0.196-0.109)^2 + (1.493-1.487)^2 + 0 + (0.278-0.310)^2) = 0.008629 给出
In: var_df
Out:
2013-01-01 00:00:00 0.008629
2013-01-01 00:30:00 0.003441
2013-01-01 01:30:00 0.354344
2013-01-01 02:00:00 0.080525
dtype: float64
所以时间戳2013-01-01 00:30:00是最“喜欢”缺失数据的时间,所以选择这个来填补缺失的数据。
所以填充的数据框看起来像这样:
In: df_gen
Out:
10053802 10053856 10053898 10058054
2013-01-01 00:00:00 0.196 1.493 0.332 0.278
2013-01-01 00:30:00 0.155 1.497 0.336 0.275
2013-01-01 01:00:00 0.109 1.487 0.336 0.310
2013-01-01 01:30:00 0.703 1.479 0.331 0.272
2013-01-01 02:00:00 0.389 1.533 0.293 0.313
(注意:在这个小例子中,“最佳”时间戳恰好是丢失数据之前的时间戳,但在完整数据集中,它可能是一年中 17519 个时间戳中的任何一个。)
这段代码有效,但是慢!通过数据集大约需要 2 个月!我希望通过避免嵌套迭代或加速函数来加快它的速度。
【问题讨论】:
-
处理顺序重要吗?即我们需要在客户
10006572之前做客户10006414吗?如果不是,您可以考虑使用多处理,否则使用 ctypes 可能会加快您的循环。 -
您是否考虑过使用
pandas.Dataframe.interpolate而不是滚动您自己的插值算法?看来您正在尝试做"nearest"所做的事情,但我确信它会更有效地完成它。 -
@jprockbelly - 不,顺序并不重要。对多处理一无所知,但 PC 有 16 个内核,所以绝对值得一探。
-
@juanpa.arrivillaga 我看过那个文档。我不认为“最近”做了我想做的事,尽管我不完全理解那里给出的不同方法。
-
您没有提供足够的数据来证明问题。您也没有提供示例计算。期望您的代码记录您的想法通常不是一个好主意。请花时间指导我们进行计算。并向我们展示填补缺失的样子。
标签: python performance pandas dataframe iteration