我有一个数据集,它缩写了列中的数值。例如,12M 表示 1200 万,1.2k 表示 1,200。 M 和 k 是唯一的缩写。如何编写代码让 R 将这些值从最低到最高排序?
我虽然使用 gsub 将 M 转换为 000,000 等,但这没有考虑小数(1.5M 将是 1.5000000)。
> 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
。试一试:
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
很高兴认识你。
我写了另一个答案
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
所有其他答案对我来说都不能很好地与 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