2009-11-23 53 views
18

Trong tinh khiết Python bạn có thể phát triển ma trận cột theo cột khá dễ dàng:ma trận Trồng theo cột trong NumPy

mảng
data = [] 
for i in something: 
    newColumn = getColumnDataAsList(i) 
    data.append(newColumn) 

NumPy 's không có chức năng phụ thêm. Chức năng hstack không hoạt động trên zero kích thước mảng, do đó sau đây sẽ không hoạt động:

data = numpy.array([]) 
for i in something: 
    newColumn = getColumnDataAsNumpyArray(i) 
    data = numpy.hstack((data, newColumn)) # ValueError: arrays must have same number of dimensions 

Vì vậy, lựa chọn của tôi là một trong hai để loại bỏ các initalization iside vòng lặp với điều kiện thích hợp:

data = None 
for i in something: 
    newColumn = getColumnDataAsNumpyArray(i) 
    if data is None: 
     data = newColumn 
    else: 
     data = numpy.hstack((data, newColumn)) # works 

... hoặc sử dụng danh sách Python và chuyển đổi sau này thành mảng:

data = [] 
for i in something: 
    newColumn = getColumnDataAsNumpyArray(i) 
    data.append(newColumn) 
data = numpy.array(data) 

Cả hai biến thể có vẻ hơi khó xử. Có giải pháp đẹp hơn không?

Trả lời

18

NumPy thực sự không có một append chức năng, mà nó dường như có thể làm những gì bạn muốn, ví dụ:

import numpy as NP 
my_data = NP.random.random_integers(0, 9, 9).reshape(3, 3) 
new_col = NP.array((5, 5, 5)).reshape(3, 1) 
res = NP.append(my_data, new_col, axis=1) 

đoạn thứ hai của bạn (hstack) sẽ làm việc nếu bạn thêm một dòng khác, ví dụ như,

my_data = NP.random.random_integers(0, 9, 16).reshape(4, 4) 
# the line to add--does not depend on array dimensions 
new_col = NP.zeros_like(my_data[:,-1]).reshape(-1, 1) 
res = NP.hstack((my_data, new_col)) 

hstack g ives kết quả tương tự như concatenate((my_data, new_col), axis=1), tôi không chắc chắn làm thế nào họ so sánh hiệu suất khôn ngoan.


Trong khi đó là câu trả lời trực tiếp nhất cho câu hỏi của bạn, tôi nên đề cập đến rằng vòng lặp thông qua một nguồn dữ liệu để cư một mục tiêu thông qua thêm, trong khi chỉ tốt trong python, không phải là thành ngữ NumPy. Dưới đây là lý do:

khởi tạo một mảng NumPy là tương đối đắt tiền, và với mẫu python truyền thống này, bạn phải chịu chi phí đó, nhiều hơn hoặc ít hơn, tại mỗi lần lặp (ví dụ, mỗi thêm vào sau một mảng NumPy được xấp xỉ như khởi tạo một mảng mới có kích thước khác).

Vì lý do đó, mẫu chung trong NumPy để thêm lặp lại các cột vào mảng 2D là khởi tạo một mảng đích khi (hoặc phân bổ trước một mảng 2D NumPy có tất cả các cột trống) liền cư các cột trống bằng cách thiết lập mong muốn cột khôn ngoan bù đắp (index) - dễ dàng hơn để hiển thị hơn để giải thích:

>>> # initialize your skeleton array using 'empty' for lowest-memory footprint 
>>> M = NP.empty(shape=(10, 5), dtype=float) 

>>> # create a small function to mimic step-wise populating this empty 2D array: 
>>> fnx = lambda v : NP.random.randint(0, 10, v) 

cư mảng NumPy như trong OP, ngoại trừ mỗi lần lặp chỉ cần tái thiết lập các giá trị của M tại vị trí lệch cột liên tiếp

