Les fonctions any () et all () sont des raccourcis pratiques. Ils déclarent si l'un ou l'autre de leurs arguments est VRAI.
Par exemple, supposons que R exécute les éléments suivants:
Il évalue d'abord x> 8, en donnant ceci:
(FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE)
La fonction any () indique si aucune de ces valeurs est TRUE. La fonction all () fonctionne de la même manière et indique si toutes les valeurs sont TRUE.
2.5.1 Exemple étendu: trouver des exécutions de consécutifs
Supposons que nous sommes intéressés à trouver des séries de 1 consécutifs dans des vecteurs constitué de 1 et de 0. Dans le vecteur (1,0,0,1,1,1,0,1,1), par exemple, il y a une longueur de longueur 3 commençant à l'index 4, et de longueur 2 commençant aux indices 4, 5, et 8. Donc, l'appel de recherche (c (1,0,0,1,1,1,0,1,1), 2) à notre fonction à afficher ci-dessous revient (4,5,8). Voici le code:
Dans la ligne 5, nous devons déterminer si toutes les valeurs k commençant à x [i], c'est-à-dire toutes les valeurs dans x [i], x [i + i], ..., x [i + ki ] -sont des 1. L'expression x [i: (i + k-l)] nous donne cette plage dans x, puis on applique all() nous indique s'il y a une exécution.
Testez-le.
Bien que l'utilisation de all() soit bonne dans le code précédent, l'accumulation du vecteur s'exécute n'est pas si bonne. L'allocation de vecteur prend du temps. Chaque exécution de ce qui suit ralentit notre code, car il alloue un nouveau vecteur dans l'appel c(runs,i). (Le fait qu'un nouveau vecteur est assigné à exécuter est irréductible, nous avons toujours fait une allocation d'espace de mémoire vectorielle.)
Dans une courte boucle, cela ne sera probablement pas un problème, mais lorsque les performances de l'application pose un problème, il existe de meilleures façons.
Une alternative est de préaffecter l'espace mémoire, comme ceci:
Dans la ligne 3, nous créons un espace d'un vecteur de longueur n. Cela signifie que nous évitons de nouvelles allocations lors de l'exécution de la boucle. Nous remplissons simplement les courses, dans la ligne 8. Juste avant de sortir de la fonction, nous redéfinissons les courses dans la ligne 12 pour supprimer la partie inutilisée du vecteur.
C'est mieux, car nous avons réduit le nombre d'allocations de mémoire à seulement deux, à partir de plusieurs de la première version du code.
Si nous avons vraiment besoin de vitesse, nous pourrions envisager de recodier ceci en C, tel que décrit dans le chapitre 14.
2.5.2 Exemple étendu: prévision de la série temporelle à temps discret
Supposons que nous observons des données à valeur 0 et 1, une par période. Pour rendre les choses concrètes, dites-le que c'est une météo quotidienne: 1 pour la pluie et 0 pour aucune pluie. Supposons que nous souhaitons prédire s'il va pleuvoir demain, en sachant s'il a plu ou pas ces derniers jours. Plus précisément, pour un certain nombre k, nous prévoyons la météo de demain en fonction de la météo des derniers k jours. Nous utiliserons la règle de la majorité: si le nombre de 1s dans les dernières périodes de K est d'au moins k / 2, nous allons prédire que la valeur suivante soit 1; sinon, notre prédiction est 0. Par exemple, si k = 3 et les données pour les trois dernières périodes est de 1,0,1, nous allons prédire que la prochaine période soit 1.
Mais comment devrions-nous choisir k? De toute évidence, si nous choisissons une valeur trop petite, cela nous donnera un échantillon trop petit pour prévoir. Une valeur trop importante nous amènera à s'appuyer sur des données du passé lointain qui peuvent avoir peu ou pas de valeur prédictive.
Une solution commune à ce problème est de prendre des données connues, appelé un ensemble de formation, puis de demander à quel point diverses valeurs de k auraient pu fonctionner sur ces données.
Dans le cas météorologique, supposons que nous disposons de 500 jours de données et supposons que nous envisageons d'utiliser k = 3. Pour évaluer la capacité prédictive de cette valeur pour k, nous "prédisons" chaque jour dans nos données des trois jours précédents, puis comparez les prédictions avec les valeurs connues. Après avoir fait cela tout au long de nos données, nous avons un taux d'erreur pour k = 3. Nous faisons la même chose pour k = 1, k = 2, k = 4, et ainsi de suite, jusqu'à une valeur maximale de k que nous estimons être suffisante . Nous utilisons alors la valeur de k qui a fonctionné le mieux dans nos données de formation pour les prévisions futures.
Alors, comment pouvons-nous coder cela dans R? Voici une approche naïve:
preda <- function(x,k) {
Le coeur du code est la ligne 7. Là, nous prévoyons le jour i + k (la prévision à stocker dans pred [i]) à partir des k jours précédents, c'est-à-dire les jours i, ..., i + k-1. Ainsi, nous devons compter les 1s parmi ces jours. Puisque nous sommes
en travaillant avec 0 et 1 données, le nombre de 1s est simplement la somme de x [j] parmi ces jours, que nous pouvons facilement obtenir comme suit:
L'utilisation de sum () et l'indexation vectorielle nous permettent de faire ce calcul de manière compacte, en évitant la nécessité d'écrire une boucle, donc c'est plus simple et plus rapide. C'est typique R.
Il en va de même pour cette expression, à la ligne 9: moyenne (abs (pred-x [(k + 1): n]))
Ici, pred contient les valeurs prédites, tandis que x [(k + 1): n] a les valeurs réelles pour les jours en question. En soustrayant le second du premier, nous donnons des valeurs de 0, 1 ou -1. Ici, 1 ou -1 correspondent à des erreurs de prédiction dans un sens ou l'autre, en prédisant 0 lorsque la valeur réelle était 1 ou vice versa. En prenant des valeurs absolues avec abs (), nous avons 0s et 1s, ce dernier correspondant à des erreurs.
Nous savons maintenant où les jours nous ont donné des erreurs. Il reste à calculer la proportion d'erreurs. Nous faisons cela en appliquant mean (), où nous exploitons le fait mathématique que la moyenne des données 0 et 1 est la proportion de 1s. Il s'agit d'un tour R courant.
Le codage ci-dessus de notre fonction preda () est assez simple, et il présente l'avantage de la simplicité et de la compacité. Cependant, il est évidemment lent. Nous pourrions essayer de l'accélérer en vectorisant la boucle, comme indiqué dans la .6. Cependant, cela ne résoudrait pas l'obstacle majeur à la vitesse ici, qui est tout le calcul en double que le code fait. Pour les valeurs successives de i dans la boucle, sum () est appelé des vecteurs qui ne diffèrent que par deux éléments. Sauf pour les cas où k est très petit, cela pourrait vraiment ralentir les choses.
Alors, réécrivons le code pour profiter du calcul précédent. Dans chaque itération de la boucle, nous mettrons à jour la somme précédente que nous avons trouvée, plutôt que de calculer la nouvelle somme à partir de zéro.
La clé est la ligne 9. Ici, nous mettons à jour sm, en soustrayant l'élément le plus ancien constituant la somme (x [i-l]) et en ajoutant le nouveau (x [i + k-l]).
Encore une autre approche de ce problème est d'utiliser la fonction R cumsum (), qui forme des sommes cumulées à partir d'un vecteur. Voici un exemple:
Ici, les sommes cumulées de y sont 5 = 5, 5 + 2 = 7, 5 + 2+ (-3) = 4, et 5 + 2 + (-3) +8 = 12, les valeurs renvoyées par cumsum ().
La somme d'expression (x [i: (i + (k-l)) dans preda () dans l'exemple suggère d'utiliser les différences de cumsum () à la place:
Au lieu d'appliquer la fonction sum () à une fenêtre de k éléments consécutifs en x, comme ceci:
nous calculons cette même somme en trouvant la différence entre les sommes cumulées à la fin et au début de cette fenêtre, comme ceci:
Notez la précontrainte d'un 0 dans le vecteur des sommes cumulées:
Ceci est nécessaire pour traiter correctement le cas i = 1.
Cette approche dans predc () nécessite une opération de soustraction par itération de la boucle, par rapport à deux dans predb ().