-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathTP2.rmd
398 lines (327 loc) · 18.4 KB
/
TP2.rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
---
title: "Apprentissage Statistique - Compte rendu du TP2"
output: html_document
---
*Par Alexandre COMBESSIE et Saad MACHRAOUI*
```{r include=FALSE}
library(class)
data(iris)
head(iris)
summary(iris)
train = iris[c(1:30,51:80,101:130),1:5]
test = iris[c(31:50,81:100,131:150),1:5]
pred = knn(train[,1:4], test[,1:4], train[,5], k = 3)
# display the confusion matrix
table(pred,test[,5])
# 5-fold cross-validation to select k
# from the set {1,...,10}
fold = sample(rep(1:5,each=18)) # creation des groupes B_v
cvpred = matrix(NA,nrow=90,ncol=10) # initialisation de la matrice
# des prédicteurs
for (k in 1:10)
for (v in 1:5){
sample1 = train[which(fold!=v),1:4]
sample2 = train[which(fold==v),1:4]
class1 = train[which(fold!=v),5]
cvpred[which(fold==v),k] = knn(sample1,sample2,class1,k=k)}
class = as.numeric(train[,5])
# display misclassification rates for k=1:10
apply(cvpred,2,function(x) sum(class!=x)) # calcule l'erreur de classification
```
### 1. Expliquer la commande `apply(cvpred,2,function(x) sum(class!=x))`
L'erreur globale, qui correspond au resultat de cette commande, peut êre alors définie comme un vecteur de nombre des erreurs commises sur le nombre total des échantillons de test pour k= 1,2 ...10. L'estimation consiste en une classification au sein de trois classes ("setosa","versicolor","virginica"). L'erreur de classification est booléenne (`class!=x` soit 0 soit 1). On peut l'écrire mathématiquement comme suit:
$$e=\frac{1}{n}\sum_{i=1}^{n} \mathbb{I}_(y_{pred}\neq y)$$
****
### 2. Pourquoi si l'on relance deux fois les commandes de la page 2, les résultats obtenus ne sont pas les mêmes ? Imaginons que nous avons lancé ces commandes 100 fois. Proposez une stratégie pour choisir k en combinant ces 100 résultats obtenus.
En relançant deux fois la commande on obtient différents résultats parce que l'algorithme utlisé se base sur un choix d'echantillons et ce choix se fait de façon aléatoire. A chaque éxecution on a un vecteur `fold` différent ce qui résulte de deux échantillons `sample1` et `sample2` différents à chaque exécution.
En éxecutant la commande 100 fois, on peut mettre une place la stratégie suivante:
- on stocke dans une matrice (100x10) les erreurs de classification obtenues
- on calcule la moyenne des colonnes pour chaque k=1,2... 10
- notre "k" optimal correspondera à l'indice du vecteur contenant le minimum des moyennes calculées.
```{r}
fold = sample(rep(1:5,each=18)) # creation des groupes B_v
cvpred = matrix(NA,nrow=90,ncol=10) # initialisation de la matrice
# des predicteurs
error = matrix(NA,nrow=100,ncol=10)
error_mean = c()
for (i in 1:100) {
for (k in 1:10) {
for (v in 1:5) {
sample1 = train[which(fold!=v),1:4]
sample2 = train[which(fold==v),1:4]
class1 = train[which(fold!=v),5]
cvpred[which(fold==v),k] = knn(sample1,sample2,class1,k=k)}}
class = as.numeric(train[,5])
error[i,]=apply(cvpred,2,function(x) sum(class!=x))}
for (i in 1:10) {
error_mean[i]=mean(error[,i])}
k_optimal = which(error_mean==min(error_mean))
```
****
### 3. Répondre aux questions 1-5 ci-dessus en insérant le code le cas échéant.
```{r include=FALSE}
library(DMwR)
data(GSPC)
T.ind = function(quotes, tgt.margin = 0.025, n.days = 10) {
v = apply(HLC(quotes), 1, mean)
r = matrix(NA, ncol = n.days, nrow = NROW(quotes))
for (x in 1:n.days) r[, x] = Next(Delt(v, k = x), x)
x = apply(r, 1, function(x) sum(x[x > tgt.margin | x <
-tgt.margin]))
if (is.xts(quotes))
xts(x, time(quotes))
else x
}
library(quantmod)
candleChart(last(GSPC, "3 months"), theme = "white", TA = NULL)
avgPrice = function(p) apply(HLC(p), 1, mean)
addAvgPrice = newTA(FUN = avgPrice, col = 1, legend = "AvgPrice")
addT.ind = newTA(FUN = T.ind, col = "red", legend = "tgtRet")
get.current.chob<-function(){quantmod:::get.current.chob()}
candleChart(last(GSPC, "3 months"), theme = "white", TA = "addAvgPrice(on=1)")
candleChart(last(GSPC, "3 months"), theme = "white", TA = "addAvgPrice(on=1)")
candleChart(last(GSPC, "3 months"), theme = "white", TA = "addT.ind();addAvgPrice(on=1)")
```
#### 3.1. Ecrire un code qui permet d'ajouter aux chandeliers japonais la courbe des valeurs médianes. Que se passe-t-il si l'on supprime l'argument `on=1` de la fonction `addAvgPrice` ?
On peut ajouter aux chandeliers japonais la courbe des valeurs médianes de la même facon qu'on ajoute la courbe des valeurs moyennes, en définissant une fonction `MedPrice` qui retourne la médiane des valeurs et une fonction `addMedPrice` pour l'ajouter au graphique. Si on supprime l'option `on=1` les courbes supplémentaires `TA` ne sont pas superposées sur le même graphique mais ajoutées sur un graphique séparé en dessous. Cela donne par exemple:
```{r fig.width=8, fig.height=5}
MedPrice = function(p) apply(HLC(p), 1, median)
addMedPrice=newTA(FUN = MedPrice, col = 1, legend = "MedPrice")
candleChart(last(GSPC,"3 months"), theme = "white", TA = "addMedPrice()")
```
****
#### 3.2 A quoi l'option `training.per` de la fonction `buildModel` correspond-t-elle ? et l'option `importance` ?
```{r include = FALSE}
myATR = function(x) ATR(HLC(x))[, "atr"]
mySMI = function(x) SMI(HLC(x))[, "SMI"]
myADX = function(x) ADX(HLC(x))[, "ADX"]
myAroon = function(x) aroon(x[, c("High", "Low")])$oscillator
myBB = function(x) BBands(HLC(x))[, "pctB"]
myChaikinVol = function(x) Delt(chaikinVolatility(x[, c("High","Low")]))[, 1]
myCLV = function(x) EMA(CLV(HLC(x)))[, 1]
myEMV = function(x) EMV(x[, c("High", "Low")], x[, "Volume"])[,2]
myMACD = function(x) MACD(Cl(x))[, 2]
myMFI = function(x) MFI(x[, c("High", "Low", "Close")],x[, "Volume"])
mySAR = function(x) SAR(x[, c("High", "Close")])[, 1]
myVolat = function(x) volatility(OHLC(x), calc = "garman")[,1]
data(GSPC)
library(randomForest)
data.model = specifyModel(T.ind(GSPC) ~ Delt(Cl(GSPC),k=1:10) +
myATR(GSPC) + mySMI(GSPC) + myADX(GSPC) + myAroon(GSPC) +
myBB(GSPC) + myChaikinVol(GSPC) + myCLV(GSPC) +
CMO(Cl(GSPC)) + EMA(Delt(Cl(GSPC))) + myEMV(GSPC) +
myVolat(GSPC) + myMACD(GSPC) + myMFI(GSPC) + RSI(Cl(GSPC)) +
mySAR(GSPC) + runMean(Cl(GSPC)) + runSD(Cl(GSPC)))
```
```{r include=FALSE}
set.seed(1234)
rf = buildModel(data.model,method="randomForest",
training.per=c(start(GSPC),index(GSPC["1999-12-31"])),
ntree=50, importance=T)
```
L'option `training.per` indique à la fonction `buildModel` où commence et où s'arrête l'échantillon d'entraînement en termes de dates. On note que comme ce sont des données de séries temporelles, il faut absolument que ce soit une plage temporelle continue. Il n'est pas possible de sélectionner un échantillon d'entraînement aléatoire comme on peut le faire sur d'autres types de données en Machine Learning.
Quant à l'option binaire `importance`, il s'agit de savoir si oui/non on demande au modèle `randomForest` d'étudier l'importance des variables/prédicteurs. C'est une mesure intéressante en termes d'interprétation des variables pour voir lesquelles sont "importantes" pour prédire. Si l'option est choisie, soit `importance=T`, on peut extraire cette information du modèle directement:
```{r}
head([email protected]$importance,5)
```
On remarque que cette option augmente le temps de calcul du modèle. Sur une simulation, le temps de calcul sans l'option `importance` est de 27 secondes, à comparer à 35 secondes avec l'option.
```{r eval=FALSE}
t1<-system.time(buildModel(data.model,method="randomForest",
training.per=c(start(GSPC),index(GSPC["1999-12-31"])),ntree=50, importance=T))[3]
#print(paste("Temps de calcul avec importance: ",toString(round(t1,0))," secondes"))
t2<-system.time(buildModel(data.model,method="randomForest",
training.per=c(start(GSPC),index(GSPC["1999-12-31"])),ntree=50, importance=F))[3]
#print(paste("Temps de calcul sans importance: ",toString(round(t2,0))," secondes"))
```
****
#### 3.3 Sachant que le graphique tracé représente le pourcentage d'augmentation de l'erreur quadratique due à la suppression d'une variable explicative, déterminer les 8 variables les plus pertinentes.
La fonction `varImpPlot` va trier par défaut les variables par ordre d'importance décroissant (`sort=TRUE`), les plus importantes étant en haut du graphique. Ici l'importance est vue comme le pourcentage d'augmentation de l'erreur quadratique due à la suppression de la variable. Cela correspond à l'option `type=1`. On aurait pu prendre `type=2` auquel cas l'importance serait vue comme la baisse des "node impurities" induite par un split sur la variable, moyenné sur tous les arbres.
```{r echo=FALSE, fig.width=7, fig.height=6}
varImpPlot([email protected], type = 1)
```
Les 8 variables les plus "pertinentes" sont donc les 8 premières en haut du graphique, soit:
1. SAR : Parabolic Stop-and-Reverse Index
2. ADX : Welles Wilder's Directional Movement Index
3. MACD : Moving Average Convergence/Divergence oscillator
4. Volat : Volatility indicator
5. ATR : Average True Range
6. SMI : Stochastic Momentum Index
7. MFI : Money Flow Index
8. CLV : Close Location Value
****
#### 3.4 En utilisant la fonction `specifyModel`, définir le nouveau modèle `data.model` qui a pour variable à expliquer `T.ind(GSPC)` et comme variables explicatives les 8 variables les plus pertinentes trouvées dans la question précédente.
Il suffit d'utiliser la fonction `specifyModel` en lui passant comme argument `Variable à expliquer ~ Variables explicatives choisies`.
```{r eval=FALSE}
Variables_explicatives<-c("SAR","ADX","MACD","Volat","ATR","SMI","MFI","CLV")
Variables_explicatives2<-sapply(Variables_explicatives,
FUN=function(x){paste("my",x,"(GSPC)",sep="")})
formula<-as.formula(paste("T.ind(GSPC) ~ ",paste(Variables_explicatives2, collapse= "+")))
data.model2 <- specifyModel(formula)
```
****
#### 3.5 Que fait la fonction `na.omit`? Pourquoi son utilisation est plus importante (voire indispensable) dans la définition de l'échantillon de test, alors que l'on s'en passe dans la définition de l'échantillon d'entrainement.
```{r}
Tdata.train = as.data.frame(modelData(
data.model,data.window=c("1970-01-02","1999-12-31")))
Tdata.eval = na.omit(as.data.frame(modelData(
data.model,data.window=c("2000-01-01","2009-09-15"))))
```
La fonction `na.omit` est indispensable dans la définition de l'échantillon de test, car cet échantillon sert à l'évaluation de la performance du modèle. Les valeurs manquantes empêcheraient la bonne mesure de la performance, ou fausseraient son évaluation. En revanche, pour la définition de l'échantillon d'entraînement, cela n'est pas nécessaire car on est pas au stade de l'évaluation.
****
### 4. Utiliser l'algorithme *kNN* pour prédire la variable signal sur l'échantillon de test `Tdata.eval`, en utilisant `Tdata.train` comme échantillon d'entraînement. Evaluer l'erreur de la prédiction.
On utilisera ici l'algorithme `knn` pour prédire la variable signal en suivant les memes etapes que la premiere question.Pour evaluer l'erreur de la prediction, on utilise la meme commande utilisee et expliquee dans la premiere question `apply(cvpred,2,function(x) sum(class!=x))` et on stockera le resultat dans le vecteur `errors_knn`.
*****
### 4. Utiliser l'algorithme *kNN* pour prédire la variable signal sur l'échantillon de test `Tdata.eval`, en utilisant `Tdata.train` comme échantillon d'entraînement. Evaluer l'erreur de la prédiction. Inclure le code.
On utilisera ici l'algorithme `knn` pour prédire la variable signal en suivant les memes etapes que la premiere question.Pour evaluer l'erreur de la prediction, on utilise la meme commande utilisee et expliquee dans la premiere question `apply(cvpred,2,function(x) sum(class!=x))` et on stockera le resultat dans le vecteur `errors_knn`. Dans notre cas, on obtient pour k=10 la plus petite erreur de prediction.
```{r}
Tdata.eval[,1] = trading.signals(Tdata.eval[,1],0.1,-0.1)
Tdata.train[,1] = trading.signals(Tdata.train[,1],0.1,-0.1)
names(Tdata.eval)[1] = "signal"
names(Tdata.train)[1] = "signal"
#summary(Tdata.train) #Mis en commentaire pour limiter la taille du compte rendu
#summary(Tdata.train) #Mis en commentaire pour limiter la taille du Compte Rendu
cvpred = matrix(NA,nrow=2430,ncol=10) #Pour le recueil des résultats;
class=as.numeric(Tdata.eval[,1]) #Vraies classes de Tdata.eval;
cvpred = matrix(NA,nrow=2430,ncol=10)
class=as.numeric(Tdata.eval[,1])
for(i in (1:10)) {
cvpred[,i] = knn(Tdata.train[,-1], Tdata.eval[,-1] , Tdata.train[,1], k = i)}
errors_knn = apply(cvpred,2,function(x) sum(class!=x))
errors_knn
# Matrice de confusion de l'indice k correspondant au minimum d'erreurs:
table(cvpred[,which(errors_knn==min(errors_knn))],Tdata.eval[,1])
```
****
### 5. La même chose pour l'algorithme d'arbre de décision. Est-il meilleur que kNN ? Afficher l'arbre de décision obtenu.
En comparant la matrice de confusion obtenue à la question 4 et la matrice de confusion ci dessous, on remarque que l'erreur de prediction pour l'arbre de decision est inferieure à l'erreur de prediction pour l'algorithme knn, on en conclut que l'algorithme d'arbre de decision est meilleur que knn au sens de l'erreur de classification sur notre échantillon.
```{r fig.width=8, fig.height=7}
library(rpart)
Tdata.train[,1]=as.data.frame(modelData(data.model,
data.window=c("1970-01-02","1999-12-31")))[,1]
Tdata.eval[,1]=na.omit(as.data.frame(modelData(data.model,
data.window=c("2000-01-01","2009-09-15"))))[,1]
regressionFormula = "signal ~ myATR.GSPC + mySMI.GSPC + myADX.GSPC + myCLV.GSPC +
myVolat.GSPC + myMACD.GSPC + myMFI.GSPC +mySAR.GSPC"
importantVars = c("myATR.GSPC","mySMI.GSPC","myADX.GSPC",
"myCLV.GSPC","myVolat.GSPC","myMACD.GSPC",
"myMFI.GSPC","mySAR.GSPC")
importantColumnsIndexes = c(1)
i=2
for(var in importantVars) {
importantColumnsIndexes[i] = which(colnames(Tdata.train) == var)
i= i+1
}
rt.ai = rpart(regressionFormula, data = Tdata.train[,importantColumnsIndexes])
rt.predictions.eval = predict(rt.ai, Tdata.eval[,-1])
predictions.eval.signal = trading.signals(rt.predictions.eval ,0.1,-0.1)
table(predictions.eval.signal,trading.signals(Tdata.eval[,1],0.1,-0.1))
prettyTree(rt.ai,col="navy",bg="lemonchiffon",cex=0.5)
```
****
# Annexes
## I. Predicteur KNN
```{r}
library(class)
data(iris)
head(iris)
summary(iris)
train = iris[c(1:30,51:80,101:130),1:5]
test = iris[c(31:50,81:100,131:150),1:5]
pred = knn(train[,1:4], test[,1:4], train[,5], k = 3)
# display the confusion matrix
table(pred,test[,5])
# 5-fold cross-validation to select k
# from the set {1,...,10}
fold = sample(rep(1:5,each=18)) # creation des groupes B_v
cvpred = matrix(NA,nrow=90,ncol=10) # initialisation de la matrice
# des predicteurs
for (k in 1:10)
for (v in 1:5) {
sample1 = train[which(fold!=v),1:4]
sample2 = train[which(fold==v),1:4]
class1 = train[which(fold!=v),5]
cvpred[which(fold==v),k] = knn(sample1,sample2,class1,k=k)}
class = as.numeric(train[,5])
# display misclassification rates for k=1:10
apply(cvpred,2,function(x) sum(class!=x)) # calcule l'erreur de classification
```
## II.Predicting stock market returns
```{r fig.width=8, fig.height=5}
library(DMwR)
data(GSPC)
T.ind = function(quotes, tgt.margin = 0.025, n.days = 10) {
v = apply(HLC(quotes), 1, mean)
r = matrix(NA, ncol = n.days, nrow = NROW(quotes))
for (x in 1:n.days) r[, x] = Next(Delt(v, k = x), x)
x = apply(r, 1, function(x) sum(x[x > tgt.margin | x <
-tgt.margin]))
if (is.xts(quotes))
xts(x, time(quotes))
else x
}
library(quantmod)
candleChart(last(GSPC, "3 months"), theme = "white", TA = NULL)
avgPrice = function(p) apply(HLC(p), 1, mean)
addAvgPrice = newTA(FUN = avgPrice, col = 1, legend = "AvgPrice")
addT.ind = newTA(FUN = T.ind, col = "red", legend = "tgtRet")
get.current.chob<-function(){quantmod:::get.current.chob()}
candleChart(last(GSPC, "3 months"), theme = "white", TA = "addAvgPrice(on=1)")
candleChart(last(GSPC, "3 months"), theme = "white", TA = "addAvgPrice(on=1)")
candleChart(last(GSPC, "3 months"), theme = "white", TA = "addT.ind();addAvgPrice(on=1)")
```
```{r}
myATR = function(x) ATR(HLC(x))[, "atr"]
mySMI = function(x) SMI(HLC(x))[, "SMI"]
myADX = function(x) ADX(HLC(x))[, "ADX"]
myAroon = function(x) aroon(x[, c("High", "Low")])$oscillator
myBB = function(x) BBands(HLC(x))[, "pctB"]
myChaikinVol = function(x) Delt(chaikinVolatility(x[, c("High","Low")]))[, 1]
myCLV = function(x) EMA(CLV(HLC(x)))[, 1]
myEMV = function(x) EMV(x[, c("High", "Low")], x[, "Volume"])[,2]
myMACD = function(x) MACD(Cl(x))[, 2]
myMFI = function(x) MFI(x[, c("High", "Low", "Close")],x[, "Volume"])
mySAR = function(x) SAR(x[, c("High", "Close")])[, 1]
myVolat = function(x) volatility(OHLC(x), calc = "garman")[,1]
```
```{r}
data(GSPC)
library(randomForest)
data.model = specifyModel(T.ind(GSPC) ~ Delt(Cl(GSPC),k=1:10) +
myATR(GSPC) + mySMI(GSPC) + myADX(GSPC) + myAroon(GSPC) +
myBB(GSPC) + myChaikinVol(GSPC) + myCLV(GSPC) +
CMO(Cl(GSPC)) + EMA(Delt(Cl(GSPC))) + myEMV(GSPC) +
myVolat(GSPC) + myMACD(GSPC) + myMFI(GSPC) + RSI(Cl(GSPC)) +
mySAR(GSPC) + runMean(Cl(GSPC)) + runSD(Cl(GSPC)))
set.seed(1234)
rf = buildModel(data.model,method="randomForest",
training.per=c(start(GSPC),index(GSPC["1999-12-31"])),
ntree=50, importance=T)
```
```{r}
Tdata.train[,1] = trading.signals(Tdata.train[,1],0.1,-0.1)
names(Tdata.train)[1] = "signal"
summary(Tdata.train)
```
```{r include=FALSE}
library(rpart)
Tdata.train[,1] =as.data.frame(modelData(data.model,
data.window=c("1970-01-02","1999-12-31")))[,1]
Tdata.eval[,1]=na.omit(as.data.frame(modelData(data.model,
data.window=c("2000-01-01","2009-09-15"))))[,1]
regressionFormula = "signal ~ myATR.GSPC + mySMI.GSPC + myADX.GSPC + myCLV.GSPC +
myVolat.GSPC + myMACD.GSPC + myMFI.GSPC +mySAR.GSPC"
importantVars = c("myATR.GSPC","mySMI.GSPC","myADX.GSPC",
"myCLV.GSPC","myVolat.GSPC","myMACD.GSPC",
"myMFI.GSPC","mySAR.GSPC")
importantColumnsIndexes = c(1)
i=2
for( var in importantVars){
importantColumnsIndexes[i] = which(colnames(Tdata.train) == var)
i= i+1
}
rt.ai = rpart(regressionFormula, data = Tdata.train[,importantColumnsIndexes])
rt.predictions.eval = predict(rt.ai, Tdata.eval[,-1])
predictions.eval.signal = trading.signals(rt.predictions.eval ,0.1,-0.1)
table(predictions.eval.signal,trading.signals(Tdata.eval[,1],0.1,-0.1))
prettyTree(rt.ai,col="navy",bg="lemonchiffon")
```