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

如何将数字格式化为R中的百分比?,r,formatting,R,Formatting,作为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

作为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%"
set.seed(1)

m这是我定义新函数的解决方案(主要是为了让我可以使用Curry和Compose:-):

库(roxygen)
printpct甚至更晚:

正如@DzimitryM所指出的,
percent()
已经“退役”,取而代之的是
label_percent()
,它是旧的
percent_format()
函数的同义词

label_percent()
返回一个函数,因此要使用它,需要额外的一对括号

library(scales)
x <- c(-1, 0, 0.1, 0.555555, 1, 100)
label_percent()(x)
## [1] "-100%"   "0%"      "10%"     "56%"     "100%"    "10 000%"
label_percent(big.mark = ",", suffix = " percent")(x)
## [1] "-100 percent"   "0 percent"      "10 percent"    
## [4] "56 percent"     "100 percent"    "10,000 percent"

几年后的更新:

如今,正如krlmlr的回答中所记录的那样,包中有一个函数。用它来代替我的手卷解决方案


试试像这样的东西

percent <- function(x, digits = 2, format = "f", ...) {
  paste0(formatC(100 * x, format = format, digits = digits, ...), "%")
}
percent查看包裹。我想它曾经是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%"

我对这些答案的速度做了一些基准测试,并惊讶地看到
scales
软件包中的
百分比,考虑到它的缓慢性。我想它的优点是能够自动检测出正确的格式,但是如果你知道你的数据看起来是什么样子的话,那么很明显是可以避免的

以下是尝试将(0,1)中100000个百分比的列表格式化为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()
试试这个~

数据格式从
格式表
包中查看
百分比
函数:

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

x此函数可以按列将数据转换为百分比

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

您可以仅为此操作使用scales软件包(无需使用require或library加载它)


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%
>库(dplyr)
>图书馆(比例尺)
>种子(1)
>突变率(perc=百分比(m,准确度=0.001))
百万分之一
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%
看起来像往常一样整洁。

Base R 我更喜欢使用base R中提供的
sprintf

sprintf("%0.1f%%", .7293827 * 100)
[1] "72.9%"
我特别喜欢
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%"
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
最后,作为我个人的参考,因为我们讨论的是格式,所以我用base R做逗号:

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

sprintf
似乎是邮件列表中最受欢迎的解决方案,我还没有看到任何更好的解决方案。无论如何,调用任何内置函数都不会简单得多,对吧?在我看来
sprintf
对于那些碰巧也是程序员的R编码器子集来说是完美的。我在生活中编写了很多代码,包括COBOL(颤抖)和FORTRAN(显示我的年龄)。但是我不认为<代码> SaveTf规则是显而易见的(翻译:WTF)。当然,一个专用的包装器比SAVETF更容易调用,例如:<代码> FortAt%(x=0.12345,数字=2)。
@hircus我认为这很常见,它应该有自己的短咖喱函数。这在Swave中尤其是一个问题,其中\Sexpr{sprintf(%1.2f%%',myvar)}比\Sexpr{pct(myvar)}丑陋得多或者不管更短的函数是什么。学习使用适当的工具难道不是我们应该期望用户努力实现的吗?我的意思是,学习使用
sprintf()
几乎比发现包foo包含
format\u percent()更耗时
。如果用户不想将格式设置为百分比,而是类似的格式,会发生什么?他们需要找到另一个包装器。从长远来看,学习基本工具将是有益的。有一个小问题是,
%
是LaTeX中的注释字符,这是“默认值”“R的报告格式。因此,虽然它可能对标记图形有用,但如果要删除格式化的数字,则必须小心。是的,这是有效的,并且是我在问题中提供的解决方法的一个更一般的版本。但我真正的问题是,这是否存在于基数R中。在列表百分比中对我有效,但替换了“x”在统计或绘图命令中使用“百分比(x)”会产生错误消息。@rolando2我的答案和krlmlr的答案都返回字符向量作为输出,而不是数字。它们用于格式化轴标签等。也许您只想乘以100?从2020年开始
缩放
版本1.1.0手册告诉:
百分比()
已停用;请改用
label_percent()relevant@DzimitryM为什么
label_percent()
不适用于数字格式?不适用于负数。
percent(-0.1)
produces
NaN%
@akhmed:这已经报告过了,有一个修复程序可用,但有待审查:。注意,它似乎适用于多个负数:
scales::percent(c(-0.1,-0.2))
谢谢你的链接!我不确定这是一个功能还是一个bug。对于多个数字,它有时有效,有时无效。比如,
sprintf("%0.1f%%", .7293827 * 100)
[1] "72.9%"
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%"
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
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%
30298.78 %>% round %>% prettyNum(big.mark = ",")
[1] "30,299"