【问题标题】:Convert numbers to SI prefix将数字转换为 SI 前缀
【发布时间】:2012-07-05 15:04:32
【问题描述】:

是否有 R 函数(或任何包)允许使用标准单位前缀(Kilo、Mega 等)格式化数字(整数),所以

10 -> 10
1000 -> 1K
0.01 - > 10m

等等... 我可以自己做,但我不想重新发明轮子。

【问题讨论】:

  • utils:::print.object_size 为一些二进制单元实现了它
  • 在没有校对的情况下,我会小心谨慎。例如,虽然 ISO 允许 3.5 毫米之类的东西,但在标准使用中,每个人都使用 3.5e3 公里。由于从不使用前缀来表示无量纲值,您打算如何附加物理单位本身?
  • 我明白你的意思。但是,我正在做的事情并不“认真”,而且我没有任何单位。我只是在绘图/表格中显示值,我需要每个来适应 3/4 个字符。 10k 比 1000 或 1e+03 更紧凑。
  • ?scales::label_number_si.

标签: r number-formatting


【解决方案1】:
require(sitools)
f2si(80000)
 [1] "80 k"
f2si(8E12)
 [1] "8 T"

如果不使用 SI 前缀,它会附加两个空格,这似乎非常简单:

f2si(80)
[1] "80  "

该函数易于修改以包括舍入。我还解决了附加空格的问题。

f2si2<-function (number,rounding=F) 
{
    lut <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06, 
        0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21, 
        1e+24)
    pre <- c("y", "z", "a", "f", "p", "n", "u", "m", "", "k", 
        "M", "G", "T", "P", "E", "Z", "Y")
    ix <- findInterval(number, lut)
    if (lut[ix]!=1) {
        if (rounding==T) {
         sistring <- paste(round(number/lut[ix]), pre[ix])
        }
        else {
         sistring <- paste(number/lut[ix], pre[ix])
        } 
    }
    else {
        sistring <- as.character(number)
    }
    return(sistring)
}

f2si2(12345)
 [1] "12.345 k"
f2si2(12345,T)
 [1] "12 k"

【讨论】:

  • 似乎正是我想要的,但由于某种原因,我无法安装它:-(
  • 嗯,哪个 R 版本,哪个 CRAN 镜像,...?
  • 更新R。当前版本是2.15.1。
  • 有效,唯一的问题是它不会截断 (12345 -> 12.345 K),所以有点没用
  • 这是在重新发明轮子。我在gdata 包中找到了humanReadable,它可以进行额外的控制。唯一的问题是它添加了一个易于删除的“B”(用于字节)。
【解决方案2】:

我带着同样的问题来到这里。感谢罗兰的回答;我在他的代码的基础上做了一些改动:

  • 当 rounding=FALSE 时允许指定有效数字(默认为 6,就像 'signif' 内置函数一样)
  • 值低于 1e-24 时不会引发错误
  • 为 1e27 以上的值输出科学计数法(无单位)

希望这有帮助。

f2si<-function (number, rounding=F, digits=ifelse(rounding, NA, 6)) 
{
    lut <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06, 
        0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21, 
        1e+24, 1e+27)
    pre <- c("y", "z", "a", "f", "p", "n", "u", "m", "", "k", 
        "M", "G", "T", "P", "E", "Z", "Y", NA)
    ix <- findInterval(number, lut)
    if (ix>0 && ix<length(lut) && lut[ix]!=1) {
        if (rounding==T && !is.numeric(digits)) {
            sistring <- paste(round(number/lut[ix]), pre[ix])
        }
        else if (rounding == T || is.numeric(digits)) {
            sistring <- paste(signif(number/lut[ix], digits), pre[ix])
        }
        else {
            sistring <- paste(number/lut[ix], pre[ix])
        } 
    }
    else {
        sistring <- as.character(number)
    }
    return(sistring)
}

f2si(12345)
 [1] "12.345 k"
f2si(12345, T)
 [1] "12 k"
f2si(10^31)
 [1] "1e+31" # (previous version would output "1e+07 Y"
f2si(10^-25)
 [1] "1e-25" # (previous version would throw error)
f2si(123456789)
 [1] "123.457 M" # (previous version would output ""123.456789 M"
f2si(123456789, digits=4)
 [1] "123.5 M" # (note .456 is rounded up to .5)

