我正在尝试对pandas数据帧进行下采样以减少粒度。例如,我想减少这个数据帧:
1 2 3 4
2 4 3 3
2 2 1 3
3 1 3 2
到此(使用均值获得2x2数据帧的下采样):
2.25 3.25
2 2.25
是否有内置的方法或有效的方法来完成它,或者我必须自己编写它?
由于
答案 0 :(得分:7)
一种选择是使用groupby两次。一次为索引:
In [11]: df.groupby(lambda x: x/2).mean()
Out[11]:
0 1 2 3
0 1.5 3.0 3 3.5
1 2.5 1.5 2 2.5
和一次列:
In [12]: df.groupby(lambda x: x/2).mean().groupby(lambda y: y/2, axis=1).mean()
Out[12]:
0 1
0 2.25 3.25
1 2.00 2.25
注意:一个只计算一次平均值的解决方案可能更可取...一个选项是stack,groupby,mean和unstack,但是atm这有点繁琐。
这似乎明显快于Vicktor's solution:
In [21]: df = pd.DataFrame(np.random.randn(100, 100))
In [22]: %timeit df.groupby(lambda x: x/2).mean().groupby(lambda y: y/2, axis=1).mean()
1000 loops, best of 3: 1.64 ms per loop
In [23]: %timeit viktor()
1 loops, best of 3: 822 ms per loop
事实上,Viktor的解决方案使我的(动力不足)笔记本电脑崩溃了更大的DataFrames:
In [31]: df = pd.DataFrame(np.random.randn(1000, 1000))
In [32]: %timeit df.groupby(lambda x: x/2).mean().groupby(lambda y: y/2, axis=1).mean()
10 loops, best of 3: 42.9 ms per loop
In [33]: %timeit viktor()
# crashes
正如Viktor所指出的那样,这不适用于非整数索引,如果需要,你可以将它们存储为临时变量并在之后将它们反馈:
df_index, df_cols, df.index, df.columns = df.index, df.columns, np.arange(len(df.index)), np.arange(len(df.columns))
res = df.groupby(...
res.index, res.columns = df_index[::2], df_cols[::2]
答案 1 :(得分:3)
您可以使用两次rolling_mean
函数,首先是列,然后是行,然后对结果进行切片:
rbs = 2 # row block size
cbs = 2 # column block size
pd.rolling_mean(pd.rolling_mean(df.T, cbs, center=True)[cbs-1::cbs].T,
rbs)[rbs-1::rbs]
除了索引会有所不同(但您可以使用.reset_index(drop=True)
修复此问题)之外,它会提供您想要的相同结果:
1 3
1 2.25 3.25
3 2.00 2.25
时间信息:
In [11]: df = pd.DataFrame(np.random.randn(100, 100))
In [12]: %%timeit
pd.rolling_mean(pd.rolling_mean(df.T, 2, center=True)[1::2].T, 2)[1::2]
100 loops, best of 3: 4.75 ms per loop
In [13]: %%timeit
df.groupby(lambda x: x/2).mean().groupby(lambda y: y/2, axis=1).mean()
100 loops, best of 3: 932 µs per loop
所以它比群组慢了大约5倍而不是800x:)