2010-07-14 25 views
39

Giả sử tôi có mảng thưa thớt 2d. Trong usecase thật của tôi cả số lượng hàng và cột là lớn hơn nhiều (nói 20000 và 50000) do đó nó không thể phù hợp trong bộ nhớ khi một đại diện dày đặc được sử dụng:Làm thế nào để nhân một ma trận scipy.sparse một cách yếu tố bằng một mảng dày đặc 1d được phát sóng?

>>> import numpy as np 
>>> import scipy.sparse as ssp 

>>> a = ssp.lil_matrix((5, 3)) 
>>> a[1, 2] = -1 
>>> a[4, 1] = 2 
>>> a.todense() 
matrix([[ 0., 0., 0.], 
     [ 0., 0., -1.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 2., 0.]]) 

Bây giờ giả sử tôi có một mảng 1d dày đặc với tất cả thành phần không số không với kích thước 3 (hoặc 50000 trong trường hợp thực tế cuộc sống của tôi):

>>> d = np.ones(3) * 3 
>>> d 
array([ 3., 3., 3.]) 

tôi muốn tính toán nhân elementwise của a và d bằng cách sử dụng ngữ nghĩa phát thanh truyền hình thông thường của numPy. Tuy nhiên, các ma trận thưa thớt trong scipy là của np.matrix: các '*' điều hành bị quá tải để có nó cư xử giống như một ma trận nhân thay vì elementwise-nhân:

>>> a * d 
array([ 0., -3., 0., 0., 6.]) 

Một giải pháp sẽ được thực hiện ' một' chuyển sang ngữ nghĩa mảng cho '*' nhà điều hành, mà sẽ cung cấp cho các kết quả mong đợi:

>>> a.toarray() * d 
array([[ 0., 0., 0.], 
     [ 0., 0., -3.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 6., 0.]]) 

Nhưng tôi không thể làm điều đó kể từ khi cuộc gọi đến toArray() sẽ thực hóa các phiên bản dày đặc của 'a' mà không vừa trong bộ nhớ (và kết quả sẽ dày đặc quá):

>>> ssp.issparse(a.toarray()) 
False 

Bất kỳ ý tưởng làm thế nào để xây dựng này trong khi chỉ giữ cơ sở dữ liệu thưa thớt và không cần phải làm một vòng python không hiệu quả trên các cột của 'a'?

+0

Nếu 'd' là ma trận thưa thớt có cùng kích thước với' a' bạn có thể sử dụng 'a.multiply (d)'. Có lẽ bạn có thể tạo một 'd' là N hàng dài và lặp qua N hàng của' một' tại một thời điểm? – mtrw

+1

Nhưng d là dày đặc và không thể được phát sóng rõ ràng trong bộ nhớ để đáp ứng các yêu cầu hình dạng nhân. Looping trên một lô là một lựa chọn nhưng tôi thấy điều này một chút hackish. Tôi đã có thể nghĩ rằng có một vani vectorized/scipy cách để làm điều này mà không có một vòng python. – ogrisel

+0

Tôi đoán vấn đề là bạn muốn đại diện cho một ma trận (thưa thớt) nhưng hoạt động mulitply của một mảng. Tôi nghĩ rằng bạn sẽ phải cuộn của riêng bạn không may. – mtrw

Trả lời

42

Tôi cũng trả lời tại scipy.org, nhưng tôi nghĩ tôi nên thêm câu trả lời ở đây, trong trường hợp những người khác tìm thấy trang này khi tìm kiếm.

Bạn có thể biến véc tơ thành ma trận đường chéo thưa và sau đó sử dụng phép nhân ma trận (với *) để thực hiện tương tự như phát sóng, nhưng hiệu quả.

>>> d = ssp.lil_matrix((3,3)) 
>>> d.setdiag(np.ones(3)*3) 
>>> a*d 
<5x3 sparse matrix of type '<type 'numpy.float64'>' 
with 2 stored elements in Compressed Sparse Row format> 
>>> (a*d).todense() 
matrix([[ 0., 0., 0.], 
     [ 0., 0., -3.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 6., 0.]]) 

Hy vọng điều đó sẽ hữu ích!

+0

Cảm ơn có vẻ như nó sẽ giải quyết được vấn đề của tôi. – ogrisel

+0

Điều tuyệt vời về điều này là nó cũng hoạt động khi 'X' là một' ndarray' hoặc một ma trận dày đặc. +1. –

+4

Điều này có thể được đơn giản hơn nữa bằng cách sử dụng ['scipy.sparse.diags (d, 0)'] (http://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.sparse.diags. html) thay vì 'lil_matrix' –

1

Vâng, đây là một mã đơn giản sẽ làm những gì bạn muốn. Tôi không biết nếu nó là hiệu quả như bạn mong muốn, vì vậy mang nó hoặc để lại nó:

import scipy.sparse as ssp 
def pointmult(a,b): 
    x = a.copy() 
    for i in xrange(a.shape[0]): 
     if x.data[i]: 
      for j in xrange(len(x.data[i])): 
       x.data[i] *= b[x.rows[i]] 
    return x 

Nó chỉ làm việc với ma trận lil vì vậy bạn sẽ cần phải thực hiện một số thay đổi nếu bạn muốn nó để làm việc với các định dạng khác.

+0

cảm ơn tôi đã có thể muốn tránh cho các vòng trong python tuy nhiên.Nhưng có lẽ không có cách nào với các lớp scipy.sparse hiện tại cho trường hợp sử dụng này. – ogrisel

23

Tôi nghĩ rằng A.multiply (B) nên hoạt động trong scipy thưa thớt. Phương thức nhân nhân làm phép nhân "điểm-khôn ngoan", chứ không phải nhân ma trận.

HTH

+1

Kết quả là một ma trận dày đặc. Không tốt. –

+3

@ K3 --- rnc kết quả chỉ dày đặc nếu B dày đặc. Nếu bạn chuyển đổi B thành bất kỳ định dạng thưa thớt nào, nó sẽ thực hiện thủ thuật. Ví dụ. A.multiply (csc_matrix (B)) – markhor

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