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.