2014-09-26 78 views
3

我試圖找到一個矢量/快/ numpy的友好的方式轉換成在A列下面的值,列B:Python/Numpy - 填補非連續點之間的差距?

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 

上述功能得到我的機器上具有以下性能:

%timeit y = make_y(x) 
10000 loops, best of 3: 28 µs per loop 

我猜一定是有方法,使整個事情速度更快,因爲我最終將需要處理的是1000萬個+元素長數組...

+0

是模式始終如果A是1個,那麼下一行是1時至-1出現在答:這是1和-1標誌着連續的開始和結束1s(但不包括1出現在A中的那一行) – EdChum 2014-09-26 12:33:59

+0

@EdChum--這是正確的。然而,你可能已經注意到'make_y'循環函數中有一個參數也可以跟蹤-1區域。爲了簡化事情(最初),我將這一部分放在了問題的範圍之外。 – bazel 2014-09-26 12:52:28

+0

這是棘手的,我想不出沒有迭代的方法,你可以使用類似'mask = df.loc [(df ['A']。shift()== 1)| (df ['A'] == - 1)]'然後使用'mask.loc [(mask ['A'] == -1)| (mask ['A']。shift(-1)!= -1)]'然後應該顯示開始和結束索引,然後遍歷或拉動索引到成對的列表中,並將其設置爲1. – EdChum 2014-09-26 13:25:34

回答

2

一個可能的量化的解決方案可能是如下

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] 

我們現在有兩條等長的陣列,idx0sidx_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進行了優化,可以更快地搜索已排序的鍵,因此它可能不會引起注意。

如果我把它放在你的x上,它不會超過循環版本,但對於更大的數組,它可能會。

+1

這很漂亮,謝謝。我在2600+元素的數組上定時了你的解決方案。最初的for循環出現了大約500ms。Cython優化版將其降至2ms。該解決方案將其降至113μs。 Jaime好,再次感謝! – bazel 2014-09-26 23:46:19

1

這工作得很好,

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) 
+1

對不起,這不比OP的嘗試更快,OP正在尋找矢量化解決方案。 – EdChum 2014-09-26 17:05:23