web-dev-qa-db-fra.com

Comment formater un nombre sous forme de pourcentage dans R?

Une des choses qui me laissait perplexe quand j'étais nouveau chez R était de savoir comment formater un nombre sous forme de pourcentage pour l’impression.

Par exemple, affichez 0.12345 sous la forme 12.345%. J'ai un certain nombre de solutions de contournement pour cela, mais aucune d'entre elles ne semble être "amicale". 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 de base R pour le faire? Sinon, existe-t-il un paquet largement utilisé offrant un wrapper pratique?


Bien que nous ayons cherché quelque chose comme ceci dans ?format, ?formatC et ?prettyNum, je n’ai pas encore trouvé d’emballage approprié en base R. ??"percent" ne donne rien d’utile. library(sos); findFn("format percent") renvoie 1250 résultats - encore une fois inutile. ggplot2 a une fonction percent mais cela ne permet pas de contrôler la précision de l'arrondi.

112
Andrie

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

Ces jours-ci, il existe une fonction percent dans le package scales , comme indiqué dans la réponse de krlmlr. Utilisez cela au lieu de ma solution roulée à la main.


Essayez quelque chose comme

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

Avec l'utilisation, par exemple,

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

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

106
Richie Cotton

Découvrez le package scales . Cela 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 permettant de détecter la précision devrait fonctionner assez 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%"
66
krlmlr

Découvrez la fonction percent du package formattable:

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

J’ai fait quelques analyses comparatives des réponses rapides et j’ai été surpris de voir percent dans le package scales ainsi vanté, compte tenu de sa lenteur. J'imagine que l'avantage réside dans son détecteur automatique permettant un formatage correct, mais si vous savez à quoi ressemblent vos données, il semble évident qu'elles doivent être évitées.

Voici les résultats de la tentative de formater une liste de 100 000 pourcentages de (0,1) en pourcentage à 2 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()

Donc, sprintf apparaît clairement comme un gagnant lorsque nous voulons ajouter un signe de pourcentage. Par contre, si nous voulons seulement multiplier le nombre et arrondir (passer de proportion en 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()
9
MichaelChirico

Voici ma solution pour définir une nouvelle fonction (principalement pour pouvoir jouer avec Curry et Compose :-)):

library(roxygen)
printpct <- Compose(function(x) x*100, Curry(sprintf,fmt="%1.2f%%"))
6
Ari B. Friedman

Vous pouvez utiliser le paquet scale uniquement pour cette opération (sans le charger avec require ou library)

scales::percent(m)
5

Voyant comment on avait déjà montré que scalable::percent était le plus lent et que Liliana Pacheco offrait une autre solution, j'ai décidé de la comparer à certaines des autres options basées sur l'exemple donné par Michael:

library(microbenchmark)
library(scales)
library(formattable)

x<-runif(1e5)

lilip <- function() formattable::percent(x,2)
krlmlr <- function() scales::percent(x)
andrie1 <- function() paste0(round(x,4) * 100, '%')

microbenchmark(times=100L,lilip(), krlmlr(), andrie1())

Ce sont les résultats que j'ai obtenus:

Unit: microseconds
      expr        min          lq        mean      median          uq        max neval
   lilip()    194.562    373.7335    772.5663    889.7045    950.4035   1611.537   100
  krlmlr() 226270.845 237985.6560 260194.9269 251581.0235 280704.2320 373022.180   100
 andrie1()  87916.021  90437.4820  92791.8923  92636.8420  94448.7040 102543.252   100

Je n'ai aucune idée, cependant, pourquoi mes krlmlr() et andrie1() ont été tellement pires que dans l'exemple de MichaelChirico. Des indices?

3
matt_jay
try this~

data_format <- function(data,digit=2,type='%'){
if(type=='d') {
    type = 'f';
    digit = 0;
}
switch(type,
    '%' = {format <- paste("%.", digit, "f%", type, sep='');num <- 100},
    'f' = {format <- paste("%.", digit, type, sep='');num <- 1},
    cat(type, "is not a recognized type\n")
)
sprintf(format, num * data)
}
0
light-voice

Cette fonction pourrait transformer les données en pourcentages par colonnes

percent.colmns = function(base, columnas = 1:ncol(base), filas = 1:nrow(base)){
    base2 = base
    for(j in columnas){
        suma.c = sum(base[,j])
        for(i in filas){
            base2[i,j] = base[i,j]*100/suma.c
        }
    }
    return(base2)
}
0
Edwin Torres