web-dev-qa-db-fra.com

Calcul des pentes en Numpy (ou Scipy)

J'essaie de trouver le moyen le plus rapide et le plus efficace de calculer les pentes en utilisant Numpy et Scipy. J'ai un ensemble de données de trois variables Y et une variable X et j'ai besoin de calculer leurs pentes individuelles. Par exemple, je peux facilement le faire une ligne à la fois, comme indiqué ci-dessous, mais j'espérais qu'il y avait un moyen plus efficace de le faire. Je ne pense pas non plus que linregress soit la meilleure voie à suivre, car je n'ai besoin d'aucune des variables auxiliaires comme l'interception, l'erreur standard, etc. dans mes résultats. Toute aide est grandement appréciée.

    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]
17
hotshotiguana

Le calcul de régression linéaire est, dans une dimension, un calcul vectoriel . Cela signifie que nous pouvons combiner les multiplications sur la matrice entière [~ # ~] y [~ # ~] , puis vectoriser les ajustements en utilisant la axis paramètre dans numpy. Dans votre cas, cela correspond à ce qui suit

((X*Y).mean(axis=1) - X.mean()*Y.mean(axis=1)) / ((X**2).mean() - (X.mean())**2)

Les paramètres de qualité d'ajustement ne vous intéressent pas, mais la plupart d'entre eux peuvent être obtenus de manière similaire.

7
Brian B

Le moyen le plus rapide et le plus efficace serait d'utiliser une fonction native scipy de linregress qui calcule tout:

pente: pente de la droite de régression

interception: interception de la droite de régression

valeur r: coefficient de corrélation

p-value: p-value bilatérale pour un test d'hypothèse dont l'hypothèse nulle est que la pente est nulle

stderr: erreur type de l'estimation

Et voici un exemple:

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)

vous renverra:

LinregressResult(slope=0.20833333333333337, intercept=13.375, rvalue=0.14499815458068521, pvalue=0.68940144811669501, stderr=0.50261704627083648)

P.S. Juste une formule mathématique pour la pente:

enter image description here

33
Salvador Dali

Une représentation plus simple que la réponse acceptée:

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))

L'équation de la pente provient de notation vectorielle de la pente d'une droite par régression simple .

7
drpm

La façon dont je l'ai fait utilise la fonction np.diff ():

dx = np.diff (xvals),

dy = np.diff (yvals)

pentes = dy/dx

4
user10028580

Comme dit précédemment, vous pouvez utiliser le linregress de scipy. Voici comment obtenir juste la pente:

    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)

Gardez à l'esprit que le faire de cette façon, puisque vous calculez des valeurs supplémentaires comme r_value et p_value, prendra plus de temps que de calculer uniquement la pente manuellement. Cependant, Linregress est assez rapide.

Source: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html

2
embulldogs99

Avec X et Y définis de la même manière que dans votre question, vous pouvez utiliser:

dY = (numpy.roll(Y, -1, axis=1) - Y)[:,:-1]
dX = (numpy.roll(X, -1, axis=0) - X)[:-1]

slopes = dY/dX

numpy.roll () vous aide à aligner l'observation suivante avec l'observation actuelle, il vous suffit de supprimer la dernière colonne qui est la différence inutile entre la dernière et la première observation. Ensuite, vous pouvez calculer toutes les pentes à la fois, sans scipy.

Dans votre exemple, dX est toujours égal à 1, vous pouvez donc gagner plus de temps en calculant slopes = dY.

1
Benjamin

Cette doublure transparente devrait être suffisamment efficace sans scipy:

slope = np.polyfit(X,Y,1)[0]

Enfin, vous devriez

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]

La sortie est [1.54983152e + 10 9.98749876e + 01 1.84564349e + 00]

1
kimstik

J'ai construit sur les autres réponses et la formule de régression originale pour construire une fonction qui fonctionne pour n'importe quel tenseur. Il calculera les pentes des données le long de l'axe donné. Donc, si vous avez des tenseurs arbitraires X[i,j,k,l], Y[i,j,k,l] Et que vous voulez connaître les pentes de tous les autres axes le long des données du troisième axe, vous pouvez l'appeler avec 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

Il a également le gadget de fonctionner avec uniquement des données y également espacées. Ainsi, par exemple:

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 ) )

Production:

[1. 2. 3. 4.]
[1. 2.]
[0.5 0.5]
0
mxmlnkn