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

时间:2011-08-22 10:05:24

标签: r formatting

过去常常让我感到困惑的一件事就是如何将数字格式化为打印的百分比。

例如,将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,但这无法控制舍入精度。

11 个答案:

答案 0 :(得分:103)

几年后的更新:

现在percent包中有一个scales函数,如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"。)

答案 1 :(得分:65)

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

答案 2 :(得分:30)

查看percent包中的formattable功能:

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

答案 3 :(得分:9)

我对这些答案的速度做了一些基准测试,并且惊讶地看到CREATE TABLE matches (`date` DATE, `winner` VARCHAR(12), `loser` VARCHAR(12), `row` INT); INSERT INTO matches (`date`,`winner`,`loser`,`row`) VALUES (STR_TO_DATE('3-03-2013', '%m-%d-%Y') ,'USA' ,'CHINA' ,1) ,(STR_TO_DATE('3-05-2013', '%m-%d-%Y') ,'USA' ,'RUSSIA' ,2) ,(STR_TO_DATE('3-06-2013', '%m-%d-%Y') ,'FRANCE' ,'GERMANY' ,3) ,(STR_TO_DATE('3-08-2013', '%m-%d-%Y') ,'USA' ,'RUSSIA' ,4) ,(STR_TO_DATE('3-10-2013', '%m-%d-%Y') ,'FRANCE' ,'RUSSIA' ,5) ,(STR_TO_DATE('3-12-2013', '%m-%d-%Y') ,'SRI LANKA','MALAYSIA' ,6) ,(STR_TO_DATE('3-14-2013', '%m-%d-%Y') ,'USA' ,'AUSTRALIA' ,7) ,(STR_TO_DATE('3-16-2013', '%m-%d-%Y') ,'FRANCE' ,'RUSSIA' ,8) ,(STR_TO_DATE('3-18-2013', '%m-%d-%Y') ,'USA' ,'NEW ZEALAND',9); 包中的percent如此吹捧,因为它的迟缓。我认为它的优点是它的自动检测器可以进行正确的格式化,但是如果你知道你的数据是什么样的,那么似乎很明显可以避免。

以下是尝试格式化100,000个百分比列表的结果。 (0,1)到2位数的百分比:

scales

因此,当我们想要添加百分号时,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() 会成为明显的赢家。另一方面,如果我们只想将数字与数字相乘(从比例变为百分比而没有&#34;%&#34;,则sprintf最快:

round()

答案 4 :(得分:5)

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

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

答案 5 :(得分:5)

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

    listViewHome.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(final AdapterView<?> parent, View view, final int position, long id) {
            Log.i("@@@@@@", "setOnItemClickListener: " + position);

            view.animate().alpha(0f).setDuration(1000).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    Log.i("@@@@@@", "onAnimationEnd: " + position);
                    contacts.remove(position);
                    adapter.notifyDataSetChanged();
                    super.onAnimationEnd(animation);
                }
            });
        }
    });

答案 6 :(得分:3)

看到scalable::percent已经被证明是最慢的,而Liliana Pacheco提供了另一种解决方案,我继续尝试将其与基于迈克尔设置示例的其他一些选项进行对比:

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 :(得分:1)

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%

像往常一样保持整洁。

答案 8 :(得分:0)

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 :(得分:0)

此功能可以将数据转换为按列的百分比

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

答案 10 :(得分:0)

基本R

我更喜欢使用基数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

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%

最后,作为我自己的自私参考,由于我们正在谈论格式化,所以这是我对基数R进行逗号处理的方法:

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