15  Mettre en forme des nombres

Dans les chapitres suivants, nous aurons régulièrement besoin, pour produire des tableaux ou des figures propres, de fonctions de formatage qui permettent de transformer des valeurs numériques en chaînes de texte.

La fonction R de base est format() mais de nombreux autres packages proposent des variations pour faciliter cette opération. Le plus complet est probablement scales et, notamment, ses fonctions scales::label_number() et scales::number().

Elles ont l’air très similaires et partagent un grand nombre de paramètres en commun. La différence est que scales::number() a besoin d’un vecteur numérique en entrée qu’elle va mettre en forme, tandis que que scales::label_number() renvoie une fonction que l’on pourra ensuite appliquer à un vecteur numérique.

library(scales)
x <- c(0.0023, .123, 4.567, 874.44, 8957845)
number(x)
[1] "0.00"         "0.12"         "4.57"         "874.44"       "8 957 845.00"
f <- label_number()
f(x)
[1] "0.00"         "0.12"         "4.57"         "874.44"       "8 957 845.00"
label_number()(x)
[1] "0.00"         "0.12"         "4.57"         "874.44"       "8 957 845.00"

Dans de nombreux cas de figure (par exemple pour un graphique ggplot2 ou un tableau gtsummary), il sera demandé de fournir une fonction de formatage, auquel cas on aura recours aux fonctions de scales préfixées par label_*() qui permettent donc de générer une fonction personnalisée.

15.1 label_number()

scales::label_number() est la fonction de base de mise en forme de nombres dans scales, une majorité des autres fonctions faisant appel à scales::label_number() et partageant les mêmes arguments.

Le paramètre accurary permets de définir le niveau d’arrondi à utiliser. Par exemple, .1 pour afficher une seule décimale. Il est aussi possible d’indiquer un nombre qui n’est pas une puissance de 10 (par exemple .25). Si on n’indique rien (NULL), alors scales::label_number() essaiera de deviner un nombre de décimales pertinent en fonction des valeurs du vecteur de nombres à mettre en forme.

label_number(accuracy = NULL)(x)
[1] "0.00"         "0.12"         "4.57"         "874.44"       "8 957 845.00"
label_number(accuracy = .1)(x)
[1] "0.0"         "0.1"         "4.6"         "874.4"       "8 957 845.0"
label_number(accuracy = .25)(x)
[1] "0.0"         "0.0"         "4.5"         "874.5"       "8 957 845.0"
label_number(accuracy = 10)(x)
[1] "0"         "0"         "0"         "870"       "8 957 840"

L’option scale permets d’indiquer un facteur multiplicatif à appliquer avant de mettre en forme. On utilisera le plus souvent les options prefix et suffix en même temps pour indiquer les unités.

label_number(scale = 100, suffix = "%")(x) # pour cent
[1] "0%"           "12%"          "457%"         "87 444%"      "895 784 500%"
label_number(scale = 1000, suffix = "\u2030")(x) # pour mille
[1] "2‰"             "123‰"           "4 567‰"         "874 440‰"      
[5] "8 957 845 000‰"
label_number(scale = .001, suffix = " milliers", accuracy = .1)(x)
[1] "0.0 milliers"     "0.0 milliers"     "0.0 milliers"     "0.9 milliers"    
[5] "8 957.8 milliers"

Les arguments decimal.mark et big.mark permettent de définir, respectivement, le séparateur de décimale et le séparateur de milliers. Ainsi, pour afficher des nombres à la française (virgule pour les décimales, espace pour les milliers) :

label_number(decimal.mark = ",", big.mark = " ")(x)
[1] "0,00"         "0,12"         "4,57"         "874,44"       "8 957 845,00"

Note : il est possible d’utiliser small.interval et small.mark pour ajouter des séparateurs parmi les décimales.

label_number(accuracy = 10^-9, small.mark = "|", small.interval = 3)(x)
[1] "0.002|300|000"         "0.123|000|000"         "4.567|000|000"        
[4] "874.440|000|000"       "8 957 845.000|000|000"

