Cela peut vraiment simplifier notre code et, en outre, nous donner une augmentation spectaculaire des performances de centaines ou plus.
L'un des moyens les plus efficaces pour obtenir de la vitesse dans le code R consiste à utiliser des opérations vectorisées, ce qui signifie qu'une fonction appliquée à un vecteur est appliquée de manière réelle individuellement à chaque élément.
1 Vector In, Vector Out
Vous avez vu des exemples de fonctions vectorisées plus tôt dans le chapitre, avec les opérateurs + et *. Un autre exemple est ">".
Ici, la fonction > a été appliquée à u [1] et v [1], résultant en TRUE, puis à [2] et v [2], ce qui entraîne FALSE, etc.
Un point clé est que si une fonction R utilise des opérations vectorisées, elle est également vectorisée, ce qui permet une accélération potentielle. Voici un exemple:
Ici, w () utilise +, qui est vectorisé, donc w () est vectorisé aussi. Comme vous pouvez le voir, il existe un nombre illimité de fonctions vectorisées, car les complexes sont construits à partir de simples.
Notez que même les fonctions transcendantales - les racines carrées, les journaux, les fonctions trigonométriques, etc. - sont vectorisées.
[1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 [9] 3.000000
> sqrt (1: 9)
[1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427 [9] 3.000000
Le fait est que la fonction rond () est appliquée individuellement à chaque élément dans le vecteur y. Et rappelez-vous que les scalaires sont vraiment des vecteurs à élément unique, de sorte que l'utilisation "ordinaire" de round () onjust one number est simplement un cas spécial.
Ici, nous avons utilisé la fonction intégrée round (), mais vous pouvez faire la même chose avec des fonctions que vous écrivez.
Comme mentionné précédemment, même les opérateurs tels que + sont vraiment des fonctions. Par exemple, considérez ce code:
La raison pour laquelle l'addition par élément de 4 fonctionne ici est que le + est en fait une fonction! Ici, il est explicitement:
Notez également que le recyclage a joué un rôle clé ici, avec les 4 recyclés dans
(4,4,4).
Comme nous savons que R n'a pas de scalaires, considérons les fonctions vectorisées qui semblent avoir des arguments scalaires.
Dans notre définition de f () ici, nous avons clairement l'intention de c pour être un scalaire, mais bien sûr, il s'agit en fait d'un vecteur de longueur 1. Même si nous utilisons un seul nombre pour c dans notre appel à f (), il sera étendu par recyclage à un vecteur pour notre calcul de x + c dans f (). Donc, dans notre appel f (1: 3, 1) dans l'exemple, la quantité x + c devient la suivante:
Cela soulève une question de sécurité du code. Il n'y a rien dans f () qui nous empêche d'utiliser un vecteur explicite pour c, comme dans cet exemple:
Vous devriez travailler à travers le calcul pour confirmer que (4,16,36) est en effet la sortie attendue.
Si vous souhaitez vraiment restreindre c aux scalaires, vous devez insérer une sorte de vérification, disons ceci:
> f }
> f
function(x,c) {
if (length(c) != 1) stop("vector c not allowed")
return((x+c)^2)
}
2 Vector In, Matrix Out
Les fonctions vectorisées avec lesquelles nous travaillons jusqu'à présent ont des valeurs de retour scalaires. Appeler sqrt () sur un numéro nous donne un numéro. Si nous appliquons cette fonction à un vecteur à huit éléments, nous obtenons huit nombres, donc un autre vecteur à huit éléments, comme sortie.
Mais que faire si notre fonction elle-même est vectorielle, comme z12 ():
L'application de z12 () à 5, par exemple, nous donne le vecteur à deux éléments (5,25). Si nous appliquons cette fonction à un vecteur à huit éléments, il produit 16 nombres:
Il pourrait être plus naturel de disposer de cette matrice 8-par-2 que nous pouvons faire avec la fonction matricielle:
[,1] [,2] [1,] 1 1 [2,] 2 4 [3,] 3 9 [4,] 4 16 [5,] 5 25 [6,] 6 36 [7,] 7 49 [8,] 8 64
> matrix(z12(x),ncol=2)
[,1] [,2]
[1,] 1 1
[2,] 2 4
[3,] 3 9
[4,] 4 16
[5,] 5 25
[6,] 6 36
[7,] 7 49
[8,] 8 64
Mais nous pouvons rationaliser les choses en utilisant sapply () (ou simplifier appliquer). L'appel sapply (x, f) applique la fonction f () à chaque élément de x puis convertit le résultat en une matrice. Voici un exemple:
Nous obtenons une matrice 2 par 8, pas une 8 par seconde, mais c'est tout aussi utile de cette façon. Nous allons discuter de sapply () plus loin dans le chapitre 4.