2016-04-15 16 views
8

Tôi có hai mảng kết xuất 2D (được đơn giản hóa trong ví dụ này về kích thước và nội dung) với kích thước giống nhau. ma trậnTổng hợp dữ liệu từ mảng dựa trên mảng khác trong Numpy

Một ID:

1 1 1 2 2 
1 1 2 2 5 
1 1 2 5 5 
1 2 2 5 5 
2 2 5 5 5 

và một ma trận giá trị:

14.8 17.0 74.3 40.3 90.2 
25.2 75.9 5.6 40.0 33.7 
78.9 39.3 11.3 63.6 56.7 
11.4 75.7 78.4 88.7 58.6 
79.6 32.3 35.3 52.5 13.3 

Mục tiêu của tôi là để đếmtổng các giá trị từ các ma trận thứ hai được phân nhóm theo các ID từ ma trận đầu tiên:

1: (8, 336.8) 
2: (9, 453.4) 
5: (8, 402.4) 

Tôi có thể làm điều này trong một vòng lặp for nhưng khi ma trận có kích thước bằng hàng nghìn thay vì chỉ 5x5 và hàng nghìn ID duy nhất, phải mất rất nhiều thời gian để xử lý.

numpy có phương pháp thông minh hoặc kết hợp các phương pháp để thực hiện việc này không?

Trả lời

5

Dưới đây là một cách tiếp cận vectorized để có được tính cho IDID-based giá trị tóm tắt cho value với sự kết hợp của np.uniquenp.bincount -

unqID,idx,IDsums = np.unique(ID,return_counts=True,return_inverse=True) 

value_sums = np.bincount(idx,value.ravel()) 

Để có được kết quả cuối cùng như một cuốn từ điển, bạn có thể sử dụng vòng lặp-hiểu để thu thập các giá trị tóm tắt, như vậy -

{i:(IDsums[itr],value_sums[itr]) for itr,i in enumerate(unqID)} 

mẫu chạy -

In [86]: ID 
Out[86]: 
array([[1, 1, 1, 2, 2], 
     [1, 1, 2, 2, 5], 
     [1, 1, 2, 5, 5], 
     [1, 2, 2, 5, 5], 
     [2, 2, 5, 5, 5]]) 

In [87]: value 
Out[87]: 
array([[ 14.8, 17. , 74.3, 40.3, 90.2], 
     [ 25.2, 75.9, 5.6, 40. , 33.7], 
     [ 78.9, 39.3, 11.3, 63.6, 56.7], 
     [ 11.4, 75.7, 78.4, 88.7, 58.6], 
     [ 79.6, 32.3, 35.3, 52.5, 13.3]]) 

In [88]: unqID,idx,IDsums = np.unique(ID,return_counts=True,return_inverse=True) 
    ...: value_sums = np.bincount(idx,value.ravel()) 
    ...: 

In [89]: {i:(IDsums[itr],value_sums[itr]) for itr,i in enumerate(unqID)} 
Out[89]: 
{1: (8, 336.80000000000001), 
2: (9, 453.40000000000003), 
5: (8, 402.40000000000003)} 
+1

Đẹp nhất! Tôi không biết các đối số 'return_ *' cho 'np.unique'. – kazemakase

+1

@Divakar: Cảm ơn bạn! Đây chính xác là loại giải pháp mà tôi đang tìm kiếm với một hiệu suất tốt do sự vectơ hóa. – Chau

1

này có thể với sự kết hợp của một vài phương pháp đơn giản:

  1. sử dụng numpy.unique để tìm mỗi ID
  2. tạo ra một mặt nạ boolean cho mỗi ID
  3. tổng 1s trong mặt nạ (count) và các giá trị mà mặt nạ là 1

này có thể trông như thế này:

import numpy as np 

ids = np.array([[1, 1, 1, 2, 2], 
       [1, 1, 2, 2, 5], 
       [1, 1, 2, 5, 5], 
       [1, 2, 2, 5, 5], 
       [2, 2, 5, 5, 5]]) 

values = np.array([[14.8, 17.0, 74.3, 40.3, 90.2], 
        [25.2, 75.9, 5.6, 40.0, 33.7], 
        [78.9, 39.3, 11.3, 63.6, 56.7], 
        [11.4, 75.7, 78.4, 88.7, 58.6], 
        [79.6, 32.3, 35.3, 52.5, 13.3]]) 


for i in np.unique(ids): # loop through all IDs 
    mask = ids == i # find entries that match current ID 
    count = np.sum(mask) # number of matches 
    total = np.sum(values[mask]) # values of matches 
    print('{}: ({}, {:.1f})'.format(i, count, total)) #print result 

# Output: 
# 1: (8, 336.8) 
# 2: (9, 453.4) 
# 5: (8, 402.4) 
+0

Đó chính xác là vòng lặp 'for' khó chịu mà tôi đang đề cập đến trong câu hỏi của mình, tôi nên rõ ràng hơn về điều đó. – Chau

+0

Tôi nghĩ rằng không thực sự là một cách succint làm mà không có vòng lặp for. Nó có thể là có thể, nhưng có thể sẽ dẫn đến mã rất khó đọc. Nếu bạn chỉ có một vài ID duy nhất thì không nên có quá nhiều lần thực hiện bởi vòng lặp for. Dù sao, tôi sẽ suy nghĩ về nó trong một thời gian ... – kazemakase

+0

Hình như tôi đã được chứng minh là sai trong câu trả lời của [Divakar] (http: // stackoverflow.com/a/36643601/3005167). – kazemakase

0

Gói numpy_indexed (từ chối trách nhiệm: Tôi là tác giả của nó) có chức năng để giải quyết các loại vấn đề một cách thanh lịch và vectorized:

import numpy_indexed as npi 
group_by = npi.group_by(ID.flatten()) 
ID_unique, value_sums = group_by.sum(value.flatten()) 
ID_count = groupy_by.count  

Lưu ý: nếu bạn muốn tính tổng và đếm trong để tính giá trị trung bình, cũng có group_by.mean; cộng với rất nhiều chức năng hữu ích khác.

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