【发布时间】:2018-07-31 08:16:03
【问题描述】:
如何获取 每个序列 的 5 列中 至少 3 倍于第一的 Dataframe 的行? 用 1 和 0 填充的数据框(无缺失值)。
此外,由于我需要检查数百万行和数十个列,因此快速接近会很有帮助。
【问题讨论】:
标签: python pandas numpy dataframe matrix
如何获取 每个序列 的 5 列中 至少 3 倍于第一的 Dataframe 的行? 用 1 和 0 填充的数据框(无缺失值)。
此外,由于我需要检查数百万行和数十个列,因此快速接近会很有帮助。
【问题讨论】:
标签: python pandas numpy dataframe matrix
创建一个宽度为 5 的滚动总和宽度,查看从第 5 到末尾的所有列,如果值始终为 3 或更高,则选择它们:
rolling_sum = df.rolling(5, min_periods=1, axis=1).sum()
select = (rolling_sum.iloc[:, 4:] >= 3).all(axis=1)
In [92]: df
Out[92]:
0 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 1 0 1 1 0 0
2 0 1 0 1 1 0 0 1 0 0
3 0 1 1 1 0 1 1 1 1 1
4 0 1 0 1 1 1 0 0 1 1
5 0 0 1 1 1 0 1 1 1 0
In [94]: (df.rolling(5, min_periods=1, axis=1).sum().iloc[:, 4:] >= 3).all(axis=1)
Out[94]:
0 False
1 False
2 False
3 True
4 True
5 True
dtype: bool
【讨论】:
df[df != 1] = 0),然后运行相同的算法。也许在df 的副本上执行此操作以保留原始值。
将底层数组数据重塑为3D,使最后一个轴具有5元素,每个元素代表5的块,然后沿该轴求和,得到每个块的总和,最后使用@987654324 @reduce 沿第二个轴表示原始数据帧中的每一行 -
df['result'] = (df.values.reshape(-1,df.shape[1]//5,5).sum(2)>=3).any(1)
为了提高性能,您可能希望使用布尔数组 :df.values==1 而不是 df.values。
示例运行 -
In [41]: df
Out[41]:
0 1 2 3 4 5 6 7 8 9
0 0 1 1 0 0 1 0 0 0 1
1 0 0 0 0 0 0 1 0 1 1
2 0 1 1 0 0 1 1 0 0 1
3 1 1 1 1 0 0 0 1 0 1
4 0 1 1 1 0 1 1 1 1 0
5 0 0 0 0 1 0 0 1 1 1
6 0 0 1 0 1 1 0 0 0 1
In [42]: df['result'] = (df.values.reshape(-1,df.shape[1]//5,5).sum(2)>=3).any(1)
In [43]: df
Out[43]:
0 1 2 3 4 5 6 7 8 9 result
0 0 1 1 0 0 1 0 0 0 1 False
1 0 0 0 0 0 0 1 0 1 1 True
2 0 1 1 0 0 1 1 0 0 1 True
3 1 1 1 1 0 0 0 1 0 1 True
4 0 1 1 1 0 1 1 1 1 0 True
5 0 0 0 0 1 0 0 1 1 1 True
6 0 0 1 0 1 1 0 0 0 1 False
如果列数不是5的倍数,我们可以使用np.add.reduceat -
idx = np.arange(0,df.shape[1],5)
df['result'] = (np.add.reduceat(df.values, idx, axis=1)>=3).any(1)
millions rows and tens of cols 的时间安排 -
In [99]: np.random.seed(0)
...: a = (np.random.rand(1000000,20)>0.6).astype(int)
...: df = pd.DataFrame(a)
# Solution from this post
In [101]: %timeit (df.values.reshape(-1,df.shape[1]//5,5).sum(2)>=3).any(1)
10 loops, best of 3: 65.3 ms per loop
# @w-m's soln
In [102]: %timeit (df.rolling(5, min_periods=1, axis=1).sum().iloc[:, 4:] >= 3).all(axis=1)
1 loop, best of 3: 8.04 s per loop
【讨论】: