优雅地将1M转换为1000000

时间:2016-02-02 06:19:00

标签: r data.table

我想转换:

library(data.table)
market.cap <- data.table(cap=c("1B", "10M", "2M"))

  cap
1  1B
2 10M
3  2M

为:

      cap
1 1000000000
2   10000000
3    2000000

这是我的解决方案。它有效,但涉及添加一个列,我知道这不是必需的。什么是更好的方式?

market.cap[, cap1 := cap]
market.cap$cap = sapply(market.cap$cap, function(x) (as.numeric(temp <- gsub("B", "", x)) * 1000000000))
market.cap$cap1 = sapply(market.cap$cap1, function(x) (as.numeric(temp <- gsub("M", "", x)) * 1000000))
M = data.frame(x = na.omit(market.cap$cap))
B = data.frame(x = na.omit(market.cap$cap1))
rbind(M,B)

3 个答案:

答案 0 :(得分:6)

我们可以使用gsubfn,匹配非数字元素(\\D),将其替换为与value匹配的list key },并使用eval(parse将其转换为数值。

library(gsubfn) 
options(scipen=999)
unname(sapply(gsubfn('\\D', list(B= '*1e9', M= '*1e6'), 
       market.cap$cap), function(x) eval(parse(text=x))))
#[1] 1000000000   10000000    2000000

我们也可以在提取match和非数字部分后使用numeric,然后使用带有字母矢量match的{​​{1}}来获取数字索引并用新值替换它。

c('B', 'M')

答案 1 :(得分:4)

这也是一个选择:

# Your toy data
library("data.table")
market.cap <- data.table(c("1B", "10M", "2M"))
colnames(market.cap) <- "cap"

# Helpful functions
ssub <- function(x) gsub("B", "*1e9", gsub("M", "*1e6", x))
evalp <- function(x) eval(parse(text = x))

# Substitute and evaluate
sapply(ssub(market.cap$cap), evalp)
#1*1e9 10*1e6  2*1e6 
#1e+09  1e+07  2e+06 

答案 2 :(得分:3)

这是我自己的尝试:

market.cap[ , cap1 := {
  sf <- gsub("[0-9]", "", cap)
  as.numeric(gsub("[^0-9]", "", cap)) * 1000 ^ (2 + (sf == "B"))}]

以下方法可能会更快,因为它不需要浪费时间通过正则表达式运行cap两次:

market.cap[ , cap1 := {
  x<- do.call("rbind", strsplit(cap, split = "(?=[BM])", perl = TRUE))
  as.numeric(x[ , 1L]) * 1000 ^ (2 + (x[ , 2L] == "B"))}]

tstrsplit {/ 1>} data.table进行优化以来,以下内容可能最快

market.cap[ , cap1 := {
  x <- tstrsplit(cap, split = "(?=[BM])", perl = TRUE)
  as.numeric(x[[1L]]) * 1000 ^ (2 + (x[[2]] == "B"))}]