Python/Numpy-填充非连续点之间的间隙?

Python/Numpy-填充非连续点之间的间隙?,python,algorithm,numpy,pandas,vectorization,Python,Algorithm,Numpy,Pandas,Vectorization,我试图找到一种矢量化/快速/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-

我试图找到一种矢量化/快速/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列@ID3中的首字母1)。接下来,从ID10到ID14用1填充(因为列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

我猜一定有办法让整个过程更快,因为我最终需要处理1000多万个元素长的阵列…

一个可能的矢量化解决方案如下

idx_1s, = np.where(x == -1)  # find the positions of the -1's
idx1s, = np.where(x == 1)  # find the positions of the 1's
要查找哪些1应变为0并标记1块的开头,请执行以下操作:

idx0s = np.concatenate(([0], np.searchsorted(idx1s, idx_1s[:-1])))
idx0s = idx1s[idx0s]
我们现在有两个长度相等的数组,
idx0s
idx_1s
,标记每个块的第一个和最后一个项目的位置,因此我们现在可以执行以下操作:

y = x.copy()
y[idx0s] = 0
idx0s += 1
idx_1s += 1
mask = np.zeros_like(y, dtype=np.bool)
mask[idx0s] = True
mask[idx_1s] = True
mask = np.logical_xor.accumulate(mask)
y[mask] = 1
这将产生所需的:

>>> y
array([0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0])
它可能有点脆弱,输入格式不正确,我认为它不会优雅地处理拖尾-1。但是唯一的非O(n)操作是调用searchsorted,但是
searchsorted
进行了优化,使排序键的搜索速度更快,因此可能不会引起注意

如果我在您的
x
上计时,它不会超过循环版本,但对于更大的阵列,它可能会

A=[0,0,1,1,0,0,-1,0,1,0,0,1,0,-1,0]
B=[]
#initializing column with same number of zeros 
for j in range(len(A)):
    B.append(0)
print A
for i in range(len(A)):
    #retrieve the indices of pair (1 to -1)
    try:
            one_index=A.index(1)
            neg_one_index=A.index(-1)
    except:
            pass 
    one_index=one_index+1
    #replacing the zeros in column B by 1 at correct locations
    while one_index<=neg_one_index:
            B[one_index]=1
            A[one_index-1]=0
            A[one_index]=0
            one_index=one_index+1
print B
#output->[0,0,0,1,1,1,1,0,0,1,1,1,1,1,0] (i.e correct)
A=[0,0,1,1,0,0,-1,0,1,0,0,1,0,-1,0]
B=[]
#使用相同数量的零初始化列
对于范围内的j(len(A)):
B.追加(0)
打印
对于范围内的i(len(A)):
#检索对(1到-1)的索引
尝试:
一个指数=一个指数(1)
负指数=A指数(-1)
除:
通过
一个指数=一个指数+1
#在正确位置将B列中的零替换为1
而一个_指数[0,0,0,1,1,1,1,0,0,1,1,1,1,0](即正确)

模式是否始终是如果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)]再次折叠它(掩码['A'].shift(-1)!=-1)]
然后应该显示开始索引和结束索引,然后迭代或将索引拉入元组对列表中,元组对中有beg、end并将其设置为1。很抱歉,这并不比OP的尝试快,OP正在寻找矢量化解决方案。这非常巧妙,谢谢。我在2600+eleme的数组上计时了您的解决方案nts。最初的for循环速度约为500毫秒。Cython优化版将速度降低到2毫秒。此解决方案将速度降低到113微秒。干得好,Jaime,再次感谢!
A=[0,0,1,1,0,0,-1,0,1,0,0,1,0,-1,0]
B=[]
#initializing column with same number of zeros 
for j in range(len(A)):
    B.append(0)
print A
for i in range(len(A)):
    #retrieve the indices of pair (1 to -1)
    try:
            one_index=A.index(1)
            neg_one_index=A.index(-1)
    except:
            pass 
    one_index=one_index+1
    #replacing the zeros in column B by 1 at correct locations
    while one_index<=neg_one_index:
            B[one_index]=1
            A[one_index-1]=0
            A[one_index]=0
            one_index=one_index+1
print B
#output->[0,0,0,1,1,1,1,0,0,1,1,1,1,1,0] (i.e correct)