如何在R中将数字格式化为百分比?

And*_*rie 116 formatting r

曾经困扰我作为R的新事物的一件事是如何将数字格式化为打印的百分比.

例如,显示0.1234512.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%"
Run Code Online (Sandbox Code Playgroud)

问题:是否有基本的R函数来执行此操作?或者,是否有广泛使用的包提供方便的包装?


尽管在这里搜索了类似的东西?format,?formatC并且?prettyNum我还没有在基础R中找到一个适当方便的包装器, ??"percent"但没有产生任何有用的东西. library(sos); findFn("format percent")返回1250次点击 - 所以再次没用. ggplot2有一个功能,percent但这不能控制舍入精度.

Ric*_*ton 109

几年后的更新:

现在percent,scales包中有一个函数,如krlmlr的答案中所述.使用它而不是我的手卷解决方案.


尝试类似的东西

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

使用,例如,

x <- c(-1, 0, 0.1, 0.555555, 1, 100)
percent(x)
Run Code Online (Sandbox Code Playgroud)

(如果您愿意,请将格式更改"f""g".)

  • 是的,这有效,并且是我在问题中提供的解决方法的更通用版本。但我真正的问题是这是否存在于基础 R 中。 (2认同)
  • +1用于显示如何编写此类功能。 (2认同)

krl*_*mlr 69

看看scales包裹.ggplot2我认为它曾经是其中的一部分.

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

对于大多数情况,用于检测精度的内置逻辑应该足够好.

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%"
Run Code Online (Sandbox Code Playgroud)

  • 不适用于负数.`百分比(-0.1)`产生'NaN%` (2认同)

Lil*_*eco 30

percentformattable包中查看功能:

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

  • +1,这允许指定要包含多少位数,前两个答案中的"scales :: percent"不包含. (4认同)
  • +1,尽管滚动自己的功能非常容易,但选择位数非常有用. (3认同)

gen*_*ama 30

基础R

我更喜欢使用sprintfBase R 中提供的功能。

sprintf("%0.1f%%", .7293827 * 100)
[1] "72.9%"
Run Code Online (Sandbox Code Playgroud)

我特别喜欢sprintf,因为你还可以插入字符串。

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%"
Run Code Online (Sandbox Code Playgroud)

sprintf对于像数据库配置这样的东西使用特别有用;您只需读取 yaml 文件,然后使用 sprintf 填充模板,而无需一堆讨厌的paste0

更长的激励例子

当您有大量文本和大量值需要聚合时,此模式对于 rmarkdown 报告特别有用。

设置/聚合:

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
Run Code Online (Sandbox Code Playgroud)

sprintf与文本和数字向量一起使用,cat仅输出换行符。

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%
Run Code Online (Sandbox Code Playgroud)

最后,为了我自己自私的参考,因为我们正在讨论格式化,所以这就是我如何使用基本 R 来处理逗号:

30298.78 %>% round %>% prettyNum(big.mark = ",")
[1] "30,299"
Run Code Online (Sandbox Code Playgroud)


Mic*_*ico 9

我对这些答案的速度进行了一些基准测试,并且因为它的低迷percent而在scales包装中如此受到惊吓.我想其优点是它的自动检测器可以进行正确的格式化,但是如果你知道你的数据是什么样的,那么它似乎很明显可以避免.

以下是尝试将(0,1)中的100,000个百分比列表格式化为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()
Run Code Online (Sandbox Code Playgroud)

因此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()
Run Code Online (Sandbox Code Playgroud)


Ari*_*man 6

这是我定义一个新功能的解决方案(主要是因为我可以使用Curry和Compose :-)):

library(roxygen)
printpct <- Compose(function(x) x*100, Curry(sprintf,fmt="%1.2f%%"))
Run Code Online (Sandbox Code Playgroud)


בני*_*ילי 6

您可以仅使用scale包进行此操作(无需使用require或库加载)

scales::percent(m)
Run Code Online (Sandbox Code Playgroud)

  • 如何给出位数的准确度? (4认同)

Gia*_*omo 5

tidyverse版本是这样的:

> library(dplyr)
> library(scales)

> set.seed(1)
> m <- runif(5)
> dt <- as.data.frame(m)

> dt %>% mutate(perc=percent(m,accuracy=0.001))
          m    perc
1 0.2655087 26.551%
2 0.3721239 37.212%
3 0.5728534 57.285%
4 0.9082078 90.821%
5 0.2016819 20.168%
Run Code Online (Sandbox Code Playgroud)

看起来像往常一样整洁。

  • 确实很整洁。但鉴于我们重视整洁,我认为人们可以将库称为“scales”(就像您对“tidyverse”所做的那样)并省略“::”运算符,这会让像我这样的新手感到困惑。 (2认同)