web-dev-qa-db-fra.com

Régression linéaire simple à l'aide de la base de données pandas

Je cherche à vérifier les tendances pour un certain nombre d'entités (SysNr)

J'ai des données sur 3 ans (2014,2015,2016)

Je regarde une grande quantité de variables, mais limiterai cette question à une ('res_f_r')

Mon DataFrame ressemble à quelque chose comme ça

d = [
    {'RegnskabsAar': 2014, 'SysNr': 1, 'res_f_r': 350000},
    {'RegnskabsAar': 2015, 'SysNr': 1, 'res_f_r': 400000},
    {'RegnskabsAar': 2016, 'SysNr': 1, 'res_f_r': 450000},
    {'RegnskabsAar': 2014, 'SysNr': 2, 'res_f_r': 350000},
    {'RegnskabsAar': 2015, 'SysNr': 2, 'res_f_r': 300000},
    {'RegnskabsAar': 2016, 'SysNr': 2, 'res_f_r': 250000},
]

df = pd.DataFrame(d)



   RegnskabsAar  SysNr  res_f_r
0          2014      1   350000
1          2015      1   400000
2          2016      1   450000
3          2014      2   350000
4          2015      2   300000
5          2016      2   250000

Mon désir est de faire une régression linéaire sur chaque entité (SysNr) et de me renvoyer la pente et l’interception.

Ma sortie souhaitée pour ce qui précède est 

   SysNr  intercept  slope
0      1     300000  50000
1      2     400000 -50000

Des idées?

5
Henrik Poulsen

Donc, je ne sais pas pourquoi nos valeurs d'interception diffèrent (peut-être que j'ai commis une erreur ou que vos données fournies ne sont pas les données complètes sur lesquelles vous comptez travailler), mais je vous suggérerais d'utiliser np.polyfit ou l'outil de votre choix ( scikit-learn , scipy.stats.linregress , ...) en association avec groupby et appliquez:

In [25]: df.groupby("SysNr").apply(lambda g: np.polyfit(g.RegnskabsAar, g.res_f_r, 1))
Out[25]:
SysNr
1    [49999.99999999048, -100349999.99998075]
2    [-49999.99999999045, 101049999.99998072]
dtype: object

Après cela, embellissez-le:

In [43]: df.groupby("SysNr").apply(
    ...:     lambda g: np.polyfit(g.RegnskabsAar, g.res_f_r, 1)).apply(
    ...:     pd.Series).rename(columns={0:'slope', 1:'intercept'}).reset_index()
Out[43]:
   SysNr    slope     intercept
0      1  50000.0 -1.003500e+08
1      2 -50000.0  1.010500e+08

Modifier:

Parce que vous avez demandé dans l’autre réponse, dans le commentaire, comment gérer les années manquantes pour une variable SysNr: , Supprimez-la simplement NaNs pour une régression linéaire valide. Bien sûr, vous pouvez également les remplir avec la moyenne ou plus, en fonction de ce que vous voulez réaliser, mais ce n'est pas utile de mon point de vue.

Si l'entité ne dispose que de données pour une année, vous ne pouvez pas appliquer une régression linéaire sur celle-ci utilement. Mais vous pouvez (si vous le souhaitez et si cela vous convient, veuillez fournir plus d'informations sur les données si nécessaire) pour extrapoler d'une manière ou d'une autre la pente des autres entités par rapport à celle-ci et calculer l'interception. Pour cela, bien sûr, vous devez faire quelques hypothèses sur la distribution de la pente des entités (par exemple, linéaire, la pente de sysNr 3 serait donc -150000.0).

4
Nico Albers

Vous pouvez également utiliser linregress à partir de scipy.stats avec groupby à partir de pandas:

from scipy.stats import linregress

# groupby column
grouped = df.groupby('SysNr')

# https://stackoverflow.com/a/14775604/5916727
# apply linear regression to each group
result_df = pd.DataFrame(grouped.apply(lambda x: linregress(x['RegnskabsAar'], x['res_f_r']))).reset_index()

# https://stackoverflow.com/a/29550458/5916727
# expand result to each column
result_df[['slope', 'intercept', 'r_value', 'p_value', 'std_err']] = result_df[0].apply(pd.Series)

# drop initial column with all in one
del result_df[0]

result_df

Résultat:

   SysNr    slope    intercept  r_value       p_value  std_err
0      1  50000.0 -100350000.0      1.0  9.003163e-11      0.0
1      2 -50000.0  101050000.0     -1.0  9.003163e-11      0.0
1
student