【发布时间】:2014-11-21 10:59:53
【问题描述】:
我正在尝试找到一种矢量化/快速/numpy 友好的方式来将 A 列中的以下值转换为 B 列:
ID A B
1 0 0
2 0 0
3 1 0
4 1 1
5 0 1
6 0 1
7 -1 1
8 0 0
9 1 0
10 0 1
11 0 1
12 1 1
13 0 1
14 -1 1
15 0 0
定义列“B”的算法将使用值 1 填充 1 和 -1 组之间的所有间隙,跳过每对中的第一行。也就是说,对于 ID4-ID7,B 列用 1 填充(给定 A 列中的初始 1 @ ID3)。接下来,从 ID10-ID14 填充一个(因为列 A @ ID9 =1)。
虽然使用 for 循环很容易做到这一点,但我想知道是否存在非循环解决方案?下面是一个基于 O(n) 循环的解决方案:
import numpy as np
import pandas as pd
x = np.array([ 0, 0, 1, 1, 0 ,0, -1, 0, 1, 0 , 0, 1, 0, -1, 0])
def make_y(x,showminus=False):
y = x * 0
state = 0 # are we in 1 or 0 or -1
for i,n in enumerate(x):
if n == 1 and n != state:
state = n
if i < len(y)-1:
y[i+1] = state
elif n == -1 and n != state:
y[i] = state
if showminus:
state = -1
else:
state = 0
else:
y[i] = state
return y
y = make_y(x)
print pd.DataFrame([x,y]).T
上述函数在我的机器上产生以下性能:
%timeit y = make_y(x)
10000 loops, best of 3: 28 µs per loop
我猜肯定有某种方法可以让整个事情变得更快,因为我最终需要处理超过 1000 万个元素长的数组...
【问题讨论】:
-
模式是否总是如果 A 为 1,则下一行 B 为 1,直到 -1 出现在 A 中。即 1 和 -1 标记连续 1 的开始和结束(但不包括1 出现在 A) 中的行
-
@EdChum - 没错。但是,您可能已经注意到在
make_y循环函数中还有一个参数也可以跟踪-1 区域。为了简化事情(最初),我把那部分排除在外。 -
这很棘手,我想不出没有迭代的方法,你可以使用
mask = df.loc[(df['A'].shift() == 1) | (df['A']==-1)]之类的东西获取这些标记的索引,然后使用mask.loc[(mask['A'] == -1) | (mask['A'].shift(-1) != -1)]再次折叠它应该然后显示开始和结束索引,然后迭代或将索引拉入元组对列表中,其中该对已经开始,结束并将这些设置为 1。
标签: python algorithm numpy pandas vectorization