【问题标题】:pandas fill forward performance issue熊猫填补前瞻性能问题
【发布时间】:2015-10-08 15:20:39
【问题描述】:

我有一个带有多索引(日期、输入时间)的数据框,并且该数据框可能在列(值、ID)中包含一些 NA 值。我想填写前向值,但仅按日期填写,无论如何我都找不到以非常有效的方式执行此操作。

这是我拥有的数据框类型:

这是我想要的结果:

所以要按日期正确填写,我可以使用 groupby(level=0) 函数。 groupby 很快,但是按日期分组的数据帧上的填充功能真的太慢了​​。

这是我用来比较简单前向填充(没有给出预期结果但运行速度非常快)和预期按日期前向填充(给出预期结果但真的太慢)的代码。

import numpy as np
import pandas as pd
import datetime as dt

# Show pandas & numpy versions
print('pandas '+pd.__version__)
print('numpy '+np.__version__)

# Build a big list of (Date,InputTime,Value,Id)
listdata = []
d = dt.datetime(2001,10,6,5)
for i in range(0,100000):
    listdata.append((d.date(), d, 2*i if i%3==1 else np.NaN, i if i%3==1 else np.NaN))
    d = d + dt.timedelta(hours=8)

# Create the dataframe with Date and InputTime as index
df = pd.DataFrame.from_records(listdata, index=['Date','InputTime'], columns=['Date', 'InputTime', 'Value', 'Id'])

# Simple Fill forward on index
start = dt.datetime.now()
for col in df.columns:
    df[col] = df[col].ffill()
end = dt.datetime.now()
print "Time to fill forward on index = " + str((end-start).total_seconds()) + " s"

# Fill forward on Date (first level of index)
start = dt.datetime.now()
for col in df.columns:
    df[col] = df[col].groupby(level=0).ffill()
end = dt.datetime.now()
print "Time to fill forward on Date only = " + str((end-start).total_seconds()) + " s"

有人可以解释一下为什么这段代码这么慢,或者可以帮助我找到一种有效的方法来在大数据框上按日期填写吗?

谢谢

【问题讨论】:

  • 为什么需要遍历列?如果您没有将索引设置为这些列,而是这样做了:df.groupby(['Date','InputTime']).fillna() 这不会给您想要的吗?

标签: python performance pandas


【解决方案1】:

github/jreback:这是 #7895 的欺骗。 .ffill 没有在 cython 的 groupby 操作中实现(尽管它当然可以),而是在每个组上调用 python 空间。 这是一个简单的方法来做到这一点。 网址:https://github.com/pandas-dev/pandas/issues/11296

根据 jreback 的回答,当你做一个 groupby 时, ffill() 没有优化,但 cumsum() 是。试试这个:

df = df.sort_index()
df.ffill() * (1 - df.isnull().astype(int)).groupby(level=0).cumsum().applymap(lambda x: None if x == 0 else 1)

实用功能:(感谢@Phun)

def ffill_se(df: pd.DataFrame, group_cols: List[str]):
    df['GROUP'] = df.groupby(group_cols).ngroup()
    df.set_index(['GROUP'], inplace=True)
    df.sort_index(inplace=True)
    df = df.ffill() * (1 - df.isnull().astype(int)).groupby(level=0).cumsum().applymap(lambda x: None if x == 0 else 1)
    df.reset_index(inplace=True, drop=True)
    return df

【讨论】:

  • 男孩,这个答案应该更受欢迎!多么快!谢谢!一个方便的函数:``` def ffill_se(df, group_cols): df['GROUP'] = df.groupby(group_cols).ngroup() df.set_index(['GROUP'], inplace=True) df.sort_index( inplace=True) df = df.ffill() * (1 - df.isnull().astype(int)).groupby(level=0).cumsum().applymap(lambda x: None if x == 0 else 1) df.reset_index(inplace=True, drop=True) return df ```
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-11
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
相关资源
最近更新 更多