2011-02-18 46 views
7

Tôi có một mảng NumPy lớn:NumPy Lookup (Bản đồ, hoặc Point)

array([[32, 32, 99, 9, 45], # A 
     [99, 45, 9, 45, 32], 
     [45, 45, 99, 99, 32], 
     [ 9, 9, 32, 45, 99]]) 

và một mảng lớn ish các giá trị duy nhất trong một thứ tự cụ thể:

array([ 99, 32, 45, 9])  # B 

Làm thế nào tôi có thể nhanh chóng (không có từ điển python, không có bản sao của A, không có vòng python) thay thế các giá trị trong A để trở thành chỉ báo của các giá trị trong B?:

array([[1, 1, 0, 3, 2], 
     [0, 2, 3, 2, 1], 
     [2, 2, 0, 0, 1], 
     [3, 3, 1, 2, 0]]) 

Tôi cảm thấy ngớ ngẩn vì không thể làm điều này trên đầu của tôi, cũng không tìm thấy nó trong tài liệu. Điểm dễ dàng!

Trả lời

6

Ở đây bạn đi

A = array([[32, 32, 99, 9, 45], # A 
    [99, 45, 9, 45, 32], 
    [45, 45, 99, 99, 32], 
    [ 9, 9, 32, 45, 99]]) 

B = array([ 99, 32, 45, 9]) 

ii = np.argsort(B) 
C = np.digitize(A.reshape(-1,),np.sort(B)) - 1 

Nguyên tôi đề nghị:

D = np.choose(C,ii).reshape(A.shape) 

Nhưng tôi nhận ra rằng có những hạn chế khi bạn đi đến mảng lớn hơn. Thay vào đó, vay từ @ unutbu là câu trả lời thông minh:

D = np.argsort(B)[C].reshape(A.shape) 

Hoặc một liner

np.argsort(B)[np.digitize(A.reshape(-1,),np.sort(B)) - 1].reshape(A.shape) 

Mà tôi tìm thấy là nhanh hay chậm hơn so với mã @ unutbu của tùy thuộc vào kích thước của mảng được xem xét và số lượng giá trị duy nhất.

+0

Giải pháp này thực hiện tương đối nhanh hơn cho use-case của tôi (B.size << A.size), nhưng đối với hồ sơ, giải pháp @ unutbu dường như có hiệu suất chung tốt hơn. Không, tuy nhiên là một giải pháp "tại chỗ" mà tôi có thể chỉ ám chỉ mong muốn khi tôi nói "thay thế các giá trị trong' A'. " ..mà tôi không nghĩ là có thể mà không có Cython. Cảm ơn cả hai! – Paul

+0

Tôi cũng tìm thấy giải pháp của unutbu thường nhanh hơn trừ khi B.size << A.size. Thật vui khi thấy nhiều giải pháp và tinker với tối ưu hóa – JoshAdel

7
import numpy as np 
A=np.array([[32, 32, 99, 9, 45], 
      [99, 45, 9, 45, 32], 
      [45, 45, 99, 99, 32], 
      [ 9, 9, 32, 45, 99]]) 

B=np.array([ 99, 32, 45, 9]) 

cutoffs=np.sort(B) 
print(cutoffs) 
# [ 9 32 45 99] 

index=cutoffs.searchsorted(A) 
print(index) 
# [[1 1 3 0 2] 
# [3 2 0 2 1] 
# [2 2 3 3 1] 
# [0 0 1 2 3]]  

index lưu các chỉ mục vào mảng cắt liên kết với từng phần tử A. Lưu ý rằng chúng tôi phải sắp xếp B kể từ khi np.searchsorted mong đợi một mảng được sắp xếp.

index là hầu hết các câu trả lời mong muốn, ngoại trừ việc chúng tôi muốn để lập bản đồ

1-->1 
3-->0 
0-->3 
2-->2 

np.argsort cho chúng ta bản đồ này:

print(np.argsort(B)) 
# [3 1 2 0] 
print(np.argsort(B)[1]) 
# 1 
print(np.argsort(B)[3]) 
# 0 
print(np.argsort(B)[0]) 
# 3 
print(np.argsort(B)[2]) 
# 2 

print(np.argsort(B)[index]) 
# [[1 1 0 3 2] 
# [0 2 3 2 1] 
# [2 2 0 0 1] 
# [3 3 1 2 0]] 

Vì vậy, như một lớp lót, câu trả lời là:

np.argsort(B)[np.sort(B).searchsorted(A)] 

Gọi cả hai np.sort(B)np.argsort(B) không hiệu quả do cả hai thao tác cần phân loại B. Đối với bất kỳ 1D-mảng B,

np.sort(B) == B[np.argsort(B)] 

Vì vậy, chúng ta có thể tính toán kết quả mong muốn nhanh hơn một chút bằng

key=np.argsort(B) 
result=key[B[key].searchsorted(A)]