2017-10-13 40 views
2

我有一系列指標a,如果應該複製最後0的索引,它包含1。否則,當前正在運行的指數經過:重複以前的索引

也就是說,

a = np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1]) 
i = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 

與預期輸出

x = np.array([0, 0, 0, 0, 4, 5, 6, 6, 6, 9, 9]) 

還是那句話:邏輯:

  • 在指數y
  • 到達
    • 如果a[y] == 0:返回i[y]
    • 如果a[y] == 1:返回i[yy],其中yymax yy < y: a[yy] == 0 - 「最後一個索引」,其中a0

a[0] == 0,始終。

我設法完成的任何方法都使用遞歸方法/循環,而且效率不高。什麼是快速計算方法x

回答

3

的lenght這裏有一個量化的方式利用的maskingmaximum-accumulationnp.maximum.accumulate -

i[np.maximum.accumulate(np.where(a==0, np.arange(len(a)), 0))] 

另一種方式把它是 -

i[np.maximum.accumulate(np.arange(len(a)) * (a==0))] 

說明

剛進入這裏的故事肉的細節,讓我們分解步驟 -

1]輸入:

In [83]: a = np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1]) 
    ...: i = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 
    ...: 

2]因此,輸入a是:

In [84]: a 
Out[84]: array([0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1]) 

3]獲取覆蓋長度的範圍數組a

In [85]: np.arange(len(a)) 
Out[85]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 

4]現在m問出在地方,其中a是1的範圍內排列,留給我們相對應的元件a是0:

In [86]: np.arange(len(a)) * (a==0) 
Out[86]: array([0, 0, 0, 0, 4, 5, 6, 0, 0, 9, 0]) 

5]使用最大累加來創建斜坡結構根據需要:

In [87]: np.maximum.accumulate(np.arange(len(a)) * (a==0)) 
Out[87]: array([0, 0, 0, 0, 4, 5, 6, 6, 6, 9, 9]) 

6最後索引爲i個與這些號碼爲期望的輸出:

In [88]: i[np.maximum.accumulate(np.arange(len(a)) * (a==0))] 
Out[88]: array([0, 0, 0, 0, 4, 5, 6, 6, 6, 9, 9]) 

運行測試

途徑 -

def FranciscoRodriguez(a,i): # @Francisco Rodríguez's soln 
    x = [] 
    for idx,val in enumerate(a): 
     if val==0: x.append(i[idx]) 
     elif val==1: x.append(x[-1]) 
    return x 

def ThomasGuenet(a,i): # @ThomasGuenet 's soln 
    x = np.zeros(len(a)) 
    for j, aa in enumerate(a): 
     if j == 0: 
      x[j] == aa 
     elif aa == 1: 
      x[j] = x[j-1] 
     else: 
      x[j] = i[j] 
    return x 

def vectorizedApp1(a,i): 
    return i[np.maximum.accumulate(np.where(a==0, np.arange(len(a)), 0))] 

def vectorizedApp2(a,i): 
    return i[np.maximum.accumulate(np.arange(len(a)) * (a==0))] 

計時 -

讓我們的瓷磚給定的樣本,以創造更大的數據集,並測試了所有的解決方案:

In [78]: a = np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1]) 
    ...: i = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 
    ...: 
    ...: a = np.tile(a,100000) 
    ...: i = np.tile(i,100000) 
    ...: 

In [79]: %timeit FranciscoRodriguez(a,i) 
    ...: %timeit ThomasGuenet(a,i) 
    ...: %timeit vectorizedApp1(a,i) 
    ...: %timeit vectorizedApp2(a,i) 
    ...: 
1 loop, best of 3: 328 ms per loop 
1 loop, best of 3: 331 ms per loop 
100 loops, best of 3: 6.07 ms per loop 
100 loops, best of 3: 6.77 ms per loop 
+1

'ufunc.accumulate'非常方便,以前我從來沒有用過! – FooBar

+1

你釘了它的人!我很驚訝! – FcoRodr

2

我做了這個辦法:

a = [0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1] 
i = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
x = [] 
for idx,val in enumerate(a): 
    if val==0: x.append(i[idx]) 
    elif val==1: x.append(x[-1]) 

這是一個循環,只有遍歷列表一次,所以沒有嵌套循環或遞歸。這樣的時間成本將是O(N),爲N的a

+0

在一個長度爲10000的數組上,您的代碼需要'0.0115'秒,而@ Divakar的tkaes'0.00036',將循環加邊。 – FooBar

0

使代碼快,我理解你應使用盡可能少的if,否for(包含一段時間並嘗試/ except),預賦值變量,並使用numpy數組。

a = np.array([0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1]) 
i = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 
x = np.zeros(len(a)) 
for j, aa in enumerate(a): 
    if j == 0: 
     x[j] == aa 
    elif aa == 1: 
     x[j] = x[j-1] 
    else: 
     x[j] = i[j]