Les fonctions (premier contact)

Nous avons vu dans les précédents articles (Le découpage de fichiers “à plat” et Touche pas au RSS ! (ben si en fait…)) comment charger des données depuis un fichier. Cependant, il faut bien dire que devoir, à chaque fois qu’on charge un RSS, retaper la liste des définitions de colonnes et les mutate de formatage est un peu longuet.

C’est donc le moment d’introduire la notion de fonction (function en anglais)

Qu’est-ce-qu’une fonction ?

C’est un regroupement d’instruction s’exécutant en masse sur des données.

Depuis le début nous avons utilisé de nombreuses fonctions, pour n’en citer que quelques unes : mean(), mutate(), group_by(), etc…

une fonction est définie par un « nom » et un ensemble de paramètres dont certains peuvent-être optionnels.

En R, les paramètres d’une fonction peuvent être fixés soit par position, soit par nom, soit un peu des deux.

Si je veux écrire une fonction qui multiplie une valeur par une autre, je peux imaginer la fonction multiplie() qui attendra 2 paramètres que je nomme a et b et retournera le produit a*b.

Le prototype de la fonction sera donc multiplie(a, b)et je pourrais l’appeler par exemple en faisant :

multiplie(1, 2)
ou
multiplie(a = 1, b = 2)
ou
multiplie(b = 2, a = 1)
ou encore
multiplie(1, b = 2)
ou enfin (mais je vous le déconseille)
multiplie(b = 2, 1)

Comment définit-on une fonction ?

Une fonction est une variable comme une autre. Elle s’attribue donc via « <- » et grâce à la fonction function() suivie d’un ensemble de commandes la plupart du temps entourées d’accolades { }.

Cela donne donc pour notre fonction multiplie().

multiplie <- function(a, b){
          a * b
}

la valeur de retour d’une fonction est la dernière valeur retournée par son contenu, ou il est possible d’utiliser la commande return() pour interrompre le traitement et retourner la valeur spécifiée. On peut donc écrire :

multiplie <- function(a, b){
          return(a * b)
}

qui revient strictement au même.

Et nous pouvons exécuter nos exemples ci-dessus :

> multiplie(1, 2)
[1] 2
> multiplie(a = 1, b = 2)
[1] 2
> multiplie(b = 2, a = 1)
[1] 2
> multiplie(1, b = 2)
[1] 2
> multiplie(b = 2, 1)
[1] 2

Il existe une version plus compacte (les accolades sont omises mais le corps de la fonction doit tenir sur une ligne) pour les fonctions très courtes qui est donc utilisable ici :

multiplie <- function(a, b) a*b

Première fonction

Nous pouvons définir par exemple la fonction lit_ium() qui permettrait de lire en une ligne un fichier d’UM. Pour cela il convient d’écrire :

lit_ium <- function(fichier) {
       read_fwf( file = fichier,
                 col_positions = fwf_cols(UM     = c(1, 4),
                                          FINESS = c(5, 13),
                                          AUTH   = c(14, 16), 
                                          DDEB   = c(17, 24),
                                          NLITS  = c(25, 27),
                                          MODE   = c(28,28)
                 ), 
                 col_types="ccccnc"
       ) %>% mutate( DDEB = as.Date(DDEB, format = "%d%m%Y"))
}

Il suffira alors d’appeler la fonction par

> lit_ium("DEF.IUM")
# A tibble: 32 x 6
   UM    FINESS    AUTH  DDEB       NLITS MODE 
   <chr> <chr>     <chr> <date>     <dbl> <chr>
 1 2055  330780529 NA    2020-01-01    NA C    
 2 1101  330780529 11    2020-01-01    NA M    
 3 3505  330780529 07    2020-01-01    NA C    
 4 1201  330780529 11    2020-01-01    NA M    
 5 3252  330780529 03    2020-01-01    NA C    
 6 2251  330780529 11    2020-01-01    NA P    
 7 2051  330780529 11    2020-01-01    NA P    
 8 1002  330780529 NA    2020-01-01    NA C    
 9 1001  330780529 11    2020-01-01    NA M    
10 2451  330780529 11    2020-01-01    NA P    
# ... with 22 more rows

>ums <- lit_ium("DEF.IUM") # pour stocker le résultat dans une variable

Les paramètres optionnels

Pour définir qu’un paramètre est optionnel, il suffit dans le prototype de la fonction de lui définir une valeur par défaut. Essayons dans l’état de lancer multiplie() avec une seule valeur :

> multiplie(1)
Error in multiplie(1) : argument "b" is missing, with no default

Pour permettre cette exécution, il suffit de préciser

multiplie <- function(a, b = 1){
          a * b
}

Alors :

> multiplie(1)
[1] 1

Notre code s’exécute et renvoi a*1 soit la valeur du paramètre a.

Et si je veux utiliser une fonction avec un %>% ?

Je l’ai déjà évoqué rapidement et cela va tout de suite parler aux personnes utilisant Python.

x%>% appel_fonction(...) est un raccourci pour appel_fonction(x,...)

Il suffit donc d’écrire sa fonction en utilisant la part gauche du pipe en 1er paramètre.

Exercices

En vous basant sur les fonctions définies dans les articles précédents, écrivez une fonction pour

  • lire le RSS contenu dans le fichier dont le nom est passé en paramètre (protoype de fonction : lit_rss(fichier))
  • transformer un ensemble de RUM d’un jeu de données RSS en un ensemble de séjours (nom de fonction : synthese_sejours(rss))
  • Et utiliser ces fonctions pour qu’en une ligne on trouve le nombre de séjours dans un fichier
lit_rss <- function(fichier){
       read_fwf(file = fichier,
                col_positions = fwf_cols(GHMC = c(3, 8),
                                         SEV  = c(8, 8),
                                         RGHM = c(3, 7),
                                         CMD  = c(3, 4),
                                         NRSS = c(28, 47),
                                         NRUM = c(68, 77),
                                         NDA  = c(48, 67),
                                         SEXE = c(86, 86),
                                         DN   = c(78, 85),
                                         DENT = c(93, 100),
                                         DSORT= c(103, 110),
                                         MENT = c(101, 101),
                                         CENT = c(102, 102),
                                         MSORT= c(111, 111),
                                         CSORT= c(112, 112),
                                         UM   = c(87, 90) 
                                         ),
                col_types = paste(rep("c", times = 16), collapse = "")
) %>%
  mutate( DN = as.Date(DN, format = "%d%m%Y"),
          DENT = as.Date(DENT, format = "%d%m%Y"),
          DSORT = as.Date(DSORT, format = "%d%m%Y")
          )
}

synthese_sejours <- function(rss){
               rss %>%
               group_by(NDA) %>%
               arrange(DENT,DSORT) %>%
               summarise(DENT = first(DENT),
                         DSORT = last(DSORT),
                         MultiRUM = n(),
                         MENT = first(MENT),
                         CENT = first(CENT),
                         MSORT = last(MSORT),
                         CSORT = last(CSORT),
                         CMD = first(CMD),
                         SEV = first(SEV),
                         GHMC = first(GHMC),
                         RGHM = first(RGHM)
               )
}

#On peut donc faire :
lit_rss("DEF.RSS") %>% synthese_sejours %>% nrow
[1] 22727

Conclusion

Nous venons de créer des fonctions qui nous permettent de simplifier la lecture de notre code. Mais de nombreux écueils existent nous en parlerons dans un prochain article.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *