173 votes

Comment formater un nombre en pourcentage dans R ?

L'une des choses qui me laissait perplexe en tant que novice de R était de savoir comment formater un nombre en pourcentage pour l'impression.

Par exemple, affichez 0.12345 como 12.345% . Je dispose d'un certain nombre de solutions de contournement, mais aucune d'entre elles ne semble être "conviviale pour les nouveaux venus". Par exemple :

set.seed(1)
m <- runif(5)

paste(round(100*m, 2), "%", sep="")
[1] "26.55%" "37.21%" "57.29%" "90.82%" "20.17%"

sprintf("%1.2f%%", 100*m)
[1] "26.55%" "37.21%" "57.29%" "90.82%" "20.17%"

Question : Existe-t-il une fonction R de base pour faire cela ? Sinon, existe-t-il un paquetage largement utilisé qui fournit une enveloppe pratique ?


Malgré la recherche de quelque chose comme ça dans ?format , ?formatC y ?prettyNum Je n'ai pas encore trouvé d'enveloppe convenable dans R de base. ??"percent" n'a rien donné d'utile. library(sos); findFn("format percent") renvoie 1250 occurrences - donc encore une fois pas utile. ggplot2 a une fonction percent mais cela ne permet pas de contrôler la précision des arrondis.

7 votes

sprintf semble être la solution préférée sur les listes de diffusion, et je n'ai pas vu de meilleure solution. Toute fonction intégrée ne sera pas beaucoup plus simple à appeler de toute façon, n'est-ce pas ?

1 votes

A mon avis sprintf est parfaitement adapté au sous-ensemble des codeurs R qui sont aussi des programmeurs. J'ai beaucoup codé dans ma vie, y compris en COBOL (frisson) et en fortran (montre mon âge). Mais je ne considère pas le sprintf règles de formatage évidentes (traduction : WTF ?). Et bien sûr, un wrapper dédié doit être plus facile à appeler que sprintf, par exemple : format_percent(x=0.12345, digits=2)

0 votes

