Вычисление склонов в Numpy (или 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]
Ответы
Ответ 1
Расчет линейной регрессии в одном измерении векторный расчет. Это означает, что мы можем комбинировать умножения на всей матрице Y, а затем векторизовать подгонки, используя параметр оси в numpy. В вашем случае это будет выглядеть следующим образом
((X*Y).mean(axis=1) - X.mean()*Y.mean(axis=1)) / ((X**2).mean() - (X.mean())**2)
Вам не нужны параметры качества, но большинство из них можно получить аналогичным образом.
Ответ 2
Самый быстрый и эффективный способ - использовать встроенную функцию scipy из linregress, которая вычисляет все:
наклон: наклон линии регрессии
перехват: перехват линии регрессии
r-значение: коэффициент корреляции
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)
P.S. Просто математическая формула для наклона:
![введите описание изображения здесь]()
Ответ 3
Представление, которое проще, чем принятый ответ:
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))
Уравнение для наклона происходит из векторной нотации для наклона линии с использованием простой регрессии.
Ответ 4
Я сделал это с помощью функции np.diff():
dx = np.diff(xvals),
dy = np.diff(yvals)
склоны = dy/dx
Ответ 5
Как было сказано ранее, вы можете использовать скудный 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
Ответ 6
Если 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
.
Ответ 7
Я опирался на другие ответы и оригинальную формулу регрессии, чтобы построить функцию, которая работает для любого тензора. Он рассчитает наклоны данных вдоль заданной оси. Итак, если у вас есть произвольные тензоры 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 = 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]
Ответ 8
Этот понятный однострочный текст должен быть достаточно эффективным без скучного:
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]