Les options style_positive et style_negative permettent de personnaliser la manière dont les valeurs positives et négatives sont mises en forme.

y <- c(-1.2, -0.3, 0, 2.4, 7.2)
label_number(style_positive = "plus")(y)
[1] "-1.2" "-0.3" "0.0"  "+2.4" "+7.2"
label_number(style_negative = "parens")(y)
[1] "(1.2)" "(0.3)" "0.0"   "2.4"   "7.2"  

L’option scale_cut permet d’utiliser, entre autres, les préfixes du Système international d’unités les plus proches et arrondi chaque valeur en fonction, en ajoutant la précision correspondante. Par exemple, pour des données en grammes :

y <- c(.000004536, .01245, 2.3456, 47589.14, 789456244)
label_number(scale_cut = cut_si("g"), accuracy = .1)(y)
[1] "4.5 µg"   "12.4 mg"  "2.3 g"    "47.6 kg"  "789.5 Mg"

15.2 Les autres fonctions de {scales}

15.2.1 label_comma()

scales::label_comma() (et scales::comma()) est une variante de scales::label_number() qui, par défaut, affiche les nombres à l’américaine, avec une virgule comme séparateur de milliers.

label_comma()(x)
[1] "0.00"         "0.12"         "4.57"         "874.44"       "8,957,845.00"

15.2.2 label_percent()

scales::label_percent() (et scales::percent()) est une variante de scales::label_number() qui affiche les nombres sous formes de pourcentages (les options par défaut sont scale = 100, suffix = "%").

label_percent()(x)
[1] "0%"           "12%"          "457%"         "87 444%"      "895 784 500%"

On peut utiliser cette fonction pour afficher des résultats en pour mille (le code Unicode du symbole ‰ étant u2030) :

label_percent(scale = 1000, suffix = "\u2030")(x)
[1] "2‰"             "123‰"           "4 567‰"         "874 440‰"      
[5] "8 957 845 000‰"

15.2.3 label_dollar()

scales::label_dollar() est adapté à l’affichage des valeurs monétaires.

label_dollar()(x)
[1] "$0"         "$0"         "$5"         "$874"       "$8,957,845"
label_dollar(prefix = "", suffix = " €", accuracy = .01, big.mark = " ")(x)
[1] "0.00 €"         "0.12 €"         "4.57 €"         "874.44 €"      
[5] "8 957 845.00 €"

L’option style_negative permet d’afficher les valeurs négatives avec des parenthèses, convention utilisée dans certaines disciplines.

label_dollar()(c(12.5, -4, 21, -56.36))
[1] "$12.50"  "-$4.00"  "$21.00"  "-$56.36"
label_dollar(style_negative = "parens")(c(12.5, -4, 21, -56.36))
[1] "$12.50"   "($4.00)"  "$21.00"   "($56.36)"

15.2.4 label_pvalue()

scales::label_pvalue() est adapté pour la mise en forme de p-valeurs.

label_pvalue()(c(0.000001, 0.023, 0.098, 0.60, 0.9998))
[1] "<0.001" "0.023"  "0.098"  "0.600"  ">0.999"
label_pvalue(accuracy = .01, add_p = TRUE)(c(0.000001, 0.023, 0.098, 0.60))
[1] "p<0.01" "p=0.02" "p=0.10" "p=0.60"

15.2.5 label_scientific()

scales::label_scientific() affiche les nombres dans un format scientifique (avec des puissances de 10).

label_scientific(unit = "g")(c(.00000145, .0034, 5, 12478, 14569787))
[1] "1.45e-06" "3.40e-03" "5.00e+00" "1.25e+04" "1.46e+07"

15.2.6 label_bytes()

scales::label_bytes() mets en forme des tailles exprimées en octets, utilisant au besoin des multiples de 1024.

b <- c(478, 1235468, 546578944897)
label_bytes()(b)
[1] "478 B"  "1 MB"   "547 GB"
label_bytes(units = "auto_binary")(b)
[1] "478 iB"  "1 MiB"   "509 GiB"