@hircus Je pense que c'est assez commun pour mériter sa propre fonction curry courte. C'est particulièrement un problème avec Sweave, où \Sexpr {sprintf(%1.2f%%",myvar)} est bien plus moche que \Sexpr {pct(myvar)} ou toute autre fonction plus courte.

151voto

Richie Cotton Points 35365

Même plus tard :

Comme l'a souligné @DzimitryM, percent() a été "retiré" en faveur de label_percent() qui est un synonyme de l'ancien percent_format() fonction.

label_percent() renvoie une fonction, donc pour l'utiliser, vous avez besoin d'une paire de parenthèses supplémentaire.

library(scales)
x <- c(-1, 0, 0.1, 0.555555, 1, 100)
label_percent()(x)
## [1] "-100%"   "0%"      "10%"     "56%"     "100%"    "10 000%"

Personnalisez-le en ajoutant des arguments à l'intérieur de la première série de parenthèses.

label_percent(big.mark = ",", suffix = " percent")(x)
## [1] "-100 percent"   "0 percent"      "10 percent"    
## [4] "56 percent"     "100 percent"    "10,000 percent"

Une mise à jour, plusieurs années plus tard :

De nos jours, il existe un percent dans le scales comme indiqué dans la réponse de krlmlr. Utilisez cette solution au lieu de la mienne.


Essayez quelque chose comme

percent <- function(x, digits = 2, format = "f", ...) {
  paste0(formatC(100 * x, format = format, digits = digits, ...), "%")
}

Avec l'usage, par exemple,

x <- c(-1, 0, 0.1, 0.555555, 1, 100)
percent(x)

(Si vous préférez, changez le format de "f" a "g" .)

2 votes

Oui, cela fonctionne, et c'est une version légèrement plus générale de la solution de contournement que j'ai fournie dans la question. Mais ma vraie question est de savoir si cela existe dans la base R ou non.

0 votes

Cela fonctionne pour moi dans liste les pourcentages, mais remplacer "x" par "pourcentage(x)" dans une commande statistique ou graphique produit un message d'erreur.

0 votes

@rolando2 Ma réponse et celle de krlmlr renvoient toutes deux des vecteurs de caractères en sortie, et non des nombres. Ils servent à formater les étiquettes des axes et autres. Peut-être voulez-vous simplement multiplier par 100 ?

81voto

krlmlr Points 5572

Consultez le scales paquet. Il faisait partie de ggplot2 Je pense.

library('scales')
percent((1:10) / 100)
#  [1] "1%"  "2%"  "3%"  "4%"  "5%"  "6%"  "7%"  "8%"  "9%"  "10%"

La logique intégrée pour détecter la précision devrait fonctionner suffisamment bien dans la plupart des cas.

percent((1:10) / 1000)
#  [1] "0.1%" "0.2%" "0.3%" "0.4%" "0.5%" "0.6%" "0.7%" "0.8%" "0.9%" "1.0%"
percent((1:10) / 100000)
#  [1] "0.001%" "0.002%" "0.003%" "0.004%" "0.005%" "0.006%" "0.007%" "0.008%"
#  [9] "0.009%" "0.010%"
percent(sqrt(seq(0, 1, by=0.1)))
#  [1] "0%"   "32%"  "45%"  "55%"  "63%"  "71%"  "77%"  "84%"  "89%"  "95%" 
# [11] "100%"
percent(seq(0, 0.1, by=0.01) ** 2)
#  [1] "0.00%" "0.01%" "0.04%" "0.09%" "0.16%" "0.25%" "0.36%" "0.49%" "0.64%"
# [10] "0.81%" "1.00%"

2 votes

Ne fonctionne pas pour les nombres négatifs. percent(-0.1) produit NaN%

1 votes

@akhmed : Cela a déjà été signalé, un correctif est disponible mais en attente de révision : github.com/hadley/scales/issues/50 . Notez que cela semble fonctionner pour plus d'un nombre négatif : scales::percent(c(-0.1, -0.2))

0 votes

Merci pour le lien ! Je ne savais pas si c'était une fonctionnalité ou un bug. Pour les numéros multiples, cela fonctionne parfois et parfois non. Dites, scales::percent(c(-0.1,-0.1,-0.1)) produit "NaN%" "NaN%" "NaN%" mais votre exemple fonctionne. Pour la référence des autres, le bogue n'est pas encore corrigé à la date d'aujourd'hui. scales_0.2.4 . De plus, à ce jour, la demande de retrait correspondante n'a pas encore été fusionnée dans la branche principale.

39voto

Liliana Pacheco Points 517

Consultez le percent de la fonction formattable paquet :

library(formattable)
x <- c(0.23, 0.95, 0.3)
percent(x)
[1] 23.00% 95.00% 30.00%

6 votes

+1, ce qui permet de spécifier le nombre de chiffres à inclure, qui scales::percent dans les deux premières réponses ne le fait pas.

3 votes

+1, même s'il est assez facile de créer sa propre fonction, permettre de choisir le nombre de chiffres est vraiment utile.

15voto

geneorama Points 620

Base R

Je préfère de loin utiliser sprintf qui est disponible dans la base R.

sprintf("%0.1f%%", .7293827 * 100)
[1] "72.9%"

J'aime particulièrement sprintf car vous pouvez également insérer des chaînes de caractères.

sprintf("People who prefer %s over %s: %0.4f%%", 
        "Coke Classic", 
        "New Coke",
        .999999 * 100)
[1] "People who prefer Coke Classic over New Coke: 99.9999%"

Il est particulièrement utile d'utiliser sprintf avec des choses comme les configurations de base de données ; il suffit de lire un fichier yaml, puis d'utiliser sprintf pour remplir un modèle sans un tas de méchancetés. paste0 's.

Exemple de motivation plus long

Ce modèle est particulièrement utile pour les rapports rmarkdown, lorsque vous avez beaucoup de texte et beaucoup de valeurs à agréger.

Mise en place / agrégation :

library(data.table) ## for aggregate

approval <- data.table(year = trunc(time(presidents)), 
                       pct = as.numeric(presidents) / 100,
                       president = c(rep("Truman", 32),
                                     rep("Eisenhower", 32),
                                     rep("Kennedy", 12),
                                     rep("Johnson", 20),
                                     rep("Nixon", 24)))
approval_agg <- approval[i = TRUE,
                         j = .(ave_approval = mean(pct, na.rm=T)), 
                         by = president]
approval_agg
#     president ave_approval
# 1:     Truman    0.4700000
# 2: Eisenhower    0.6484375
# 3:    Kennedy    0.7075000
# 4:    Johnson    0.5550000
# 5:      Nixon    0.4859091

Utilisation de sprintf avec des vecteurs de texte et de nombres, en sortant vers cat juste pour les nouvelles lignes.

approval_agg[, sprintf("%s approval rating: %0.1f%%",
                       president,
                       ave_approval * 100)] %>% 
  cat(., sep = "\n")
# 
# Truman approval rating: 47.0%
# Eisenhower approval rating: 64.8%
# Kennedy approval rating: 70.8%
# Johnson approval rating: 55.5%
# Nixon approval rating: 48.6%

Enfin, pour ma propre référence égoïste, puisque nous parlons de formatage, voici comment je fais les virgules avec la base R :

30298.78 %>% round %>% prettyNum(big.mark = ",")
[1] "30,299"

10voto

MichaelChirico Points 76

J'ai fait quelques tests de vitesse sur ces réponses et j'ai été surpris de voir que percent dans le scales tant vanté, étant donné sa lenteur. J'imagine que l'avantage est son détecteur automatique pour un formatage correct, mais si vous savez à quoi ressemblent vos données, il semble clair qu'il faut l'éviter.

Voici les résultats d'une tentative de formatage d'une liste de 100 000 pourcentages dans (0,1) en un pourcentage à deux chiffres :

library(microbenchmark)
x = runif(1e5)
microbenchmark(times = 100L, andrie1(), andrie2(), richie(), krlmlr())
# Unit: milliseconds
#   expr       min        lq      mean    median        uq       max
# 1 andrie1()  91.08811  95.51952  99.54368  97.39548 102.75665 126.54918 #paste(round())
# 2 andrie2()  43.75678  45.56284  49.20919  47.42042  51.23483  69.10444 #sprintf()
# 3  richie()  79.35606  82.30379  87.29905  84.47743  90.38425 112.22889 #paste(formatC())
# 4  krlmlr() 243.19699 267.74435 304.16202 280.28878 311.41978 534.55904 #scales::percent()

Así que sprintf s'impose comme un vainqueur incontestable lorsque nous voulons ajouter un signe de pourcentage. En revanche, si nous voulons seulement multiplier le nombre et l'arrondir (passer de la proportion au pourcentage sans "%"), alors round() est le plus rapide :

# Unit: milliseconds
#        expr      min        lq      mean    median        uq       max
# 1 andrie1()  4.43576  4.514349  4.583014  4.547911  4.640199  4.939159 # round()
# 2 andrie2() 42.26545 42.462963 43.229595 42.960719 43.642912 47.344517 # sprintf()
# 3  richie() 64.99420 65.872592 67.480730 66.731730 67.950658 96.722691 # formatC()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X