Как отформатировать число в процентах в R?
Одна из вещей, которые меня озадачивали как новшество 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
, но это не дает контроля точности округления.
Ответы
Ответ 1
Обновление через несколько лет:
В настоящее время в пакете 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"
.)
Ответ 2
Посмотрите 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%"
Ответ 3
Проверьте percent
функцию из пакета formattable
:
library(formattable)
x <- c(0.23, 0.95, 0.3)
percent(x)
[1] 23.00% 95.00% 30.00%
Ответ 4
Я сделал некоторый бенчмаркинг для скорости ответов на эти ответы и был удивлен, увидев 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()
Ответ 5
Здесь мое решение для определения новой функции (в основном, я могу играть с Curry и Compose:-)):
library(roxygen)
printpct <- Compose(function(x) x*100, Curry(sprintf,fmt="%1.2f%%"))
Ответ 6
Увидев, как scalable::percent
уже показалось самым медленным, и Лилиана Пачеко предложила другое решение, я пошел дальше и попытался сравнить его с некоторыми другими вариантами, основанными на примере Michael set:
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. Любые подсказки?
Ответ 7
Вы можете использовать пакет весов только для этой операции (без загрузки его с требованием или библиотекой)
scales::percent(m)
Ответ 8
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)
}
Ответ 9
Эта функция может преобразовывать данные в проценты по столбцам
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)
}