通过这段代码,也很容易为常用的金融单位(K、MM、Bn、Tr)编写类似的函数。

【讨论】:

    【解决方案3】:

    略微修改版本以说明负数:

    f2si<-function (number, rounding=F, digits=ifelse(rounding, NA, 6)) 
    {
    mysign <- ""
    if (number<0) {
        mysign <- "-"
    }
    number <- abs(number)
    lut <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06, 
        0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21, 
        1e+24, 1e+27)
    pre <- c("y", "z", "a", "f", "p", "n", "u", "m", "", "k", 
        "M", "G", "T", "P", "E", "Z", "Y", NA)
    ix <- findInterval(number, lut)
    if (ix>0 && ix<length(lut) && lut[ix]!=1) {
        if (rounding==T && !is.numeric(digits)) {
            sistring <- paste(mysign,mysign,round(number/lut[ix]), pre[ix])
        }
        else if (rounding == T || is.numeric(digits)) {
            sistring <- paste(mysign,signif(number/lut[ix], digits), pre[ix],sep="")
        }
        else {
            sistring <- paste(mysign,number/lut[ix], pre[ix],sep="")
        } 
    } else {
        sistring <- paste(mysign,as.character(number),sep="")
    }
    return(sistring)
    

    }

    【讨论】:

      【解决方案4】:

      我正在寻找千(K)、百万(M)和十亿(B)数字转换器。我修改了这个例程以获取一个数字向量/单个数字来吐出所需的输出。

      CurrencyFormat <-function (number,rounding=F) 
      {
          first <- TRUE
          lut <- c( 1, 1000, 1000000, 1000000000,1000000000000 )
          pre <- c("", "K", "M", "B", "T")
          if (length(number) > 1) {
              for (cnt in 1:length(number)){        
                  ix <- findInterval(number[cnt], lut)
                  if (ix != 0 | ix != 1){
                      if (rounding==T) {
                          sistring <- paste(round(number[cnt]/lut[ix]), pre[ix])
                      }
                      else {
                          sistring <- paste(signif(number[cnt]/lut[ix],digits=5), pre[ix])
                      }
                      if (first){
                          tnumber <- sistring
                          fnumber <- tnumber
                          first <- FALSE
                      }
                      else
                          fnumber <- append(fnumber, sistring)
                  }
                  else {
                      sistring <- number[cnt]
                      if (first){
                          tnumber <- sistring
                          fnumber <- tnumber
                          first <- FALSE
                      }
                      else
                          fnumber <- append(fnumber, sistring)
                  }
              }
              return(fnumber)
          }
          else{
              ix <- findInterval(number, lut)
              if (ix != 0 | ix != 1){
                  if (rounding==T) {
                      sistring <- paste(round(number/lut[ix]), pre[ix])
                  }
                  else {
                      sistring <- paste(signif(number/lut[ix],digits=5), pre[ix])
                  }
                  return(sistring)
              }    
              else
                  return(number)
          }
      }
      

      示例:

      CurrencyFormat(1.25,F)
      [1] "1.25 "
      
      CurrencyFormat(1000.25,F)
      [1] "1.0002 K"
      
      CurrencyFormat(c( 1,45,1234, 4.36e+06, 2.84e+04, 2.01e+06),F)
      [1] "1 "      "45 "     "1.234 K" "4.36 M"  "28.4 K"  "2.01 M" 
      

      【讨论】:

        【解决方案5】:

        使用来自 dplyr 的 case_when 进行矢量化很简单,而且看起来更容易:

        library(dplyr)
        
        si_number = function(x, digits) {
        
            compress = function(x, n) {
                signif(x * 10^(-n), digits)
            }
        
            case_when(
                x >= 1e6   ~ paste0(compress(x, 6), "M"),
                x >= 1000  ~ paste0(compress(x, 3), "k"),
                x >= 1     ~ as.character(compress(x, 0)),
                x >= 0.001 ~ paste0(compress(x, -3), "m"),
                x >= 1e-6  ~ paste0(compress(x, -6), "u")
            )
        }
        

        【讨论】:

          猜你喜欢
          • 2019-11-20
          • 1970-01-01
          • 2021-10-30
          • 1970-01-01
          • 1970-01-01
          • 2012-06-13
          • 1970-01-01
          • 2020-04-04
          相关资源
          最近更新 更多