2010-09-29 29 views
5

phép nói rằng tôi có mảng:thế nào để làm phân tán/tập hợp các hoạt động trong NumPy

a = array((1,2,3,4,5)) 
indices = array((1,1,1,1)) 

và tôi thực hiện thao tác:

a[indices] += 1 

kết quả là

array([1, 3, 3, 4, 5]) 

nói cách khác , các bản sao trong số indices bị bỏ qua

nếu tôi muốn các bản sao không được bỏ qua, kết quả là:

array([1, 6, 3, 4, 5]) 

thế nào tôi sẽ đi về điều này?

ví dụ trên là hơi tầm thường, những gì sau là chính xác những gì tôi đang cố gắng để làm:

def inflate(self,pressure): 
    faceforces = pressure * cross(self.verts[self.faces[:,1]]-self.verts[self.faces[:,0]], self.verts[self.faces[:,2]]-self.verts[self.faces[:,0]]) 
    self.verts[self.faces[:,0]] += faceforces 
    self.verts[self.faces[:,1]] += faceforces 
    self.verts[self.faces[:,2]] += faceforces 

def constrain_lengths(self): 
    vectors = self.verts[self.constraints[:,1]] - self.verts[self.constraints[:,0]] 
    lengths = sqrt(sum(square(vectors), axis=1)) 
    correction = 0.5 * (vectors.T * (1 - (self.restlengths/lengths))).T 
    self.verts[self.constraints[:,0]] += correction 
    self.verts[self.constraints[:,1]] -= correction 

def compute_normals(self): 
    facenormals = cross(self.verts[self.faces[:,1]]-self.verts[self.faces[:,0]], self.verts[self.faces[:,2]]-self.verts[self.faces[:,0]]) 
    self.normals.fill(0) 
    self.normals[self.faces[:,0]] += facenormals 
    self.normals[self.faces[:,1]] += facenormals 
    self.normals[self.faces[:,2]] += facenormals 
    lengths = sqrt(sum(square(self.normals), axis=1)) 
    self.normals = (self.normals.T/lengths).T 

Ive đã nhận được một số kết quả rất buggy như một kết quả của bản sao bị bỏ qua trong các hoạt động chuyển nhượng được lập chỉ mục của tôi.

Trả lời

1

Tôi không biết một cách để làm điều đó có nghĩa là bất kỳ nhanh hơn:

for face in self.faces[:,0]: 
    self.verts[face] += faceforces 

Bạn cũng có thể làm cho self.faces vào một mảng của 3 từ điển nơi các phím tương ứng với khuôn mặt và giá trị số lần cần thêm. Sau đó, bạn sẽ nhận được mã như:

for face in self.faces[0]: 
    self.verts[face] += self.faces[0][face]*faceforces 

có thể nhanh hơn. Tôi hy vọng rằng một người nào đó đến với một cách tốt hơn bởi vì tôi muốn làm điều này khi cố gắng giúp một người nào đó tăng tốc mã của họ sớm hơn hôm nay.

4

numpy 's histogram là một hoạt động phân tán.

a += histogram(indices, bins=a.size, range=(0, a.size))[0]

Bạn có thể cần phải thực hiện một số dịch vụ chăm sóc bởi vì nếu indices chứa số nguyên, các lỗi làm tròn nhỏ có thể dẫn đến giá trị kết thúc trong xô sai. Trong trường hợp sử dụng:

a += histogram(indices, bins=a.size, range=(-0.5, a.size-0.5))[0]

để đưa mỗi chỉ mục vào giữa mỗi thùng.

Cập nhật: tính năng này hoạt động. Nhưng tôi khuyên bạn nên sử dụng câu trả lời của @Eelco Hoogendoorn dựa trên numpy.add.at.

2

Hơi muộn để đảng, nhưng nhìn thấy như thế nào thường hoạt động này là cần thiết, và thực tế là nó vẫn có vẻ không phải là một phần của NumPy tiêu chuẩn, bệnh đưa giải pháp của tôi ở đây để tham khảo:

def scatter(rowidx, vals, target): 
    """compute target[rowidx] += vals, allowing for repeated values in rowidx""" 
    rowidx = np.ravel(rowidx) 
    vals = np.ravel(vals) 
    cols = len(vals) 
    data = np.ones(cols) 
    colidx = np.arange(cols) 
    rows = len(target) 
    from scipy.sparse import coo_matrix 
    M = coo_matrix((data,(rowidx,colidx)), shape=(rows, cols)) 
    target += M*vals 
def gather(idx, vals): 
    """for symmetry with scatter""" 
    return vals[idx] 

Một thói quen C tùy chỉnh trong gọn gàng có thể dễ dàng gấp hai lần, loại bỏ sự phân bổ thừa và phép nhân với những cái bắt đầu, nhưng nó tạo ra một thế giới khác biệt về hiệu suất so với một vòng lặp trong python.

Ngoài những cân nhắc về hiệu suất, nó còn phong phú hơn nhiều so với mã vectơ được mã hóa khác để sử dụng hoạt động phân tán, thay vì kết hợp một số cho các vòng trong mã của bạn.

Chỉnh sửa:

Ok, hãy quên phần trên. Kể từ bản phát hành 1.8 mới nhất, việc thực hiện các hoạt động phân tán hiện được hỗ trợ trực tiếp bằng cách gọn gàng ở hiệu quả tối ưu.

def scatter(idx, vals, target): 
    """target[idx] += vals, but allowing for repeats in idx""" 
    np.add.at(target, idx.ravel(), vals.ravel()) 
Các vấn đề liên quan