Dans ce nouveau post, nous allons continuer à travailler sur la régression. L’objectif est de considérer des tests alternatifs sur les coefficient et d’étendre les modèles de manière à intégrer plusieurs facteurs explicatifs. Cela nous permettra de comprendre les biais créés par l’omission de variables dans les analyses de régression.
Tâche n°1 Reprenez les données sur les actions, estimez le modèle de marché pour chacun d’eux, réalisez un interval de confiance à 95% sur le beta, testez sa valeur par rapport à 1.
Comme à chaque fois, nous allons commencer par charger les packages qui vont être utilisés. On y retrouve les habituels tidyverse, haven, gt, mais aussi car, un nouveau package qui inclue des fonctions permettant la réalisation de tests statistiques complémentaires aux régressions.
library(tidyverse)
library(haven)
library(gt)
library(car)
On peut alors importer les données concernant les rendements des actions et de l’indice de marché que nous avons créé dans le post précédent. Si nécessaire vous pouvez le télécharger ici.
return_actions <- read_delim("return_actions.csv",delim = ";")
## Rows: 252 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ";"
## dbl (8): MSFT.Adjusted, AAPL.Adjusted, META.Adjusted, GSPC.Adjusted, ret_MS...
## date (1): Date
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Ceux-ci fait. On peut ré-estimer le modèle de marché pour chaque titre (régression du rendement de l’action sur l’indice de marché en utilisant la fonction lm()) et stocker l’information dans des objets dédiés (portant ici le noms des actions).
Ms<-lm(ret_MSFT~ret_GSPC,data=return_actions)
Ap<-lm(ret_AAPL~ret_GSPC,data=return_actions)
Fb<-lm(ret_META~ret_GSPC,data=return_actions)
Pour obtenir l’interval de confiance au niveau désiré (95%), il suffit de mobiliser la fonction confint(). Elle prend comme premier argument le modèle de régession et comme second (level) le niveau de confiance retenu. Produisons-la pour Microsoft (Ms).
confint(Ms,level=0.95)
## 2.5 % 97.5 %
## (Intercept) -0.001112434 0.001401162
## ret_GSPC 1.083637524 1.390103522
On peut lire que le Beta de Microsoft à 95% de chance de se trouver entre 1.083 et 1.390. Néanmoins, l’ensemble reste peut lisible du fait de l’inclusion de l’intervalle de confiance de la constante et du nombre de chiffres après la virgule affiché. Réduisons tout cela.
confint(Ms,parm=2,level=0.95) %>% round(digits = 4)
## 2.5 % 97.5 %
## ret_GSPC 1.0836 1.3901
Créons un tableau incluant l’ensemble des intervalles de confiance des beta des titre.
tb<-rbind(confint(Ms,parm=2,level=0.95),
confint(Ap,parm=2,level=0.95),
confint(Fb,parm=2,level=0.95)) %>% round(digits=4)
rownames(tb)<-NULL
tb
## 2.5 % 97.5 %
## [1,] 1.0836 1.3901
## [2,] 0.8396 1.2078
## [3,] 0.8588 1.3279
Incluons-les dans le tableau des beta tel que nous l’avions réalisé dans le post précédent.
reg1<-summary(Ms)
reg2<-summary(Ap)
reg3<-summary(Fb)
tab<-data.frame(c('Microsoft','Apple','Facebook'),
rbind(round(reg1$coefficients[2,c(1,3,4)],digits=4),
round(reg2$coefficients[2,c(1,3,4)],digits=4),
round(reg3$coefficients[2,c(1,3,4)],digits=4)),
tb)
colnames(tab)<-c(' ','Beta','t stat', 'p value','2,5%','97,5%')
tab$`p value`<-format(tab$`p value`,nsmall = 4)
tab
## Beta t stat p value 2,5% 97,5%
## 1 Microsoft 1.2369 15.8978 0.0000 1.0836 1.3901
## 2 Apple 1.0237 10.9531 0.0000 0.8396 1.2078
## 3 Facebook 1.0934 9.1810 0.0000 0.8588 1.3279
Ajoutons un titre, un sous-titre ainsi qu’un chapeau sur les colonnes correspondant à l’intervalle de confiance.
tab_<-gt(tab) %>%
tab_header(title='Beta issu du modèle de marché',
subtitle = "Estimé sur 2016 en référence à l'indice S&P500") %>%
tab_spanner('Interval de confiance à 95%',columns = c('2,5%','97,5%'))
tab_
Beta issu du modèle de marché | |||||
Estimé sur 2016 en référence à l'indice S&P500 | |||||
Beta | t stat | p value | Interval de confiance à 95% | ||
---|---|---|---|---|---|
2,5% | 97,5% | ||||
Microsoft | 1.2369 | 15.8978 | 0.0000 | 1.0836 | 1.3901 |
Apple | 1.0237 | 10.9531 | 0.0000 | 0.8396 | 1.2078 |
1.0934 | 9.1810 | 0.0000 | 0.8588 | 1.3279 |
Transférons le résultat dans un document Word.
gtsave(tab_,'Betas_conf_v1.docx')
Il nous reste à réaliser les test des beta contre la valeur 1. Les tests dans les modèles de régression sont réalisés contre 0. Pour cela, on peut utiliser la fonction linearHypothesis() du package car. Elle permet de mettre en oeuvre un test de restriction spécification de Fisher. Ses arguments sont le modèle de régression et la restriction (ici ret_GSPC=1).
linearHypothesis(Ms, "ret_GSPC = 1")
## Linear hypothesis test
##
## Hypothesis:
## ret_GSPC = 1
##
## Model 1: restricted model
## Model 2: ret_MSFT ~ ret_GSPC
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 250 0.026314
## 2 249 0.025370 1 0.00094442 9.2693 0.00258 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Pratiqué pour Microsoft, on rejette l’hypothèse H1 d’égalité du coefficient à 1 (que le modèle restreint est meilleur que le modèle de base). Appliquons la même procédure qui a un beta plus proche de 1.
linearHypothesis(Ap, "ret_GSPC = 1")
## Linear hypothesis test
##
## Hypothesis:
## ret_GSPC = 1
##
## Model 1: restricted model
## Model 2: ret_AAPL ~ ret_GSPC
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 250 0.036621
## 2 249 0.036612 1 9.4582e-06 0.0643 0.8
Cette fois ci, on ne peut rejeté H0. Le beta de Apple n’est pas statistiquement différent de 1.
La procédure rempli ses objectifs. Néanmoins, on pourrait préférer utiliser un test de Student comme pour l’hypothèse classique de beta égale 0 que l’on retrouve dans les résumés des modèles de régression. Pour cela, le plus simple (pour moi) est de créer soit même sa fonction de test. Rappelons la forme de statistique de Sudent:
Beta=ˆβ−1σ/√n
Standard error=σ/√n
La fonction pt() permet de calculer la fonction de densité cumulative (la fonction de répartition) de la loi de Student. Mobilisons-la pour calculer la p value du test.
ttest <- function(reg, coefnum, val){
co <- coef(summary(reg))
tstat <- (co[coefnum,1]-val)/co[coefnum,2]
pval<- 2 * pt(abs(tstat), reg$df.residual, lower.tail = FALSE)
ret<-round(c(tstat,pval),digits=4)
names(ret)<-c('tstat','pval')
return(ret)}
Appliquons notre fonction à la régression sur Microsoft (Ms) d’abord en testant beta égal à 0 pour comparer le résultat avec celui obtenu avec la fonction summary(), puis en testant beta égal à 1.
ttest(Ms,2,0)
## tstat pval
## 15.8978 0.0000
ttest(Ms,2,1)
## tstat pval
## 3.0445 0.0026
Notre fonction maison produit bien le résultat attendu. Appliquons-la à toute nos actions. Agrégeons l’ensemble pour l’ajouter à notre tableau des beta.
tc<-rbind(ttest(Ms,2,1),ttest(Ap,2,1),ttest(Fb,2,1))
tc
## tstat pval
## [1,] 3.0445 0.0026
## [2,] 0.2536 0.8000
## [3,] 0.7842 0.4337
Créons la data frame correspondant.
tab<-data.frame(tab,tc)
colnames(tab)<-c(' ','Beta','t stat', 'p value','2,5%','97,5%',
't_stat', 'p_value')
tab
## Beta t stat p value 2,5% 97,5% t_stat p_value
## 1 Microsoft 1.2369 15.8978 0.0000 1.0836 1.3901 3.0445 0.0026
## 2 Apple 1.0237 10.9531 0.0000 0.8396 1.2078 0.2536 0.8000
## 3 Facebook 1.0934 9.1810 0.0000 0.8588 1.3279 0.7842 0.4337
Mettons l’ensemble en page.
tab_<-gt(tab) %>%
tab_header(title='Beta issu du modèle de marché',
subtitle = "Estimé sur 2016 en référence à l'indice S&P500") %>%
tab_spanner('Beta=0',columns = c('t stat','p value')) %>%
tab_spanner('Interval de confiance à 95%',columns = c('2,5%','97,5%')) %>%
tab_spanner('Beta=1',columns = c('t_stat','p_value'))
tab_
Beta issu du modèle de marché | |||||||
Estimé sur 2016 en référence à l'indice S&P500 | |||||||
Beta | Beta=0 | Interval de confiance à 95% | Beta=1 | ||||
---|---|---|---|---|---|---|---|
t stat | p value | 2,5% | 97,5% | t_stat | p_value | ||
Microsoft | 1.2369 | 15.8978 | 0.0000 | 1.0836 | 1.3901 | 3.0445 | 0.0026 |
Apple | 1.0237 | 10.9531 | 0.0000 | 0.8396 | 1.2078 | 0.2536 | 0.8000 |
1.0934 | 9.1810 | 0.0000 | 0.8588 | 1.3279 | 0.7842 | 0.4337 |
Transférons le tableau produit dans Word.
gtsave(tab_,'Betas_conf_0_1_v1.docx')
Tâche n°2 Revenez sur les cas des écoles californiennes, incluez dans la régresion les variables d’éléves apprenant l’anglais (el_pct), étudiez les liens entre les variables
Commençons par recharger les données associés aux écoles (le fichier caschool). Si vous ne les avez pas encore vous pouvez les trouver en lien ici.
caschool <- read_dta("caschool.dta")
Une fois les données importées, créons deux modèles de régression le premier expliquant testscr uniquement avec str (reg1) et le secons l’expliquant à la fois par str et el_pct.
reg1<-lm(testscr~str,data=caschool)
reg2<-lm(testscr~str+el_pct,data=caschool)
Inspectons le résultat de la première régression via summary().
summary(reg1)
##
## Call:
## lm(formula = testscr ~ str, data = caschool)
##
## Residuals:
## Min 1Q Median 3Q Max
## -47.727 -14.251 0.483 12.822 48.540
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 698.9330 9.4675 73.825 < 2e-16 ***
## str -2.2798 0.4798 -4.751 2.78e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 18.58 on 418 degrees of freedom
## Multiple R-squared: 0.05124, Adjusted R-squared: 0.04897
## F-statistic: 22.58 on 1 and 418 DF, p-value: 2.783e-06
Le coefficient associé à str est de -2.2798 et il est statistiquement différent de zéro. Voyons ce qu’il en est dans le second modèle.
summary(reg2)
##
## Call:
## lm(formula = testscr ~ str + el_pct, data = caschool)
##
## Residuals:
## Min 1Q Median 3Q Max
## -48.845 -10.240 -0.308 9.815 43.461
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 686.03225 7.41131 92.566 < 2e-16 ***
## str -1.10130 0.38028 -2.896 0.00398 **
## el_pct -0.64978 0.03934 -16.516 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 14.46 on 417 degrees of freedom
## Multiple R-squared: 0.4264, Adjusted R-squared: 0.4237
## F-statistic: 155 on 2 and 417 DF, p-value: < 2.2e-16
La valeur du coefficient de str a changé. Elle est passée à -1.1013 mais est toujours statistiquement significatif. Le coefficient de el_pct est de -0.6497 et est statistiquement significatif.
Pour bien comprendre comment l’inclusion d’el_pct permet d’ajuster l’effet de str sur testscr, régressons str par el_pct. Cela nous indique l’effet de el_pct sur str. Sortons les résidus de la régression autrement dit la part de str non expliquée par el_pct.
rega<-lm(str~el_pct,data=caschool)
res_a<-rega$residuals
head(res_a)
## 1 2 3 4 5 6
## -1.4444089 2.1013692 -1.2194820 -1.9771752 -0.9320077 1.8310406
Régressons de la même manière testscr par el_pct et sortons le résidus, la part de testscr non expliqué par el_pct.
regb<-lm(testscr~el_pct,data=caschool)
res_b<-regb$residuals
head(res_b)
## 1 2 3 4 5 6
## 26.0605447 -0.4632982 -1.0047804 -17.0394308 -14.5888014 -50.8611787
Régressons ce dernier résidu par le premier en omettant la constante. Cela se fait en ajoutant -1 aux variables explicatives.
lm(res_b~res_a-1)
##
## Call:
## lm(formula = res_b ~ res_a - 1)
##
## Coefficients:
## res_a
## -1.101
On retrouve retrouve le même coefficient que dans notre modèle incluant les deux variables pour expliquer testscr. L’inclusion de la seconde variable permet bien de corriger l’effet de str sur testscr de la partie de cet effet qui passe par el_pct.