Tôi nghĩ đoạn mã sau minh họa sự khác biệt một cách độc đáo: >>> np.vstack(([1,2,3],[4,5,6]))
array([[1, 2, 3],
[4, 5, 6]])
>>> np.column_stack(([1,2,3],[4,5,6]))
array([[1, 4],
[2, 5],
[3, 6]])
>>> np.hstack(([1,2,3],[4,5,6]))
array([1, 2, 3, 4, 5, 6])
Tôi cũng đã đưa vào hstack để so sánh. Lưu ý cách column_stack ngăn xếp dọc theo chiều thứ hai trong khi vstack ngăn xếp dọc theo chiều thứ nhất. Tương đương với column_stack là hstack lệnh sau : >>> np.hstack(([[1],[2],[3]],[[4],[5],[6]]))
array([[1, 4],
[2, 5],
[3, 6]])
Tôi hy vọng chúng ta có thể đồng ý rằng column_stack thuận tiện hơn. 103 hữu ích 0 bình luận chia sẻ Tôi chỉ muốn biết mình đã sai ở đâu. Có vẻ
như vstack chức năng sẽ hoạt động nhưng có lẽ tôi đang thiếu một cái gì đó.
TL; DR: Đó không phải vstack là vấn đề. Vấn đề là bạn có các đường dẫn mã cố gắng gán các loại mảng khác nhau cho cùng một biến (điều này ném ra ngoại lệ hợp nhất đó). Vấn đề nằm ở đây: # Populate a_mat and b_mat
if i == 0:
a_mat = a
b_mat = b
else:
a_mat = np.vstack((a_mat, a))
b_mat = np.vstack((b_mat, b))
Trong mã con đường đầu tiên bạn gán một c-contigous mảng float64 1d để a_mat và b_mat và trong else đó là một c tiếp giáp mảng float64 2d. Các loại này không tương thích và do đó numba tạo ra
lỗi. Đôi khi thật khó khăn khi mã numba không hoạt động như mã Python , nơi bạn có loại nào không quan trọng khi bạn gán một thứ gì đó cho một biến. Tuy nhiên trong các bản phát hành gần đây, các thông báo ngoại lệ numba đã tốt hơn rất nhiều, vì vậy nếu bạn biết ngoại lệ gợi ý gì, bạn có thể nhanh chóng tìm ra vấn đề là gì. Giải thích dài hơnVấn đề là numba suy diễn ngầm các loại biến của bạn. Ví dụ: from numba import njit
@njit
def func(arr):
a = arr
return a
Ở đây tôi chưa nhập hàm nên tôi cần chạy nó một
lần: >>> import numpy as np
>>> func(np.zeros(5))
array([0., 0., 0., 0., 0.])
Sau đó, bạn có thể kiểm tra các loại: >>> func.inspect_types()
func (array(float64, 1d, C),)
--------------------------------------------------------------------------------
# File: <ipython-input-4-02470248b065>
# --- LINE 3 ---
# label 0
@njit
# --- LINE 4 ---
def func(arr):
# --- LINE 5 ---
# arr = arg(0, name=arr) :: array(float64, 1d, C)
# a = arr :: array(float64, 1d, C)
# del arr
a = arr
# --- LINE 6 ---
# $0.3 = cast(value=a) :: array(float64, 1d, C)
# del a
# return $0.3
return a
Như bạn có thể thấy, biến a được nhập cho đầu vào có kiểu array(float64, 1d, C) là array(float64, 1d, C) . Bây giờ, hãy sử dụng np.vstack thay thế: from numba import njit
import numpy as np
@njit
def func(arr):
a = np.vstack((arr, arr))
return a
Và lệnh gọi đầu tiên bắt buộc để biên dịch nó: >>> func(np.zeros(5))
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
Sau đó kiểm tra lại các loại: func (array(float64, 1d, C),)
--------------------------------------------------------------------------------
# File: <ipython-input-11-f0214d5181c6>
# --- LINE 4 ---
# label 0
@njit
# --- LINE 5 ---
def func(arr):
# --- LINE 6 ---
# arr = arg(0, name=arr) :: array(float64, 1d, C)
# $0.1 = global(np: <module 'numpy'>) :: Module(<module 'numpy'>)
# $0.2 = getattr(value=$0.1, attr=vstack) :: Function(<function vstack at 0x000001DB7082A400>)
# del $0.1
# $0.5 = build_tuple(items=[Var(arr, <ipython-input-11-f0214d5181c6> (6)), Var(arr, <ipython-input-11-f0214d5181c6> (6))]) :: tuple(array(float64, 1d, C) x 2)
# del arr
# $0.6 = call $0.2($0.5, func=$0.2, args=[Var($0.5, <ipython-input-11-f0214d5181c6> (6))], kws=(), vararg=None) :: (tuple(array(float64, 1d, C) x 2),) -> array(float64, 2d, C)
# del $0.5
# del $0.2
# a = $0.6 :: array(float64, 2d, C)
# del $0.6
a = np.vstack((arr, arr))
# --- LINE 7 ---
# $0.8 = cast(value=a) :: array(float64, 2d, C)
# del a
# return $0.8
return a
Thời gian a này được nhập như array(float64, 2d, C) cho một đầu vào của array(float64, 1d, C) . Bạn có thể đã tự hỏi mình tại sao tôi lại nói về điều đó. Hãy xem điều gì sẽ xảy ra nếu bạn cố
gắng gán có điều kiện cho a : from numba import njit
import numpy as np
@njit
def func(arr, condition):
if condition:
a = np.vstack((arr, arr))
else:
a = arr
return a
Nếu bây giờ bạn chạy mã: >>> func(np.zeros(5), True)
TypingError: Failed at nopython (nopython frontend)
Cannot unify array(float64, 2d, C) and array(float64, 1d, C) for 'a', defined at <ipython-input-16-f4bd9a4f377a> (7)
File "<ipython-input-16-f4bd9a4f377a>", line 7:
def func(arr, condition):
<source elided>
if condition:
a = np.vstack((arr, arr))
^
[1] During: typing of assignment at <ipython-input-16-f4bd9a4f377a> (9)
File "<ipython-input-16-f4bd9a4f377a>", line 9:
def func(arr, condition):
<source elided>
else:
a = arr
^
Đó chính xác là vấn đề bạn gặp phải và đó là bởi vì các biến cần phải có một và chỉ một kiểu trong numba cho một tập hợp các kiểu đầu vào cố định . Và bởi vì loại dtype, thứ hạng (số thứ nguyên) và thuộc tính liền kề đều là một phần của kiểu nên bạn không thể gán các mảng có kích thước khác nhau cho cùng một biến. Lưu ý rằng bạn có thể mở rộng các kích thước để làm cho nó hoạt
động và ép lại các kích thước không cần thiết từ kết quả (có thể không đẹp lắm nhưng nó sẽ giải quyết được vấn đề với số lượng "thay đổi" tối thiểu: from numba import njit
import numpy as np
@njit
def func(arr, condition):
if condition:
a = np.vstack((arr, arr))
else:
a = np.expand_dims(arr, 0)
return a
>>> func(np.zeros(5), False)
array([[0., 0., 0., 0., 0.]]) # <-- 2d array!
>>> func(np.zeros(5), True)
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
13 hữu ích 1 bình luận chia sẻ
|