2015-04-27 21 views
5

Nói rằng tôi có một vector numpy,Vectorizing một hoạt động lát NumPy

A = zeros(100) 

và tôi chia nó thành subvectors bởi một danh sách các breakpoint mà chỉ số thành A, ví dụ,

breaks = linspace(0, 100, 11, dtype=int) 

Vì vậy, các i -th subvector sẽ nằm giữa các chỉ số breaks[i] (bao gồm) và breaks[i+1] (độc quyền). Các điểm ngắt không nhất thiết phải là một điểm tương đồng, đây chỉ là một ví dụ. Tuy nhiên, chúng sẽ luôn tăng nghiêm ngặt.

Bây giờ tôi muốn hoạt động trên các phân nhóm con này. Ví dụ, nếu tôi muốn đặt tất cả các yếu tố của subvector i -thứ để i, tôi có thể làm:

for i in range(len(breaks) - 1): 
    A[breaks[i] : breaks[i+1]] = i 

Hoặc tôi có thể muốn tính toán subvector có nghĩa là:

b = empty(len(breaks) - 1) 
for i in range(len(breaks) - 1): 
    b = A[breaks[i] : breaks[i+1]].mean() 

Và vân vân .

Làm cách nào để tránh sử dụng các vòng for và thay vào đó vector hóa các hoạt động này?

+0

là 'breaks' trước sắp xếp? – Divakar

+0

@ Divakar: Vâng, chúng đang gia tăng nghiêm ngặt. – cfh

+0

Ngoài ra, giới hạn ngắt có thể bao gồm toàn bộ 'A', tức là có thể có một số thành phần của A không bị thay đổi sau khi hoạt động này không? – Divakar

Trả lời

5

Có thực sự không phải là một câu trả lời duy nhất cho câu hỏi của bạn, nhưng một số kỹ thuật mà bạn có thể sử dụng làm khối xây dựng.Một số khác bạn có thể thấy hữu ích:

Tất cả ufuncs NumPy có một phương pháp .reduceat, mà bạn có thể sử dụng để lợi thế của bạn đối với một số tính toán của bạn:

>>> a = np.arange(100) 
>>> breaks = np.linspace(0, 100, 11, dtype=np.intp) 
>>> counts = np.diff(breaks) 
>>> counts 
array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]) 
>>> sums = np.add.reduceat(a, breaks[:-1], dtype=np.float) 
>>> sums 
array([ 45., 145., 245., 345., 445., 545., 645., 745., 845., 945.]) 
>>> sums/counts # i.e. the mean 
array([ 4.5, 14.5, 24.5, 34.5, 44.5, 54.5, 64.5, 74.5, 84.5, 94.5]) 
3

Bạn có thể sử dụng np.repeat:

In [35]: np.repeat(np.arange(0, len(breaks)-1), np.diff(breaks)) 
Out[35]: 
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 
     2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 
     4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
     6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 
     9, 9, 9, 9, 9, 9, 9, 9]) 

Để tính toán thống kê binned tùy ý bạn có thể sử dụng scipy.stats.binned_statistic:

import numpy as np 
import scipy.stats as stats 

breaks = np.linspace(0, 100, 11, dtype=int) 
A = np.random.random(100) 

means, bin_edges, binnumber = stats.binned_statistic(
    x=np.arange(len(A)), values=A, statistic='mean', bins=breaks) 

stats.binned_statistic có thể tính toán phương tiện, trung vị, số lượng, số tiền; hoặc, để tính toán một thống kê tùy ý cho mỗi bin, bạn có thể vượt qua một callable đến statistic tham số:

def func(values): 
    return values.mean() 

funcmeans, bin_edges, binnumber = stats.binned_statistic(
    x=np.arange(len(A)), values=A, statistic=func, bins=breaks) 

assert np.allclose(means, funcmeans) 
+0

Nhưng làm thế nào bây giờ tôi sẽ đặt phần 'i'-th thành' i' trong khi tránh vòng lặp for? – cfh

6

Bạn có thể sử dụng đơn giản np.cumsum -

import numpy as np 

# Form zeros array of same size as input array and 
# place ones at positions where intervals change 
A1 = np.zeros_like(A) 
A1[breaks[1:-1]] = 1 

# Perform cumsum along it to create a staircase like array, as the final output 
out = A1.cumsum() 

mẫu chạy -

In [115]: A 
Out[115]: array([3, 8, 0, 4, 6, 4, 8, 0, 2, 7, 4, 9, 3, 7, 3, 8, 6, 7, 1, 6]) 

In [116]: breaks 
Out[116]: array([ 0, 4, 9, 11, 18, 20]) 

In [142]: out 
Out[142]: array([0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4]..) 

Nếu bạn muốn có giá trị trung bình của những người phụ đề đó từ A, bạn có thể sử dụng np.bincount -

mean_vals = np.bincount(out, weights=A)/np.bincount(out) 

Nếu bạn đang tìm kiếm để mở rộng chức năng này và sử dụng một tùy chỉnh chức năng thay vào đó, bạn có thể muốn nhìn vào MATLAB của accumarray tương đương cho : accum có mã nguồn có sẵn here.

+0

Tôi thích phương pháp của bạn; nó nhanh hơn tôi. Bạn cũng có thể sử dụng 'A1 = np.zeros (ngắt [-1])'. – unutbu

+0

@unutbu Ah cảm ơn! Tốt để biết rằng mẹo! – Divakar

+0

Điều này giải quyết trường hợp sử dụng đơn giản của việc thiết lập mỗi subvector là không đổi (có nghĩa là một ví dụ). Điều gì sẽ xảy ra nếu, ví dụ, tôi muốn tính giá trị trung bình của từng phân nhóm con? – cfh

Các vấn đề liên quan