我經常使用 numpy 撰寫方程,將標量作為輸入并回傳另一個標量或向量。后來我發現我想做同樣的事情,但用一個或多個向量作為輸入。我試圖找出一種方法,使一個函式在兩種情況下都能正常作業,而無需添加各種 if 測驗呼叫np.isscalar()或np.atleast1d()(除非這是唯一的方法)。
是否可以僅使用一個函式來處理標量和向量輸入,或者我是否堅持使用多種實作?
例如,這里有一些函式可以將 x、y 角度轉換為北、東、下單位向量(假設角度已經以弧度表示)。我已經包含了一個標量版本、矢量化版本和一個np.meshgrid()用于呼叫標量版本的版本。我試圖避免顯式回圈或呼叫np.vectorize().
標量示例
import numpy as np
def xy_to_nez_scalar(x, y):
n = np.sin(y)
e = np.sin(x) * np.cos(y)
z = np.cos(x) * np.cos(y)
return np.array([n, e, z])
x = 1
y = 1
nez1 = xy_to_nez_scalar(x, y)
print(f'{nez1=}')
print(f'{nez1.shape=}\n')
生產
nez1=array([0.84147098, 0.45464871, 0.29192658])
nez1.shape=(3,)
矢量化示例
# X and Y are arrays, so we'll follow the convention that X
# is a column of N rows and Y is a row of M columns. Then we would
# return an array of shape (N, M, 3).
def xy_to_nez_vector(x, y):
n = np.sin(y)
e = np.sin(x[:, np.newaxis]) * np.cos(y)
z = np.cos(x[:, np.newaxis]) * np.cos(y)
# make sure n has the same shape as e and z
nn = np.broadcast_to(n, e.shape)
nez = np.stack([nn, e, z], axis=-1)
return nez
x_array = np.arange(4)
y_array = np.arange(2)
nez2 = xy_to_nez_vector(x_array, y_array)
print(f'{nez2=}')
print(f'{nez2.shape=}\n')
生產
nez2=array([[[ 0. , 0. , 1. ],
[ 0.84147098, 0. , 0.54030231]],
[[ 0. , 0.84147098, 0.54030231],
[ 0.84147098, 0.45464871, 0.29192658]],
[[ 0. , 0.90929743, -0.41614684],
[ 0.84147098, 0.4912955 , -0.2248451 ]],
[[ 0. , 0.14112001, -0.9899925 ],
[ 0.84147098, 0.07624747, -0.53489523]]])
nez2.shape=(4, 2, 3)
網格示例
# note this produces a (3, M, N) result.
xv, yv = np.meshgrid(x_array, y_array)
nez3 = xy_to_nez_scalar(xv, yv)
print(f'{nez3=}')
print(f'{nez3.shape=}\n')
# fix things by transposing.
nez4 = nez3.T
print(f'{nez4=}')
print(f'{nez4.shape=}\n')
print(np.allclose(nez2, nez4))
生產
nez3=array([[[ 0. , 0. , 0. , 0. ],
[ 0.84147098, 0.84147098, 0.84147098, 0.84147098]],
[[ 0. , 0.84147098, 0.90929743, 0.14112001],
[ 0. , 0.45464871, 0.4912955 , 0.07624747]],
[[ 1. , 0.54030231, -0.41614684, -0.9899925 ],
[ 0.54030231, 0.29192658, -0.2248451 , -0.53489523]]])
nez3.shape=(3, 2, 4)
nez4=array([[[ 0. , 0. , 1. ],
[ 0.84147098, 0. , 0.54030231]],
[[ 0. , 0.84147098, 0.54030231],
[ 0.84147098, 0.45464871, 0.29192658]],
[[ 0. , 0.90929743, -0.41614684],
[ 0.84147098, 0.4912955 , -0.2248451 ]],
[[ 0. , 0.14112001, -0.9899925 ],
[ 0.84147098, 0.07624747, -0.53489523]]])
nez4.shape=(4, 2, 3)
True
uj5u.com熱心網友回復:
這可能與框架挑戰接壤,但我建議稍微改變你的實作理念,以符合大多數 numpy 函式已經做的事情。這有兩個優點:(1) 有經驗的 numpy 用戶會知道對你的函式有什么期望,(2) 標量向量問題消失了。
通常,如果面對像 的函式xy_to_nez(x, y),我希望它采用陣列x和y,并回傳具有兩者廣播形狀的東西,其中 3 作為第一個或最后一個維度。將 3 放在最后一個維度的選擇在這里完全沒問題。然而,將陣列神奇地網格化在一起而不是廣播它們是一件相當非 num-pythonic 的事情。
讓用戶明確地告訴你你想要什么(python 的核心原則,第 2 項import this)。例如,給定上面建議的廣播介面,您的標量函式就快完成了。您需要進行的唯一更改是沿最后一個軸而不是第一個軸堆疊,如下所示np.array:
def xy_to_nez(x, y):
n = np.sin(y)
e = np.sin(x) * np.cos(y)
z = np.cos(x) * np.cos(y)
return np.stack(np.broadcast_arrays(n, e, z), -1)
我希望以下三個示例可以作為nez1,nez2和nez4:
>>> xy_to_nez(1, 1) # shape: 3
array([0.84147098, 0.45464871, 0.29192658])
>>> xy_to_nez(np.arange(4)[:, None], np.arange(2)) # shape: 4, 2
array([[[ 0. , 0. , 1. ],
[ 0.84147098, 0. , 0.54030231]],
[[ 0. , 0.84147098, 0.54030231],
[ 0.84147098, 0.45464871, 0.29192658]],
[[ 0. , 0.90929743, -0.41614684],
[ 0.84147098, 0.4912955 , -0.2248451 ]],
[[ 0. , 0.14112001, -0.9899925 ],
[ 0.84147098, 0.07624747, -0.53489523]]])
>>> xy_to_nez(*np.meshgrid(np.arange(4), np.arange(2), indexing='ij'))
array([[[ 0. , 0. , 1. ],
[ 0.84147098, 0. , 0.54030231]],
[[ 0. , 0.84147098, 0.54030231],
[ 0.84147098, 0.45464871, 0.29192658]],
[[ 0. , 0.90929743, -0.41614684],
[ 0.84147098, 0.4912955 , -0.2248451 ]],
[[ 0. , 0.14112001, -0.9899925 ],
[ 0.84147098, 0.07624747, -0.53489523]]])
在第三個示例中,我nez3通過傳遞indexing='ij'給np.meshgrid. 問題不在于矢量化,而在于您傳入的網格的形狀。
我根本不希望xy_to_nez(np.arange(4), np.arange(2))作業:陣列不會一起廣播,我們不應該試圖弄清楚如何組合它們。要了解原因,假設它們每個都有三個隨機維度。你交錯嗎?您是否將一組依次放置?如果某些維度廣播但其他維度不廣播怎么辦?將這些問題排除在考慮范圍之外,由用戶來決定。
同時:
>>> xy_to_nez(np.arange(4), np.arange(4)) # Shape: 4, 3
array([[ 0. , 0. , 1. ],
[ 0.84147098, 0.45464871, 0.29192658],
[ 0.90929743, -0.37840125, 0.17317819],
[ 0.14112001, -0.13970775, 0.98008514]])
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/355121.html
標籤:Python 麻木的 numpy-ndarray 阵列广播
下一篇:如何在回圈內正確解決這個問題?
