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