[英]Calculating Slopes in Numpy (or Scipy)
我試圖找到使用 Numpy 和 Scipy 計算斜率的最快和最有效的方法。 我有一個包含三個 Y 變量和一個 X 變量的數據集,我需要計算它們各自的斜率。 例如,我可以輕松地一次完成這一行,如下所示,但我希望有一種更有效的方法來做到這一點。 我也不認為 linregress 是最好的方法,因為我的結果中不需要任何輔助變量,如截距、標准錯誤等。 任何幫助是極大的贊賞。
import numpy as np
from scipy import stats
Y = [[ 2.62710000e+11 3.14454000e+11 3.63609000e+11 4.03196000e+11
4.21725000e+11 2.86698000e+11 3.32909000e+11 4.01480000e+11
4.21215000e+11 4.81202000e+11]
[ 3.11612352e+03 3.65968334e+03 4.15442691e+03 4.52470938e+03
4.65011423e+03 3.10707392e+03 3.54692896e+03 4.20656404e+03
4.34233412e+03 4.88462501e+03]
[ 2.21536396e+01 2.59098311e+01 2.97401268e+01 3.04784552e+01
3.13667639e+01 2.76377113e+01 3.27846013e+01 3.73223417e+01
3.51249997e+01 4.42563658e+01]]
X = [ 1990. 1991. 1992. 1993. 1994. 1995. 1996. 1997. 1998. 1999.]
slope_0, intercept, r_value, p_value, std_err = stats.linregress(X, Y[0,:])
slope_1, intercept, r_value, p_value, std_err = stats.linregress(X, Y[1,:])
slope_2, intercept, r_value, p_value, std_err = stats.linregress(X, Y[2,:])
slope_0 = slope/Y[0,:][0]
slope_1 = slope/Y[1,:][0]
slope_2 = slope/Y[2,:][0]
b, a = polyfit(X, Y[1,:], 1)
slope_1_a = b/Y[1,:][0]
最快和最有效的方式是使用從本地SciPy的功能linregress這一切計算:
斜率:回歸線的斜率
截距:回歸線的截距
r-value : 相關系數
p 值:假設檢驗的兩側 p 值,其原假設是斜率為零
stderr :估計的標准誤差
這是一個例子:
a = [15, 12, 8, 8, 7, 7, 7, 6, 5, 3]
b = [10, 25, 17, 11, 13, 17, 20, 13, 9, 15]
from scipy.stats import linregress
linregress(a, b)
會給你回報:
LinregressResult(slope=0.20833333333333337, intercept=13.375, rvalue=0.14499815458068521, pvalue=0.68940144811669501, stderr=0.50261704627083648)
PS只是斜率的數學公式:
線性回歸計算在一維上是向量計算。 這意味着我們可以在整個Y矩陣上組合乘法,然后使用 numpy 中的軸參數對擬合進行矢量化。 在您的情況下,適用於以下情況
((X*Y).mean(axis=1) - X.mean()*Y.mean(axis=1)) / ((X**2).mean() - (X.mean())**2)
您對擬合質量參數不感興趣,但大多數都可以通過類似的方式獲得。
比接受的答案更簡單的表示:
x = np.linspace(0, 10, 11)
y = np.linspace(0, 20, 11)
y = np.c_[y, y,y]
X = x - x.mean()
Y = y - y.mean()
slope = (X.dot(Y)) / (X.dot(X))
斜率方程來自使用簡單回歸的直線斜率的向量表示法。
這個清晰的單線應該足夠高效,沒有 scipy:
slope = np.polyfit(X,Y,1)[0]
最后你應該得到
import numpy as np
Y = np.array([
[ 2.62710000e+11, 3.14454000e+11, 3.63609000e+11, 4.03196000e+11, 4.21725000e+11, 2.86698000e+11, 3.32909000e+11, 4.01480000e+11, 4.21215000e+11, 4.81202000e+11],
[ 3.11612352e+03, 3.65968334e+03, 4.15442691e+03, 4.52470938e+03, 4.65011423e+03, 3.10707392e+03, 3.54692896e+03, 4.20656404e+03, 4.34233412e+03, 4.88462501e+03],
[ 2.21536396e+01, 2.59098311e+01, 2.97401268e+01, 3.04784552e+01, 3.13667639e+01, 2.76377113e+01, 3.27846013e+01, 3.73223417e+01, 3.51249997e+01, 4.42563658e+01]]).T
X = [ 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999]
print np.polyfit(X,Y,1)[0]
輸出為 [1.54983152e+10 9.98749876e+01 1.84564349e+00]
我這樣做的方法是使用 np.diff() 函數:
dx = np.diff(xvals),
dy = np.diff(yvals)
斜率 = dy/dx
如前所述,您可以使用 scipy 的 linregress。 以下是如何獲得斜率:
from scipy.stats import linregress
x=[1,2,3,4,5]
y=[2,3,8,9,22]
slope, intercept, r_value, p_value, std_err = linregress(x, y)
print(slope)
請記住,這樣做,因為您正在計算 r_value 和 p_value 等額外值,將比手動僅計算斜率花費更長的時間。 但是,Linregress 非常快。
資料來源: https : //docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html
使用與您的問題相同的方式定義 X 和 Y,您可以使用:
dY = (numpy.roll(Y, -1, axis=1) - Y)[:,:-1]
dX = (numpy.roll(X, -1, axis=0) - X)[:-1]
slopes = dY/dX
numpy.roll() 幫助您將下一個觀察與當前觀察對齊,您只需要刪除最后一列,這是最后一個和第一個觀察之間無用的區別。 然后您可以一次計算所有斜率,而無需 scipy。
在您的示例中, dX
始終為 1,因此您可以通過計算slopes = dY
來節省更多時間。
我在其他答案和原始回歸公式的基礎上構建了一個適用於任何張量的函數。 它將計算數據沿給定軸的斜率。 因此,如果您有任意張量X[i,j,k,l], Y[i,j,k,l]
並且您想知道沿第三軸數據的所有其他軸的斜率,您可以調用它與calcSlopes( X, Y, axis = 2 )
。
import numpy as np
def calcSlopes( x = None, y = None, axis = -1 ):
assert x is not None or y is not None
# assume that the given single data argument are equally
# spaced y-values (like in numpy plot command)
if y is None:
y = x
x = None
# move axis we wanna calc the slopes of to first
# as is necessary for subtraction of the means
# note that the axis 'vanishes' anyways, so we don't need to swap it back
y = np.swapaxes( y, axis, 0 )
if x is not None:
x = np.swapaxes( x, axis, 0 )
# https://en.wikipedia.org/wiki/Simple_linear_regression
# beta = sum_i ( X_i - <X> ) ( Y_i - <Y> ) / ( sum_i ( X_i - <X> )^2 )
if x is None:
# axis with values to reduce must be trailing for broadcast_to,
# therefore transpose
x = np.broadcast_to( np.arange( y.shape[0] ), y.T.shape ).T
x = x - ( x.shape[0] - 1 ) / 2. # mean of (0,1,...,n-1) is n*(n-1)/2/n
else:
x = x - np.mean( x, axis = 0 )
y = y - np.mean( y, axis = 0 )
# beta = sum_i x_i y_i / sum_i x_i*^2
slopes = np.sum( np.multiply( x, y ), axis = 0 ) / np.sum( x**2, axis = 0 )
return slopes
它還具有僅使用等距 y 數據的噱頭。 例如:
y = np.array( [
[ 1, 2, 3, 4 ],
[ 2, 4, 6, 8 ]
] )
print( calcSlopes( y, axis = 0 ) )
print( calcSlopes( y, axis = 1 ) )
x = np.array( [
[ 0, 2, 4, 6 ],
[ 0, 4, 8, 12 ]
] )
print( calcSlopes( x, y, axis = 1 ) )
輸出:
[1. 2. 3. 4.]
[1. 2.]
[0.5 0.5]
好吧,這取決於您擁有的點數。 如果您有兩點,請使用linregress
stats
中的scipy
。 如果更多,請使用theilslope
因為它可以避免數據中多達 29% 的異常值並計算最佳斜率。 前者簡單地考慮所有樣本,不擔心異常值,並計算適合所有樣本的最佳斜率。
from scipy import stats
slope1 = stats.linregress([2,4],[1,2])[0] # (ydata,xdata)
slope2 = stats.theilslopes([0.2,0.5,0.9,0.4],[1,2,3,4],0.9) # (ydata,xdata,confidence)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.