>>> for index, itm in enumerate(range(5)):  
     M[:,index] = fnx(10) 

>>> M 
    array([[ 1., 7., 0., 8., 7.], 
     [ 9., 0., 6., 9., 4.], 
     [ 2., 3., 6., 3., 4.], 
     [ 3., 4., 1., 0., 5.], 
     [ 2., 3., 5., 3., 0.], 
     [ 4., 6., 5., 6., 2.], 
     [ 0., 6., 1., 6., 8.], 
     [ 3., 8., 0., 8., 0.], 
     [ 5., 2., 5., 0., 1.], 
     [ 0., 6., 5., 9., 1.]]) 

tất nhiên nếu bạn không biết trước những gì kích thước mảng của bạn nên được chỉ cần tạo một lớn hơn nhiều hơn bạn cần và cắt các phần 'không sử dụng' khi bạn kết thúc Populating nó

>>> M[:3,:3] 
    array([[ 9., 3., 1.], 
     [ 9., 6., 8.], 
     [ 9., 7., 5.]]) 
+0

Bài đăng rất hữu ích cho người mới chơi. Câu hỏi nhanh: là có bất cứ lý do tại sao bạn sử dụng 'cho chỉ số, itm trong enumerate (phạm vi (5)): ' thay vì chỉ, ví dụ, ' cho x trong phạm vi (5):' xem như chỉ mục và itm có cùng giá trị và chỉ có một giá trị được sử dụng. –

+0

@ JohnBarça cảm ơn thông tin phản hồi. Bạn có thể đúng rằng các chi tiết của đoạn mã của tôi nên được lựa chọn cẩn thận hơn - ví dụ, trong ví dụ của tôi, giá trị của 'index' tại mỗi lần lặp lại thực sự giống như giá trị của biến vòng lặp. Mặc dù đó là một tạo phẩm - giá trị của hai biến này có thể không bằng nhau trong thực tế (ví dụ, iterable là một danh sách chứa các giá trị để chuyển tới một hàm tạo ra mảng 1D sau đó được chèn vào mảng đích). – doug

1

Nói chung là tốn kém để tiếp tục phân bổ lại mảng NumPy - vì vậy giải pháp thứ ba của bạn thực sự là hiệu suất tốt nhất khôn ngoan.

Tuy nhiên tôi nghĩ hstack sẽ làm những gì bạn muốn - những gợi ý là trong thông báo lỗi,

ValueError: arrays must have same number of dimensions`

Tôi đoán rằng newColumn có hai kích thước (chứ không phải là một vector 1D), vì vậy bạn cần dữ liệu cũng có hai kích thước ..., ví dụ: data = np.array([[]]) - hoặc cách khác làm cho cột mới là véc tơ 1D (thường nếu mọi thứ là 1D thì tốt hơn là giữ chúng 1D trong NumPy, vì vậy việc phát sóng, v.v. hoạt động tốt hơn). trong trường hợp này, hãy sử dụng np.squeeze(newColumn)hstack hoặc vstack sẽ hoạt động với định nghĩa dữ liệu ban đầu của bạn.

4

Thông thường bạn không tiếp tục đổi kích thước mảng NumPy khi tạo. Những gì bạn không thích về giải pháp thứ ba của bạn? Nếu đó là một ma trận rất lớn/mảng, sau đó nó có thể là giá trị phân bổ mảng trước khi bạn bắt đầu gán giá trị của nó:

x = len(something) 
y = getColumnDataAsNumpyArray.someLengthProperty 

data = numpy.zeros((x,y)) 
for i in something: 
    data[i] = getColumnDataAsNumpyArray(i) 
3

Các hstack có thể hoạt động trên các mảng có kích thước bằng không:

import numpy as np 

N = 5 
M = 15 

a = np.ndarray(shape = (N, 0)) 
for i in range(M): 
    b = np.random.rand(N, 1) 
    a = np.hstack((a, b)) 
Các vấn đề liên quan