寻找一种有效的迭代方式
looking for an efficient way to iterate
我可以征求建议以更有效(更快)地迭代吗?
这是问题所在,我正在寻找一种在确定的 window 大小内在 pandas DataFrame 中向下传播零的方法:
import numpy as np
import pandas as pd
A = np.matrix([[ 0., 1., 1., 1., 1.],
[ 1., 0., 1., 1., 1.],
[ 1., 1., 0., 1., 1.],
[ 1., 1., 1., 0., 1.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 0., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 0., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 1., 1.],
[ 1., 1., 1., 1., 0.],
[ 1., 0., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]])
df = pd.DataFrame(A)
现在我们要以 windows 的增量填充,每行 3 行
顶部的值。
3 行中的每行 window 从 window_start 开始,定义为:
window_size = 3
window_start = [i for i in range(0, df.shape[0])
if i % window_size == 0]
print(df)
gf = df.copy()
print('\n')
现在制作零从
window:
上面的前几行
for i in window_start:
for j in range(1, window_size):
try: gf.iloc[i + j] = gf.iloc[i + j - 1] * gf.iloc[i + j]
except: pass
print(gf)
最后一点对于非常大的数据集来说效率很低而且很耗时,有更好的方法吗?
您应该能够在 groupby
.
内使用累计产品完成此任务
df.groupby(np.arange(len(df)) // 3).cumprod()
0 1 2 3 4
0 0.0 1.0 1.0 1.0 1.0
1 0.0 0.0 1.0 1.0 1.0
2 0.0 0.0 0.0 1.0 1.0
3 1.0 1.0 1.0 0.0 1.0
4 1.0 1.0 1.0 0.0 0.0
5 1.0 1.0 1.0 0.0 0.0
6 1.0 1.0 1.0 1.0 1.0
7 1.0 1.0 1.0 1.0 1.0
8 1.0 1.0 1.0 1.0 0.0
9 1.0 1.0 0.0 1.0 1.0
10 1.0 1.0 0.0 1.0 1.0
11 1.0 1.0 0.0 1.0 1.0
12 1.0 1.0 1.0 1.0 1.0
13 1.0 1.0 1.0 1.0 1.0
14 1.0 1.0 1.0 0.0 1.0
15 1.0 1.0 1.0 1.0 1.0
16 1.0 1.0 0.0 1.0 1.0
17 1.0 1.0 0.0 1.0 0.0
18 1.0 0.0 1.0 1.0 1.0
19 1.0 0.0 1.0 1.0 1.0
我们可以通过使用 concat
来查看它是否按照我们的要求进行更好的查看。
pd.concat([df.iloc[:6, :2], d1.iloc[:6, :2]], axis=1, keys=['Before', 'After'])
Before After
0 1 0 1
0 0.0 1.0 0.0 1.0
1 1.0 0.0 0.0 0.0
2 1.0 1.0 0.0 0.0
3 1.0 1.0 1.0 1.0
4 1.0 1.0 1.0 1.0
5 1.0 1.0 1.0 1.0
我对 numpy
方法的看法
请参阅@Divakar 的解决方案,因为我借用了他函数的一些元素
def prop_zero(df, window_size=3):
a = df.values
W = window_size
m, n = a.shape
pad = np.zeros((W - m % W, n))
b = np.vstack([a, pad])
return pd.DataFrame(
b.reshape(-1, W, n).cumprod(1).reshape(-1, n)[:m],
df.index, df.columns
)
prop_zero(df)
你可以用 cummin
做一个 groupby
:
In [46]: out = df.groupby(np.arange(len(df))//3).cummin()
In [47]: df.head(6)
Out[47]:
0 1 2 3 4
0 0.0 1.0 1.0 1.0 1.0
1 1.0 0.0 1.0 1.0 1.0
2 1.0 1.0 0.0 1.0 1.0
3 1.0 1.0 1.0 0.0 1.0
4 1.0 1.0 1.0 1.0 0.0
5 1.0 1.0 1.0 1.0 1.0
In [48]: out.head(6)
Out[48]:
0 1 2 3 4
0 0.0 1.0 1.0 1.0 1.0
1 0.0 0.0 1.0 1.0 1.0
2 0.0 0.0 0.0 1.0 1.0
3 1.0 1.0 1.0 0.0 1.0
4 1.0 1.0 1.0 0.0 0.0
5 1.0 1.0 1.0 0.0 0.0
这假设所有值都是 0 和 1。如果您有非 1 值但您仍然想要零后零的行为,您可以做类似的事情
df.where(~(df == 0).groupby(np.arange(len(df))//3).cummax(), 0)
这不是很漂亮,但不会被 0.5 之类的值(因为将 cummin
直接应用于这些值)或潜在的溢出(因为将 cumprod
直接应用于值确实如此)。
这是一个 NumPy 方法,它拆分第一个轴给我们一个 3D
数组,然后沿第一个轴使用 cumprod
,然后重塑回 2D
。对于行数不能被 window_size
整除的情况,我们会有剩余的元素不会成为重塑的一部分,这些元素将被单独处理。
因此,实施将是 -
def numpy_cumprod(df, window_size=3):
a = df.values
W = window_size
m,n = a.shape
N = m//W
M = N*W
out0 = a[:M].reshape(-1,W,n).cumprod(1).reshape(-1,n)
out = np.vstack(( out0, a[M:].cumprod(0)))
return pd.DataFrame(out)
示例 运行 -
In [279]: df
Out[279]:
0 1 2 3 4
0 2 2 2 0 1
1 1 2 0 2 2
2 1 1 0 0 1
3 2 0 2 0 1
4 0 0 0 1 0
5 0 0 1 2 1
6 1 1 0 0 1
7 0 0 1 2 1
8 2 2 2 1 1
9 2 1 2 1 0
10 1 1 1 1 2
11 0 2 2 1 2
In [280]: numpy_cumprod(df, window_size=3)
Out[280]:
0 1 2 3 4
0 2 2 2 0 1
1 2 4 0 0 2
2 2 4 0 0 2
3 2 0 2 0 1
4 0 0 0 0 0
5 0 0 0 0 0
6 1 1 0 0 1
7 0 0 0 0 1
8 0 0 0 0 1
9 2 1 2 1 0
10 2 1 2 1 0
11 0 2 4 1 0
更大数据集的运行时测试 -
In [275]: df = pd.DataFrame(np.random.randint(0,3,(10000,5)))
# @piRSquared's soln-1 using pandas groupby
In [276]: %timeit df.groupby(np.arange(len(df)) // 3).cumprod()
100 loops, best of 3: 2.49 ms per loop
# @piRSquared's soln-2 using NumPy
In [261]: %timeit prop_zero(df, window_size=3)
1000 loops, best of 3: 285 µs per loop
# Proposed in this post
In [262]: %timeit numpy_cumprod(df, window_size=3)
1000 loops, best of 3: 262 µs per loop
我可以征求建议以更有效(更快)地迭代吗? 这是问题所在,我正在寻找一种在确定的 window 大小内在 pandas DataFrame 中向下传播零的方法:
import numpy as np
import pandas as pd
A = np.matrix([[ 0., 1., 1., 1., 1.],
[ 1., 0., 1., 1., 1.],
[ 1., 1., 0., 1., 1.],
[ 1., 1., 1., 0., 1.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 0., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 0., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 1., 1.],
[ 1., 1., 1., 1., 0.],
[ 1., 0., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]])
df = pd.DataFrame(A)
现在我们要以 windows 的增量填充,每行 3 行 顶部的值。 3 行中的每行 window 从 window_start 开始,定义为:
window_size = 3
window_start = [i for i in range(0, df.shape[0])
if i % window_size == 0]
print(df)
gf = df.copy()
print('\n')
现在制作零从 window:
上面的前几行for i in window_start:
for j in range(1, window_size):
try: gf.iloc[i + j] = gf.iloc[i + j - 1] * gf.iloc[i + j]
except: pass
print(gf)
最后一点对于非常大的数据集来说效率很低而且很耗时,有更好的方法吗?
您应该能够在 groupby
.
df.groupby(np.arange(len(df)) // 3).cumprod()
0 1 2 3 4
0 0.0 1.0 1.0 1.0 1.0
1 0.0 0.0 1.0 1.0 1.0
2 0.0 0.0 0.0 1.0 1.0
3 1.0 1.0 1.0 0.0 1.0
4 1.0 1.0 1.0 0.0 0.0
5 1.0 1.0 1.0 0.0 0.0
6 1.0 1.0 1.0 1.0 1.0
7 1.0 1.0 1.0 1.0 1.0
8 1.0 1.0 1.0 1.0 0.0
9 1.0 1.0 0.0 1.0 1.0
10 1.0 1.0 0.0 1.0 1.0
11 1.0 1.0 0.0 1.0 1.0
12 1.0 1.0 1.0 1.0 1.0
13 1.0 1.0 1.0 1.0 1.0
14 1.0 1.0 1.0 0.0 1.0
15 1.0 1.0 1.0 1.0 1.0
16 1.0 1.0 0.0 1.0 1.0
17 1.0 1.0 0.0 1.0 0.0
18 1.0 0.0 1.0 1.0 1.0
19 1.0 0.0 1.0 1.0 1.0
我们可以通过使用 concat
来查看它是否按照我们的要求进行更好的查看。
pd.concat([df.iloc[:6, :2], d1.iloc[:6, :2]], axis=1, keys=['Before', 'After'])
Before After
0 1 0 1
0 0.0 1.0 0.0 1.0
1 1.0 0.0 0.0 0.0
2 1.0 1.0 0.0 0.0
3 1.0 1.0 1.0 1.0
4 1.0 1.0 1.0 1.0
5 1.0 1.0 1.0 1.0
我对 numpy
方法的看法
请参阅@Divakar 的解决方案,因为我借用了他函数的一些元素
def prop_zero(df, window_size=3):
a = df.values
W = window_size
m, n = a.shape
pad = np.zeros((W - m % W, n))
b = np.vstack([a, pad])
return pd.DataFrame(
b.reshape(-1, W, n).cumprod(1).reshape(-1, n)[:m],
df.index, df.columns
)
prop_zero(df)
你可以用 cummin
做一个 groupby
:
In [46]: out = df.groupby(np.arange(len(df))//3).cummin()
In [47]: df.head(6)
Out[47]:
0 1 2 3 4
0 0.0 1.0 1.0 1.0 1.0
1 1.0 0.0 1.0 1.0 1.0
2 1.0 1.0 0.0 1.0 1.0
3 1.0 1.0 1.0 0.0 1.0
4 1.0 1.0 1.0 1.0 0.0
5 1.0 1.0 1.0 1.0 1.0
In [48]: out.head(6)
Out[48]:
0 1 2 3 4
0 0.0 1.0 1.0 1.0 1.0
1 0.0 0.0 1.0 1.0 1.0
2 0.0 0.0 0.0 1.0 1.0
3 1.0 1.0 1.0 0.0 1.0
4 1.0 1.0 1.0 0.0 0.0
5 1.0 1.0 1.0 0.0 0.0
这假设所有值都是 0 和 1。如果您有非 1 值但您仍然想要零后零的行为,您可以做类似的事情
df.where(~(df == 0).groupby(np.arange(len(df))//3).cummax(), 0)
这不是很漂亮,但不会被 0.5 之类的值(因为将 cummin
直接应用于这些值)或潜在的溢出(因为将 cumprod
直接应用于值确实如此)。
这是一个 NumPy 方法,它拆分第一个轴给我们一个 3D
数组,然后沿第一个轴使用 cumprod
,然后重塑回 2D
。对于行数不能被 window_size
整除的情况,我们会有剩余的元素不会成为重塑的一部分,这些元素将被单独处理。
因此,实施将是 -
def numpy_cumprod(df, window_size=3):
a = df.values
W = window_size
m,n = a.shape
N = m//W
M = N*W
out0 = a[:M].reshape(-1,W,n).cumprod(1).reshape(-1,n)
out = np.vstack(( out0, a[M:].cumprod(0)))
return pd.DataFrame(out)
示例 运行 -
In [279]: df
Out[279]:
0 1 2 3 4
0 2 2 2 0 1
1 1 2 0 2 2
2 1 1 0 0 1
3 2 0 2 0 1
4 0 0 0 1 0
5 0 0 1 2 1
6 1 1 0 0 1
7 0 0 1 2 1
8 2 2 2 1 1
9 2 1 2 1 0
10 1 1 1 1 2
11 0 2 2 1 2
In [280]: numpy_cumprod(df, window_size=3)
Out[280]:
0 1 2 3 4
0 2 2 2 0 1
1 2 4 0 0 2
2 2 4 0 0 2
3 2 0 2 0 1
4 0 0 0 0 0
5 0 0 0 0 0
6 1 1 0 0 1
7 0 0 0 0 1
8 0 0 0 0 1
9 2 1 2 1 0
10 2 1 2 1 0
11 0 2 4 1 0
更大数据集的运行时测试 -
In [275]: df = pd.DataFrame(np.random.randint(0,3,(10000,5)))
# @piRSquared's soln-1 using pandas groupby
In [276]: %timeit df.groupby(np.arange(len(df)) // 3).cumprod()
100 loops, best of 3: 2.49 ms per loop
# @piRSquared's soln-2 using NumPy
In [261]: %timeit prop_zero(df, window_size=3)
1000 loops, best of 3: 285 µs per loop
# Proposed in this post
In [262]: %timeit numpy_cumprod(df, window_size=3)
1000 loops, best of 3: 262 µs per loop