将单位缩写转换为数字

问题描述 投票:0回答:5

我有一个数据集,它缩写了列中的数值。例如,12M 表示 1200 万,1.2k 表示 1,200。 M 和 k 是唯一的缩写。如何编写代码让 R 将这些值从最低到最高排序?

我虽然使用 gsub 将 M 转换为 000,000 等,但这没有考虑小数(1.5M 将是 1.5000000)。

r units-of-measurement exponent
5个回答
6
投票
  • 因此,您想将 SI 单位缩写(“K”、“M”等)转换为指数,即十的幂。 鉴于所有单位都是单字母,并且指数是均匀间隔的 10**3 次幂,这里是处理“Kilo”...“Yotta”以及任何未来指数的工作代码:
    > 10 ** (3*as.integer(regexpr('T', 'KMGTPEY')))
    [1] 1e+12

然后将十的幂乘以您拥有的十进制值。

  • 此外,您可能希望检测并处理未知字母前缀的“不匹配”情况,否则您会得到无意义的
    -1*3
    > unit_to_power <- function(u) {
        exp_ <- 10**(as.integer(regexpr(u, 'KMGTPEY')) *3)
        return (if(exp_>=0) exp_ else 1)
    }
  • 现在,如果您想将“k”和“K”与 Kilo 不区分大小写地匹配(正如计算机人员经常写的那样,即使从技术上讲这是对 SI 的滥用),那么您需要特殊情况,例如if-else 梯形图/表达式(SI 单位一般区分大小写,“M”表示“Mega”,但“m”严格表示“milli”,即使磁盘驱动器用户另有说明;大写字母通常表示正指数) 。因此,对于一些前缀,@DanielV 的特定情况代码更好。

  • 如果您也想要负 SI 前缀,请使用

    as.integer(regexpr(u, 'zafpnum@KMGTPEY')-8)
    ,其中
    @
    只是一些一次性字符以保持统一间距,它实际上不应该匹配。同样,如果您需要处理非 10**3 的幂单位,例如“deci”、“centi”,则需要特殊大小写,或者 WeNYoBen 使用的基于字典的通用方法。

  • base::regexpr
    不是矢量化的,而且它在大输入上的性能也很差,因此如果您想矢量化并获得更高的性能,请使用
    stringr::str_locate


3
投票

试一试:

Text_Num <- function(x){
    if (grepl("M", x, ignore.case = TRUE)) {
        as.numeric(gsub("M", "", x, ignore.case = TRUE)) * 1e6
    } else if (grepl("k", x, ignore.case = TRUE)) {
        as.numeric(gsub("k", "", x, ignore.case = TRUE)) * 1e3
    } else {
        as.numeric(x)
    }
}

1
投票

在您的情况下,您可以使用

gsubfn

a=c('12M','1.2k')
dict<-list("k" = "e3", "M" = "e6")
as.numeric(gsubfn::gsubfn(paste(names(dict),collapse="|"),dict,a))
[1] 1.2e+07 1.2e+03

0
投票

很高兴认识你。

我写了另一个答案

定义函数

res = function (x) {
  result = as.numeric(x)
  if(is.na(result)){
  text = gsub("k", "*1e3", x, ignore.case = T)
  text = gsub("m", "*1e6", text, ignore.case = T)
  result = eval(parse(text = text))
  } 
  return(result)
}

结果

> res("5M")
[1] 5e+06
> res("4K")
[1] 4000
> res("100")
[1] 100
> res("4k")
[1] 4000
> res("1e3")
[1] 1000

0
投票

所有其他答案对我来说都不能很好地与 NA 配合使用(或产生警告,这也不好)。

这是我的解决方案,它重用了其他解决方案中的一些部分。 (也发布在 R data.table 加速 SI/公制转换

library(stringr)

si2num <- function(x)
{
  conv <- paste0("e", c(seq(-24 ,-3, by=3), -2, -1, seq(3, 24, by=3),3))
  names(conv) <- c("y","z","a","f","p","n","µ","m","c","d","K","M","G","T","P","E","Z","Y","k")
  
  xout <- str_replace_all(x, conv)
  xout <- as.numeric(xout)
  
  return(xout)
}

x <- c(NA,"10", "10.01K",NA,"10.1M", "20K", "21k",NA)

si2num(x)
[1]       NA       10    10010       NA 10100000    20000    21000       NA
© www.soinside.com 2019 - 2024. All rights reserved.