Как отформатировать число в процентах в R? - PullRequest
110 голосов
/ 22 августа 2011

Одна из вещей, которая меня озадачивала как новичка в R, заключалась в том, как отформатировать число в процентах для печати. ​​

Например, отобразить 0.12345 как 12.345%. У меня есть несколько обходных путей для этого, но ни один из них не кажется «дружелюбным для новичков». Например:

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%"

Вопрос: Существует ли базовая функция R для этого? В качестве альтернативы, есть ли широко используемая упаковка, которая обеспечивает удобную упаковку?


Несмотря на то, что я искал что-то подобное в ?format, ?formatC и ?prettyNum, мне еще не удалось найти подходящую удобную обертку в базе R. ??"percent" ничего полезного не дал. library(sos); findFn("format percent") возвращает 1250 попаданий - так что опять не полезно. ggplot2 имеет функцию percent, но это не дает контроля над точностью округления.

Ответы [ 9 ]

106 голосов
/ 22 августа 2011

Обновление, спустя несколько лет:

В эти дни в пакете scales есть функция percent, как описано в ответе krlmlr.Используйте это вместо моего раскатанного вручную решения.


Попробуйте что-то вроде

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

С использованием, например,

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

(Если вы предпочитаете,изменить формат с "f" на "g".)

66 голосов
/ 22 июля 2013

Проверьте пакет scales.Я думаю, раньше она была частью ggplot2.

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

Встроенная логика для определения точности должна работать достаточно хорошо для большинства случаев.

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%"
30 голосов
/ 12 июля 2016

Проверьте функцию percent из пакета formattable:

library(formattable)
x <- c(0.23, 0.95, 0.3)
percent(x)
[1] 23.00% 95.00% 30.00%
9 голосов
/ 04 июня 2015

Я провел несколько тестов скорости на этих ответах и ​​был удивлен, увидев percent в пакете scales, который так рекламировали, учитывая его медлительность. Я полагаю, что преимуществом является его автоматический детектор правильного форматирования, но если вы знаете, как выглядят ваши данные, то, очевидно, этого следует избегать.

Вот результаты попытки отформатировать список из 100 000 процентов в (0,1) в процент в 2 цифры:

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()

Таким образом, sprintf становится явным победителем, когда мы хотим добавить знак процента. С другой стороны, если мы хотим только умножить число и округлить (перейти от пропорции к проценту без «%», то round() - самый быстрый:

# 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()
6 голосов
/ 22 августа 2011

Вот мое решение для определения новой функции (в основном, так что я могу поиграть с Curry и Compose :-)):

library(roxygen)
printpct <- Compose(function(x) x*100, Curry(sprintf,fmt="%1.2f%%"))
5 голосов
/ 11 января 2017

Вы можете использовать пакет весов только для этой операции (без загрузки его с помощью require или library)

scales::percent(m)
3 голосов
/ 17 июля 2016

Видя, что scalable::percent уже оказался самым медленным, и Лилиана Пачеко предложила другое решение, я пошел дальше и попытался сравнить его с некоторыми другими вариантами, основываясь на примере набора Майкла:

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())

Вот результаты, которые я получил:

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

Понятия не имею, почему мои krlmlr() и andrie1() работали намного хуже, чем в примере MichaelChirico.Есть какие-нибудь подсказки?

0 голосов
/ 28 сентября 2016

Эта функция может преобразовывать данные в проценты по столбцам

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 голосов
/ 30 октября 2015
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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...