Structure de la programmation R

R est un langage structuré en bloc comme C, C ++, Python, Perl, etc. Comme vous l'avez fait déjà vu, les blocs sont délimités par des accolades, bien que les accolades sont facultatives si le bloc se compose d'une simple déclaration. Les déclarations sont séparées par des caractères de nouvelle ligne ou, éventuellement, par des points-virgules.
Dans cette partie, nous allons couvrir les structures de base de R en tant que langage de programmation. Nous allons passer en revue quelques détails supplémentaires sur les boucles, puis continuer tout droit dans le sujet des fonctions, qui occuperont la majeure partie de cette partie.
Comme pour beaucoup langages de script, vous ne "déclarez" pas les variables dans R.

La valeur de retour d'une fonction peut être n'importe quel objet R. Bien que la valeur de retour soit souvent une liste, elle pourrait même être une autre fonction.
Vous pouvez transmettre une valeur à l'appelant en appelant explicitement return (). Sans cet appel, la valeur de la dernière instruction exécutée sera renvoyée par défaut. Par exemple, considérons l'exemple oddcount () du chapitre 1:

  1. > oddcount
  2. }
  3. k <- 0 # assign 0 to k
  4. for (n in x) {
  5. if (n %% 2 == 1) k <- k+1 # %% is the modulo operator
  6. }
Source code
Cette fonction renvoie le nombre de nombres impairs dans l'argument. Nous pourrions simplifier légèrement le code en éliminant l'appel à return (). Pour ce faire, nous évaluons l'expression à renvoyer, k, comme notre dernière déclaration dans le code:

  1. oddcount <- function(x) {
  2. k<-0
  3. }
  4. pagebreak
  5. for (n in x) {
  6. if(n%%2==1)k<-k+1
  7. }
  8. k
Source code

D'autre part, considérez ce code:

  1. oddcount <- function(x) {
  2. k<-0
  3. for (n in x) {
  4. if(n%%2==1)k<-k+1
  5. }
  6. }
Source code
Cela ne fonctionnerait pas, pour une raison assez subtile: La dernière instruction exécutée ici est l'appel à for (), qui renvoie la valeur NULL (et le fait, dans le jargon R, invisiblement, ce qui signifie qu'il est rejeté s'il n'est pas stocké par affectation). Ainsi, il n'y aurait pas de valeur de retour du tout.


1 Décider d'appeler explicitement return ()
Le R idiom dominant est d'éviter les appels explicites à return (). L'une des raisons invoquées pour cette approche est que l'appel de cette fonction allonge le temps d'exécution. Cependant, à moins que la fonction ne soit très courte, le temps économisé est négligeable, donc cela pourrait ne pas être la raison la plus convaincante de ne pas utiliser return (). Mais cela n'est généralement pas nécessaire.
Considérons notre deuxième exemple de la section précédente:

  1. oddcount <- function(x) {
  2. k<-0
  3. for (n in x) {
  4. }
  5. if(n%%2==1)k<-k+1
  6. }
  7. k
Source code
Ici, nous avons simplement terminé avec une déclaration listant l'expression à renvoyer - dans ce cas, k. Un appel à return () n'était pas nécessaire. Le code de ce livre inclut généralement un appel à return (), pour plus de clarté pour les débutants, mais il est de coutume de l'omettre.
Une bonne conception de logiciel, cependant, devrait signifier que vous pouvez regarder à travers le code d'une fonction et repérer immédiatement les différents points sur lesquels le contrôle est retourné à l'appelant. La façon la plus simple d'y parvenir consiste à utiliser un appel return () explicite dans toutes les lignes au milieu du code qui provoquent un retour. (Vous pouvez toujours omettre un appel return () à la fin de la fonction si vous le souhaitez.)


2 Retour d'objets complexes
La valeur de retour pouvant être n'importe quel objet R, vous pouvez renvoyer des objets complexes. Voici un exemple de fonction renvoyée:

  1. >g
  2. }
  3. t <- function(x) return(x^2)
  4. > g()
  5. <environment: 0x8aafbc0>
Source code
Si votre fonction a plusieurs valeurs de retour, placez-les dans une liste ou un autre conteneur.

R est un langage structuré par blocs dans la famille des descendants ALGOL, comme C, C ++, Python, Perl, etc. Comme vous l'avez vu, les blocs sont délimités par des accolades, bien que les accolades soient facultatives si le bloc ne comporte qu'une seule instruction. Les instructions sont séparées par des caractères newline ou, éventuellement, par des points-virgules.
Ici, nous couvrons les structures de base de R en tant que langage de programmation. Nous allons examiner quelques détails supplémentaires sur les boucles et autres, puis directement dans le sujet des fonctions, qui occuperont la majeure partie du chapitre.
En particulier, les questions de portée variable joueront un rôle majeur. Comme pour beaucoup de langages de script, vous ne déclarez pas de variables dans R. Les programmeurs qui ont un arrière-plan dans, par exemple, le langage C, trouveront des similarités dans R au début, mais verront que R a une structure de portée plus riche.

Comme indiqué à plusieurs reprises dans ce cours, le but de la fonction R () est de créer des fonctions. Par exemple, considérez ce code:

  1. inc <- function(x) return(x+1)
Source code
Il demande à R de créer une fonction qui ajoute 1 à son argument, puis assigne cette fonction à inc. Cependant, cette dernière étape - la mission - n'est pas toujours prise. Nous pouvons simplement utiliser l'objet de fonction créé par notre appel à function () sans nommer cet objet. Les fonctions dans ce contexte sont appelées anonymes, puisqu'elles n'ont pas de nom. (C'est un peu trompeur, car même les fonctions non anonymes n'ont qu'un nom dans le sens où une variable les pointe vers eux.)
Les fonctions anonymes peuvent être pratiques si elles sont courtes et sont appelées par une autre fonction. Revenons à notre exemple d'utilisation à la section 3.3:

  1. >z
  2. [,1] [,2]
  3. [1,] 1 4
  4. [2,] 2 5
  5. [3,] 3 6
  6. > f <- function(x) x/c(2,8)
  7. > y <- apply(z,1,f)
  8. >y
  9. [,1] [,2] [,3]
  10. [1,] 0.5 1.000 1.50
  11. [2,] 0.5 0.625 0.75
Source code
Nous allons contourner l'intermédiaire, c'est-à-dire ignorer l'affectation à f en utilisant une fonction anonyme dans notre appel à apply (), comme suit:

  1. > y <- apply(z,1,function(x) x/c(2,8))
  2. >y
  3. [,1] [,2] [,3]
  4. [1,] 0.5 1.000 1.50
  5. [2,] 0.5 0.625 0.75
Source code
Qu'est-ce qui s'est vraiment passé ici? Le troisième argument formel à apply () doit être une fonction, ce qui est exactement ce que nous avons fourni ici, puisque la valeur de retour de function () est une fonction!
Faire les choses de cette façon est souvent plus clair que de définir la fonction de manière externe. Bien sûr, si la fonction est plus compliquée, cette clarté n'est pas atteinte.

Vous pouvez inventer vos propres opérations! Il suffit d'écrire une fonction dont le nom s'écrit et se termine par%, avec deux arguments d'un certain type, et une valeur de retour de ce type.
Par exemple, voici une opération binaire qui ajoute le deuxième opérande au premier:

  1. > "%a2b%" <- function(a,b) return(a+2
  2. *
  3. b)
  4. > 3 %a2b% 5
  5. [1] 13
Source code

Un exemple moins trivial est donné dans la section sur les opérations d'ensemble de la section 8.5.