2010-05-02 23 views
5

Tôi binning một mảng 2ngày (x bởi y) trong Python vào thùng của giá trị x của nó (được đưa ra trong "thùng"), sử dụng np.digitize:cách tiếp cận vectorized để binning với NumPy/scipy bằng Python

elements_to_bins = digitize(vals, bins) 

nơi "Vals" là một mảng 2d, ví dụ:

vals = array([[1, v1], [2, v2], ...]). 

elements_to_bins chỉ nói những gì bin mỗi phần tử rơi vào. Những gì tôi muốn làm là lấy danh sách có chiều dài là số lượng thùng trong "thùng", và mỗi phần tử trả về giá trị y của "vals" rơi vào thùng đó. Tôi làm theo cách này ngay bây giờ:

points_by_bins = [] 
for curr_bin in range(min(elements_to_bins), max(elements_to_bins) + 1): 
    curr_indx = where(elements_to_bins == curr_bin)[0] 
    curr_bin_vals = vals[:, curr_indx] 
    points_by_bins.append(curr_bin_vals) 

là có cách nào thanh lịch/đơn giản hơn để thực hiện việc này? Tất cả những gì tôi cần là danh sách các danh sách các giá trị y rơi vào mỗi thùng.

cảm ơn.

+0

Nếu một trong những câu trả lời đã giải quyết được vấn đề của bạn, hãy đánh dấu nó là được chấp nhận (dấu kiểm màu xanh lục)! :) – EOL

Trả lời

3

Nếu tôi hiểu câu hỏi của bạn một cách chính xác:

vals = array([[1, 10], [1, 11], [2, 20], [2, 21], [2, 22]]) # Example 

(x, y) = vals.T # Shortcut 
bin_limits = range(min(x)+1, max(x)+2) # Other limits could be chosen 
points_by_bin = [ [] for _ in bin_limits ] # Final result 
for (bin_num, y_value) in zip(searchsorted(bin_limits, x, "right"), y): # digitize() finds the correct bin number 
    points_by_bin[bin_num].append(y_value) 

print points_by_bin # [[10, 11], [20, 21, 22]] 

NumPy của nhanh mảng hoạt động searchsorted() được sử dụng cho hiệu quả tối đa. Giá trị sau đó được thêm vào từng cái một (vì kết quả cuối cùng không phải là một mảng hình chữ nhật, Numpy không thể giúp ích gì nhiều cho việc này). Giải pháp này phải nhanh hơn nhiều cuộc gọi where() trong một vòng lặp, điều này buộc Numpy phải đọc lại cùng một mảng nhiều lần.

+1

numpy.searchsorted nên được ưu tiên số hóa bởi các lý do hiệu suất: https://github.com/numpy/numpy/issues/2656 – Alleo

+0

@Alleo: Điểm rất tốt (để thực hiện hiện tại 'số hóa()'). Tôi đã cập nhật câu trả lời. – EOL

0

Các khóa bin chỉ là số nguyên, không có số lần quay, như trong ví dụ của bạn? Sau đó, bạn chỉ có thể làm được điều này, mà không NumPy:

from collections import defaultdict 
bins = defaultdict(list) # or [ [] ...] as in EOL 

vals = [[1, 10], [1, 11], [2, 20], [2, 21], [2, 22]] # nparray.tolist() 
for nbin, val in vals: 
    bins[nbin].append(val) 

print "bins:", bins 
# defaultdict(<type 'list'>, {1: [10, 11], 2: [20, 21, 22]}) 
+0

+1: điều này có vẻ tốt với tôi, ngoại trừ có thể cho một thực tế rằng thùng rỗng không chứa danh sách trống (có thể được cố định với một defaultdict). Tuy nhiên, có thể áp phích ban đầu có nhiều thùng chung hơn trong tâm trí? – EOL

1

này sẽ trả về một cấu trúc dữ liệu tương tự như Reverse_Indices IDL histogram của:

ovec = np.argsort(vals) 
ivec = np.searchsorted(vals, bin_limits, sorter=ovec) 

Sau đó, danh sách các yếu tố mà rơi vào bin #I là

ovec[ ivec[i] : ivec[i+1] ] 

(kiểm tra tính thời gian nhanh của tôi cho biết nhanh hơn thuật toán của EOL 5x, vì nó không làm phiền tạo danh sách có kích thước khác)

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