15.2.7 label_ordinal()

scales::label_ordinal() permets d’afficher des rangs ou nombres ordinaux. Plusieurs langues sont disponibles.

label_ordinal()(1:5)
[1] "1st" "2nd" "3rd" "4th" "5th"
label_ordinal(rules = ordinal_french())(1:5)
[1] "1er" "2e"  "3e"  "4e"  "5e" 
label_ordinal(rules = ordinal_french(gender = "f", plural = TRUE))(1:5)
[1] "1res" "2es"  "3es"  "4es"  "5es" 

15.2.8 label_date(), label_date_short() & label_time()

scales::label_date(), scales::label_date_short() et scales::label_time() peuvent être utilisées pour la mise en forme de dates.

label_date()(as.Date("2020-02-14"))
[1] "2020-02-14"
label_date(format = "%d/%m/%Y")(as.Date("2020-02-14"))
[1] "14/02/2020"
label_date_short()(as.Date("2020-02-14"))
[1] "14\nfévr.\n2020"

La mise en forme des dates est un peu complexe. Ne pas hésiter à consulter le fichier d’aide de la fonction base::strptime() pour plus d’informations.

15.2.9 label_wrap()

La fonction scales::label_wrap() est un peu différente. Elle permets d’insérer des retours à la ligne (\n) dans des chaines de caractères. Elle tient compte des espaces pour identifier les mots et éviter ainsi des coupures au milieu d’un mot.

x <- "Ceci est un texte assez long et que l'on souhaiterait afficher sur plusieurs lignes. Cependant, on souhaite éviter que des coupures apparaissent au milieu d'un mot."
label_wrap(80)(x)
[1] "Ceci est un texte assez long et que l'on souhaiterait afficher sur plusieurs\nlignes. Cependant, on souhaite éviter que des coupures apparaissent au milieu\nd'un mot."
label_wrap(80)(x) |> message()
Ceci est un texte assez long et que l'on souhaiterait afficher sur plusieurs
lignes. Cependant, on souhaite éviter que des coupures apparaissent au milieu
d'un mot.
label_wrap(40)(x) |> message()
Ceci est un texte assez long et que
l'on souhaiterait afficher sur
plusieurs lignes. Cependant, on
souhaite éviter que des coupures
apparaissent au milieu d'un mot.

15.3 Les fonctions de formatage de {gtsummary}

Véritable couteau-suisse du statisticien, le package gtsummary sera largement utilisé dans les prochains chapitres pour produire des tableaux statistiques prêts à être publiés.

Ce package utilise par défaut ses propres fonctions de formatage mais, au besoin, il sera toujours possible de lui transmettre des fonctions de formatage créées avec scales.

15.3.1 style_number()

Fonction de base, gtsummary::style_number() accepte les paramètres big.mark (séparateur de milliers), decimal.mark (séparateur de décimales) et scale (facteur d’échelle). Le nombre de décimales se précisera quant à lui avec digits où l’on indiquera le nombre de décimales souhaité.

library(gtsummary)
#Uighur
x <- c(0.123, 0.9, 1.1234, 12.345, -0.123, -0.9, -1.1234, -132.345)
style_number(x, digits = 1)
[1] "0.1"    "0.9"    "1.1"    "12.3"   "-0.1"   "-0.9"   "-1.1"   "-132.3"
Astuce

Nous verrons dans le chapitre sur les statistiques univariées (cf. Section 18.2.1) la fonction gtsummary::theme_gtsummary_language() qui permet de fixer globalement le séparateur de milliers et celui des décimales, afin de changer les valeurs par défaut de l’ensemble des fonctions de formatage de gtsummary.

Il est important de noter que cela n’a aucun effet sur les fonctions de formatage de scales.

Mise en garde

gtsummary::style_number() est directement une fonction de formatage (comme scales::number()) et non une fonction qui génère une fonction de formatage (comme scales::label::number()).

