有沒有辦法在運行時確定函數是否需要numpy.vectorize()才能像預期的那樣工作?如何確定是否需要numpy.vectorize()?
對於背景,我問這是因爲我在程序中使用Numpy來根據文獻中提供的熱力學函數計算相圖(基於CALPHAD)。對於給定的溫度,人們評估自由能函數並確定接觸凹面(二階導數> 0)的公共切線曲線以定義相位共存的組成範圍。爲此,直接定義二階導函數是很好的。在我試圖用一個簡單的拋物線自由enrgy進行測試之前,所有的實驗自由能函數都很好(不難得到它的衍生物),它有一個常數二階導數。這使我的算法崩潰了,因爲我沒有預料到numpy廣播會在函數內部尋找並決定它不需要廣播。
困難歸結爲這種行爲:
import numpy as np
def f(x):
return(x*x)
def g(x):
return(3.0)
def h(x):
return(0*x+3.0)
def i(x):
return(x-x+3.0)
x = np.linspace(1.0, 5.0, 5)
在這些輸出中IPython的運行3.3.2結果:
F(X) - > 陣列([ (x) - > 3.0(注意只有1個元素) - 我期望的
g(x) - > 3.0 (不是天真的) - 不是天真的預期
h(x) - > array([3.,3.,3.,3.,3.]) - OK,愚弄了(x)→ array([3.,3.,3.,3.,3.]) - 與h(x)相同,但避免乘舍入問題
現在我可以用
gv = np.vectorize(g)
並獲得
GV(x)的 - >陣列([3,3,3,3,3]) - 預期行爲
如果我的程序是(最終)接受任意用戶輸入的自由能函數,這將導致問題,除非所有用戶都理解numpy內部廣播魔術。或者,我可以自反地np.vectorize一切,以防止這種情況。如果函數在numpy中「正常工作」,問題是成本。
也就是說,使用IPython的timeit%,
h(x) -> 100000 loops, best of 3: 3.45 µs per loop
如果我向量化H(X)不必要的(即HV = np.vectorize(H)),我得到
hv(x) -> 10000 loops, best of 3: 43.2 µs per loop
所以,不必要的矢量化是一個巨大的懲罰(對於5個函數實例,40微秒)。
我想我可以對評估在小ndarray以查看是否返回類型是陣列或浮子上的函數的返回初始測試,然後定義一個新的功能,如果它是浮動,如:
def gv(x):
return(g(x)+0.0*x)
這看起來像一個可怕的kludge。
所以 - 在這種情況下是否有更好的方法來'欺騙'numpy成有效的廣播?
您可以檢查'g(x)'返回的值的形狀,並根據需要進行廣播。 'numpy'(和MATLAB)函數按摩輸入以將它們放入最佳形狀進行計算並不常見,然後進一步重塑輸出以匹配輸入形狀。例如看看'np.vectorize'的內部。 – hpaulj
你爲什麼要使用numpy.vectorize?我假設你想做f(x)+ g(x)左右?但是當f(x)返回一個numpy.ndarray並且g(x)返回一個浮點數時,這也會起作用。 – usethedeathstar
一般來說,我不想使用vectorize()。問題出現是因爲如果x是一個ndarray,y = f(x)返回一個ndarray,但y = g(x)返回一個單獨的float值,而不是len(x)的數組。因此,如果試圖編寫一個庫來處理函數,那麼當你沒有得到期望的數組時,最終可能會得到不尋常的結果。 numpy.vectorize()只是讓它起作用的雜湊。 –