将单位缩写转换为数字

Converting unit abbreviations to numbers

我有一个数据集,用于缩写列中的数值。比如12M表示1200万,1.2k表示1200。 M 和 k 是唯一的缩写。我如何编写允许 R 将这些值从最低到最高排序的代码?

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

试一试:

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

在您的情况下,您可以使用 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
  • 所以您想将 SI 单位缩写 ('K','M',...) 转换为指数,从而转换为数字 powers-of-ten。 鉴于所有单位都是 single-letter,并且指数是 10**3 的 uniformly-spaced 次方,这里是处理 'Kilo'...'Yotta' 和任何未来指数的工作代码:
    > 10 ** (3*as.integer(regexpr('T', 'KMGTPEY')))
    [1] 1e+12

然后只需将 power-of-ten 乘以您的十进制值即可。

  • 此外,您可能想要检测和处理未知字母前缀的 'no-match' 情况,否则您会得到一个无意义的 -1*3
    > unit_to_power <- function(u) {
        exp_ <- 10**(as.integer(regexpr(u, 'KMGTPEY')) *3)
        return (if(exp_>=0) exp_ else 1)
    }
  • 现在,如果你想 case-insensitive-match 同时 'k' 和 'K' 到 Kilo(正如计算机人员经常写的那样,尽管从技术上讲这是对 SI 的滥用) ,那么您需要 special-case 例如 if-else ladder/expression(SI 单位通常为 case-sensitive,'M' 表示 'Mega' 但 'm' 严格表示 'milli',即使 disk-drive 用户另有说明;upper-case 通常用于正指数)。所以对于一些前缀,@DanielV 的 case-specific 代码更好。

  • 如果您也想要负 SI 前缀,请使用 as.integer(regexpr(u, 'zafpnum@KMGTPEY')-8),其中 @ 只是一些一次性字符以保持均匀间距,它实际上不应该匹配。同样,如果您需要处理 non-power-of-10**3 个单位,例如 'deci'、'centi',将需要 special-casing 或 WeNYoBen 使用的一般 dict-based 方法。

  • base::regexpr 没有矢量化,它在大输入上的性能也很差,所以如果你想矢量化并得到 higher-performance 使用 stringr::str_locate.

很高兴认识你

我写了另一个答案

定义函数

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