Hướng dẫn dùng np.vstack python

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_stackngăn xếp dọc theo chiều thứ hai trong khi vstackngăn xếp dọc theo chiều thứ nhất. Tương đương với column_stackhstacklệ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_stackthuậ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ư vstackchứ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 vstacklà 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_matb_matvà 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ơn

Vấ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: 
# --- 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)array(float64, 1d, C).

Bây giờ, hãy sử dụng np.vstackthay 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: 
# --- 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()
    #   $0.2 = getattr(value=$0.1, attr=vstack)  :: Function()
    #   del $0.1
    #   $0.5 = build_tuple(items=[Var(arr,  (6)), Var(arr,  (6))])  :: tuple(array(float64, 1d, C) x 2)
    #   del arr
    #   $0.6 = call $0.2($0.5, func=$0.2, args=[Var($0.5,  (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 anà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  (7)

File "", line 7:
def func(arr, condition):
    
    if condition:
        a = np.vstack((arr, arr))
        ^

[1] During: typing of assignment at  (9)

File "", line 9:
def func(arr, condition):
    
    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ẻ