我试图通过对一列进行分组,然后对组内的列子集进行洪水填充(bfill().ffill())来掩盖数据框中丢失的数据。
我之前用过
def ffbf(x):
return x.ffill().bfill()
df[some_cols] = df.groupby(group_key)[some_cols].transform(ffbf)
但即使在相对较小的数据帧上,变换也会变得令人难以置信慢(只有 3000x20 已经有几秒钟了),所以我想看看是否可以将 ffill 和 bfill 直接应用于组,因为它们现在应该被 cythonized。
我认为我需要在 ffill 和 bfill 之间再次调用 groupby 是否正确,因为这两种方法都不会保留分组?
现在我有
df[some_cols] = df[some_cols].groupby(group_key).ffill().groupby(group_key).bfill()
而且我认为它正在做我想做的事情,而且它比使用变换快得多,但我对熊猫的经验还不够确定,所以我想我会问。
[编辑] 看来此更改使我的数据变得混乱。为什么?
我认为这里有必要使用另一个
groupby
和 bfill
以避免仅将 NaN
组替换为另一个组。为了提高性能,使用此代码:
NaN
In [205]: %timeit df1[some_cols] = df1.groupby(group_key)[some_cols].transform(ffbf)
443 ms ± 7.26 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [206]: %timeit df[[group_key] + some_cols] = df[[group_key] + some_cols].groupby(group_key).ffill().groupby(group_key).bfill()
5.69 ms ± 31.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
编辑:在下一个 pandas 版本(测试 pandas 1.1.1)中可以使用:
np.random.seed(785)
N = 10000
df = pd.DataFrame({'key':np.random.randint(1000, size=N),
'A':np.random.choice([1,2,np.nan], size=N),
'B':np.random.choice([1,4,np.nan], size=N),
'C':np.random.choice([7,0,np.nan], size=N),
'D':np.random.choice([7,0,8], size=N)})
df = df.sort_values('key')
print (df)
def ffbf(x):
return x.ffill().bfill()
group_key = 'key'
some_cols = ['A','B','C']
df1 = df.copy()
df1[some_cols] = df1.groupby(group_key)[some_cols].transform(ffbf)
#a bit chamgef solution for working in pandas 0.23.1
df[[group_key] + some_cols] = df[[group_key] + some_cols].groupby(group_key).ffill().groupby(group_key).bfill()
print (df.equals(df1))
True
df[[group_key] + some_cols] = df[[group_key] + some_cols].groupby(df[group_key]).ffill().groupby(df[group_key]).bfill()
输出:
import numpy as np
import pandas as pd
from platform import python_version
print(python_version())
print(pd.__version__)
np.random.seed(785)
N = 10000
df = pd.DataFrame({'key1':np.random.randint(30, size=N),
'key2':np.random.randint(30, size=N),
'A':np.random.choice([1,2,np.nan], size=N),
'B':np.random.choice([1,4,np.nan], size=N),
'C':np.random.choice([7,0,np.nan], size=N),
'D':np.random.choice([7,0,8], size=N)})
df = df.sort_values(['key1', 'key2'])
def ffbf(x):
return x.ffill().bfill()
group_keys = ['key1', 'key2']
some_cols = ['A','B','C']
df1 = df.copy()
df2 = df.copy()
# slow method
df1[some_cols] = df1.groupby(group_keys)[some_cols].transform(ffbf)
# fast method
gidx = df2.groupby(group_keys, sort=False).ngroup()
df2 = df2.groupby(gidx).ffill().groupby(gidx).bfill()
print (df2.equals(df1))
import timeit
slow = """dfn = df.groupby(group_keys)[some_cols].transform(ffbf)"""
print(timeit.timeit(slow, globals=globals(), number=20))
fast = """gidx = df.groupby(group_keys, sort=False).ngroup()
dfn = df.groupby(gidx).ffill().groupby(gidx).bfill()"""
print(timeit.timeit(fast, globals=globals(), number=20))