Pour créer une fonction de formatage personnalisée, on pourra avoir recours à purrr::partial() qui permet d’appeler partiellement une fonction et qui renvoie une nouvelle fonction avec des paramètres par défaut personnalisés.

fr <- style_number |>
  purrr::partial(decimal.mark = ",", digits = 1)
fr(x)
[1] "0,1"    "0,9"    "1,1"    "12,3"   "-0,1"   "-0,9"   "-1,1"   "-132,3"

15.3.2 style_sigfig()

Variante de gtsummary::style_number(), gstummary::style_sigfig() arrondi les valeurs transmises pour n’afficher qu’un nombre choisi de chiffres significatifs. Le nombre de décimales peut ainsi varier.

style_sigfig(x)
[1] "0.12"  "0.90"  "1.1"   "12"    "-0.12" "-0.90" "-1.1"  "-132" 
style_sigfig(x, digits = 3)
[1] "0.123"  "0.900"  "1.12"   "12.3"   "-0.123" "-0.900" "-1.12"  "-132"  

15.3.3 style_percent()

La fonction gtsummary::style_percent() a un fonctionnement un peu différent de celui de scales::label_percent(). Par défaut, le symbole % n’est pas affiché (mais paramétrable avec symbol = TRUE. Par défaut, une décimale est affichée pour les valeurs inférieures à 10% et aucune pour celles supérieures à 10%. Un symbole < est ajouté devant les valeurs strictement positives inférieures à 0,1%.

v <- c(0, 0.0001, 0.005, 0.01, 0.10, 0.45356, 0.99, 1.45)
label_percent(accuracy = .1)(v)
[1] "0.0%"   "0.0%"   "0.5%"   "1.0%"   "10.0%"  "45.4%"  "99.0%"  "145.0%"
style_percent(v)
[1] "0"    "<0.1" "0.5"  "1.0"  "10"   "45"   "99"   "145" 
style_percent(v, symbol = TRUE)
[1] "0%"    "<0.1%" "0.5%"  "1.0%"  "10%"   "45%"   "99%"   "145%" 
style_percent(v, digits = 1)
[1] "0"     "0.01"  "0.50"  "1.00"  "10.0"  "45.4"  "99.0"  "145.0"

15.3.4 style_pvalue()

La fonction gtsummary::style_pvalue() est similaire à scales::label_pvalue() mais adapte le nombre de décimales affichées,

p <- c(0.000001, 0.023, 0.098, 0.60, 0.9998)
label_pvalue()(p)
[1] "<0.001" "0.023"  "0.098"  "0.600"  ">0.999"
style_pvalue(p)
[1] "<0.001" "0.023"  "0.10"   "0.6"    ">0.9"  
style_pvalue(p, prepend_p = TRUE)
[1] "p<0.001" "p=0.023" "p=0.10"  "p=0.6"   "p>0.9"  

15.3.5 style_ratio()

Enfin, gtsummary::style_ratio() est adaptée à l’affichage de ratios.

r <- c(0.123, 0.9, 1.1234, 12.345, 101.234, -0.123, -0.9, -1.1234, -12.345, -101.234)
style_ratio(r)
 [1] "0.12"  "0.90"  "1.12"  "12.3"  "101"   "-0.12" "-0.90" "-1.12" "-12.3"
[10] "-101" 

15.4 Bonus : signif_stars() de {ggstats}

La fonction ggstats::signif_stars() de ggstats permet d’afficher des p-valeurs sous forme d’étoiles de significativité. Par défaut, trois astérisques si p < 0,001, deux si p < 0,01, une si p < 0,05 et un point si p < 0,10. Les valeurs sont bien sur paramétrables.

p <- c(0.5, 0.1, 0.05, 0.01, 0.001)
ggstats::signif_stars(p)
[1] ""    "."   "*"   "**"  "***"
ggstats::signif_stars(p, one = .15, point = NULL)
[1] ""    "*"   "*"   "**"  "***"

15.5