将单位缩写转换为数字
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
我有一个数据集,用于缩写列中的数值。比如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