2012-09-25 37 views
9

Tôi có một mảng số nguyên lớn một chiều mà tôi cần phải cắt lát. Đó là tầm thường, tôi chỉ cần làm a[start:end]. Vấn đề là tôi cần thêm những lát này. a[start:end] không hoạt động nếu bắt đầu và kết thúc là mảng. Đối với vòng lặp có thể được sử dụng cho điều này, nhưng tôi cần nó càng nhanh càng tốt (nó là một nút cổ chai), do đó, một giải pháp numpy bản địa sẽ được chào đón.Cắt mảng kết khối với một mảng khác

Tiếp tục minh họa, tôi có điều này:

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) 

Và cần phải bằng cách nào đó làm cho nó vào đây:

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

Tôi đang gặp một thời gian khó khăn để hiểu những gì 'start' và 'end' có để làm điều này. Mặc dù vậy, tôi không nghĩ rằng bạn sẽ có thể làm điều này một cách đầy đủ trong các mảng cứng nhắc như hình chữ nhật. – mgilson

+0

YOu có thể thử tạo các giá trị đầu cuối làm bộ dữ liệu trong danh sách. – Keith

+0

Vì không có giải pháp numpy kinh điển ở đây, nếu bạn cần thêm ý tưởng, bạn có thể muốn thêm vào những gì bạn thực sự làm với nó sau đó và nếu các lát có một số thuộc tính đặc biệt. – seberg

Trả lời

1

Nó không phải là một "tinh khiết" giải pháp NumPy (mặc dù như @ mgilson của comment ghi chú , thật khó để xem cách đầu ra không đều có thể là một mảng không rõ ràng), nhưng:

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

được bạn:

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

theo yêu cầu.

5

Không có phương pháp numpy nào để thực hiện việc này. Lưu ý rằng vì nó là bất thường, nó sẽ chỉ là một danh sách các mảng/lát anyways. Tuy nhiên tôi muốn thêm rằng cho tất cả (nhị phân) ufuncs mà hầu như tất cả các chức năng trong numpy (hoặc ít nhất là dựa trên chúng), có phương pháp reduceat, có thể giúp bạn tránh thực sự tạo danh sách các lát, và do đó, nếu các lát nhỏ, tăng tốc độ tính toán quá:

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. ]) 

EDIT: Kể từ khi lát bạn chồng chéo lên nhau, tôi sẽ bổ sung thêm rằng đây là OK quá:

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

các [::2] nên có lớn giao dịch ở đây bình thường, vì không có thêm công việc thực tế nào được thực hiện cho các lát chồng chéo.

Ngoài ra, có một vấn đề ở đây với các lát mà trong đó stop==len(a). Điều này phải tránh. Nếu bạn có chính xác một lát với nó, bạn chỉ có thể làm reductions = reductions[:-1] (nếu người cuối cùng của nó), nhưng nếu không bạn sẽ chỉ cần thêm một giá trị cho a để lừa reduceat:

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

Như thêm một giá trị để kết thúc không quan trọng kể từ khi bạn làm việc trên các lát anyways.

7

Điều này có thể (gần như?) Được thực hiện trong tinh khiết numpy sử dụng các mảng được che dấu và các thủ đoạn sải chân. Đầu tiên, chúng ta tạo ra mặt nạ của chúng tôi:

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

Hoặc đơn giản hơn:

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

Mặt nạ được False (tức là giá trị không đeo mặt nạ) dành cho những chỉ số đó là >= với giá trị bắt đầu và < giá trị cuối . (Cắt bằng None (còn gọi là numpy.newaxis) sẽ thêm một thứ nguyên mới, cho phép phát sóng.) Bây giờ mặt nạ của chúng tôi trông như thế này:

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

Bây giờ chúng ta phải căng mảng để phù hợp với mặt nạ sử dụng 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) 

này trông giống như một mảng 3x12, nhưng mỗi điểm liên tiếp tại cùng một ký ức. Bây giờ chúng ta có thể kết hợp chúng thành một mảng bị che dấu:

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

Điều này không hoàn toàn giống như những gì bạn đã yêu cầu, nhưng nó sẽ hoạt động tương tự.

+0

Ý tưởng tuyệt vời, sẽ rất thú vị nếu biết cách tiếp cận này hoạt động cho ứng dụng của mình (trên các phiên bản mới hơn). Cái hiện tại thiếu từ khóa 'where' thành' ufunc's (1.7 sẽ không có nó để giảm). Điều đó có nghĩa là các mánh lới xâu chuỗi của bạn sẽ được sao chép vào phiên bản đầy đủ, cho hầu hết mọi thứ bạn làm trên đó ... – seberg

+0

Mmh, thiếu 'where' trong' ufunc' có * không có gì * để làm với vấn đề ở bàn tay, và 'np.ma' thường tránh các bản sao ... Nó không thực sự là vấn đề khi sử dụng' np.ma' (ý tưởng tuyệt vời) khiến tôi phiền lòng, nó có thể sẽ không đánh bại việc xây dựng các slide với một vòng lặp hoặc danh sách hiểu (chỉ vì tăng gấp đôi kích thước mảng) ... Tuy nhiên, thật thú vị, +1 –

+0

@PierreGM, vâng, tôi chỉ nghĩ về các chức năng giảm ở đó, nhưng tại một số thời điểm, những khả năng đó có thể được mong muốn ... – seberg

0

Giải pháp tương tự như ngày giờ. Tương tự như tốc độ:

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

Nếu bạn muốn nó trong một dòng, nó sẽ là:

x=[list(a[s:e]) for (s,e) in zip(start,end)] 
Các vấn đề liên quan