2012-09-25 37 views
9

我有一個大的一維整數數組,我需要切片。這是微不足道的,我只是做a[start:end]。問題是我需要更多這些切片。如果開始和結束是數組,則a[start:end]不起作用。 For循環可以用於此,但我需要它儘可能快(這是一個瓶頸),所以本地numpy解決方案將受到歡迎。用另一個數組切片numpy數組

爲了進一步說明,我有這樣的:

a = numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], numpy.int16) 
start = numpy.array([1, 5, 7], numpy.int16) 
end = numpy.array([2, 10, 9], numpy.int16) 

而且需要以某種方式使之變成這樣:

[[1], [5, 6, 7, 8, 9], [7, 8]] 
+0

我有一個很難理解什麼'start'和'end'有與此相關。另外,我不認爲你可以完全用numpy做這個,因爲numpy數組需要是矩形的。 – mgilson

+0

YOu可能會嘗試將起始值作爲列表中的元組。 – Keith

+0

因爲在這裏似乎沒有規範的numpy解決方案,所以如果您需要更多的想法,您可能希望事後添加您實際做的事情,以及切片是否具有某些特殊屬性。 – seberg

回答

1

這不是一個「純」 numpy的解決方案(儘管@ mgilson的評論筆記,很難看到不規則的輸出如何能成爲一個numpy的陣列),但:

a = numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], numpy.int16) 
start = numpy.array([1, 5, 7], numpy.int16) 
end = numpy.array([2, 10, 9], numpy.int16) 

map(lambda range: a[range[0]:range[1]],zip(start,end)) 

讓你:

[array([1], dtype=int16), array([5, 6, 7, 8, 9], dtype=int16), array([7, 8], dtype=int16)] 

根據需要。

5

沒有numpy的方法來做到這一點。請注意,由於它是不規則的,它只會是數組/片的列表。不過,我想補充一點,對於幾乎所有numpy函數(二進制)ufuncs(或者至少基於它們),都有reduceat方法,這可能會幫助您避免實際創建切片列表,因而,如果片爲小,加快計算過:

In [1]: a = np.arange(10) 

In [2]: np.add.reduceat(a, [0,4,7]) # add up 0:4, 4:7 and 7:end 
Out[2]: array([ 6, 15, 24]) 

In [3]: np.maximum.reduceat(a, [0,4,7]) # maximum of each of those slices 
Out[3]: array([3, 6, 9]) 

In [4]: w = np.asarray([0,4,7,10]) # 10 for the total length 

In [5]: np.add.reduceat(a, w[:-1]).astype(float)/np.diff(w) # equivalent to mean 
Out[5]: array([ 1.5, 5. , 8. ]) 

編輯:既然你的片重疊,我會補充說,這是太正常:

# I assume that start is sorted for performance reasons. 
reductions = np.column_stack((start, end)).ravel() 
sums = np.add.reduceat(a, reductions)[::2] 

[::2]應該沒有大通常在這裏處理,因爲重疊切片沒有真正的額外工作。

此外還有一個問題,其中stop==len(a)切片。這必須避免。如果你恰好有一個切片有了它,你可以只是做reductions = reductions[:-1](如果它的最後一個),但除此之外,你只需要一個值追加到a誘騙reduceat

a = np.concatenate((a, [0])) 

由於增加一個價值無論如何,由於你在切片上工作,最後並不重要。

7

這可以(幾乎?)在純numpy中使用掩碼數組和步進技巧完成。首先,我們創建面膜:

>>> indices = numpy.arange(a.size) 
>>> mask = ~((indices >= start[:,None]) & (indices < end[:,None])) 

或者更簡單地說:

>>> mask = (indices < start[:,None]) | (indices >= end[:,None]) 

的掩碼False(即值沒有被屏蔽),對於那些>=的起始值和<年底價值指數。 (切片None(又名numpy.newaxis)增加了一個新的維度,使廣播。)現在我們的面具看起來是這樣的:

>>> mask 
array([[ True, False, True, True, True, True, True, True, True, 
     True, True, True], 
     [ True, True, True, True, True, False, False, False, False, 
     False, True, True], 
     [ True, True, True, True, True, True, True, False, False, 
     True, True, True]], dtype=bool) 

現在我們要舒展陣列使用stride_tricks以適應面具:

>>> as_strided = numpy.lib.stride_tricks.as_strided 
>>> strided = as_strided(a, mask.shape, (0, a.strides[0])) 
>>> strided 
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 
     [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 
     [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]], dtype=int16) 

這看起來像一個3x12陣列,但同時每一行分記憶。現在,我們可以將它們組合成一個屏蔽數組:

>>> numpy.ma.array(strided, mask=mask) 
masked_array(data = 
[[-- 1 -- -- -- -- -- -- -- -- -- --] 
[-- -- -- -- -- 5 6 7 8 9 -- --] 
[-- -- -- -- -- -- -- 7 8 -- -- --]], 
      mask = 
[[ True False True True True True True True True True True True] 
[ True True True True True False False False False False True True] 
[ True True True True True True True False False True True True]], 
     fill_value = 999999) 

這是不太一樣的,你問什麼,但它應該表現相似。

+0

很酷的想法,知道這種方法是否適用於他的用例(在較新的numpy版本上)會很有趣。目前的那個缺少''where''關鍵字到'ufunc's(1.7也沒有它的縮減)。這意味着你的步幅技巧陣列將被複制到完整版本中,幾乎可以處理任何事情... – seberg

+0

Mmh,'ufunc'中'where'缺少*無法解決手頭的問題,和'np.ma'通常會避免副本......這實際上並不是使用困擾我的'np.ma'(很酷的想法本身)的問題,而是它可能無法通過循環或列表理解來構建幻燈片(僅僅是因爲數組大小加倍)......不過,這很有趣,+1 –

+0

@PierreGM,是的,我只是想到了那裏的還原函數,但是在某些時候這些可能會被想要...... – seberg

0

類似的解決方案,如timday。類似的速度:

a = np.random.randint(0,20,1e6) 
start = np.random.randint(0,20,1e4) 
end = np.random.randint(0,20,1e4) 

def my_fun(arr,start,end): 
     return arr[start:end] 

%timeit [my_fun(a,i[0],i[1]) for i in zip(start,end)] 
%timeit map(lambda range: a[range[0]:range[1]],zip(start,end)) 

100 loops, best of 3: 7.06 ms per loop 100 loops, best of 3: 6.87 ms per loop

0

如果你想在一個行,這將是:

x=[list(a[s:e]) for (s,e) in zip(start,end)] 
相關問題