【问题标题】:Fastest way to convert a list of character vectors to numeric in R在R中将字符向量列表转换为数字的最快方法
【发布时间】:2015-12-30 09:59:20
【问题描述】:

R 中,将包含一组字符数字(作为字符向量)的列表转换为数字的最快方法是什么?

使用以下虚拟数据:

set.seed(2)
N = 1e7
ncol = 10
myT = formatC(matrix(runif(N), ncol = ncol)) # A matrix converted to characters
# Each row is collapsed into a single suite of characters:
myT = apply(myT, 1, function(x) paste(x, collapse=' ') ) 
head(myT)

制作:

[1] "0.1849 0.855 0.8272 0.5403 0.3891 0.5184 0.7776 0.5533 0.1566 0.01591"  
[2] "0.7024 0.1008 0.9442 0.8582 0.3184 0.9289 0.9957 0.1311 0.2131 0.07355" 
[3] "0.5733 0.5493 0.3915 0.4423 0.8522 0.6042 0.9265 0.006878 0.7052 0.71"   
[... etc ...] 

我可以的

library(stringi) 
# In the actual dataset, the number of spaces between numbers may vary, hence "\\s+"
system.time(newT <- lapply(stri_split_regex(myT, "\\s+", omit_empty=T), as.numeric)) 
newT <- unlist(newT) # Final goal is to have a single vector of numbers

在我的带有 64 位和 16GB 系统的 Intel Core i7 2.10GHz 上(在 ubuntu 下):

   user  system elapsed 
  3.748   0.008   3.757 

对于真实数据集(ncol=150N~1e9),这太长了。 还有更好的选择吗?

【问题讨论】:

  • 对你来说什么是“太长”?你几点钟了,你的系统有多快?
  • 我在我的系统上添加了信息以及我得到的时间。 “太长了”意味着,如果我用真实的数据集来做,那将需要很多小时,这不是一个选择,因为它应该做很多次。因此,(并且完全独立于我得到的时间),我只是在寻找实现这一目标的最快方法,以便看看我是否能做到。
  • 我想知道你是怎么得到myT的。也许您需要更改之前的步骤。
  • 随意发布答案。请注意,fread 接受一个将文件预处理为输入的 shell 命令。

标签: r performance apply lapply


【解决方案1】:

这比我的系统快两倍:

x <- paste(myT, collapse = "\n")
library(data.table)
DT <- fread(x)
newT2 <- c(t(DT))

【讨论】:

  • 感谢@Roland,我得到了相同类型的改进,这是迄今为止最快的解决方案。也简单优雅 - 谢谢!
【解决方案2】:

我建议使用“iotools”包,特别是mstrsplit 函数。这样你就可以做到:

library(iotools)
newT <- as.vector(t(mstrsplit(myT, sep = " ", ncol = 10, type = "numeric")))

获取“iotools”包on GitHub


时间比较:

OPFun <- function(myT) {
  newT <- lapply(stri_split_regex(myT, "\\s+", omit_empty=T), as.numeric)
  unlist(newT)
}

RolandFun <- function(myT) {
  x <- paste(myT, collapse = "\n")
  DT <- fread(x)
  newT2 <- c(t(DT))
  newT2
}

AMFun <- function(myT) {
  as.vector(t(mstrsplit(myT, sep = " ", ncol = 10, type = "numeric")))
}

system.time(OP <- OPFun(myT))
#    user  system elapsed 
#   3.920   0.004   3.917 
system.time(Roland <- RolandFun(myT))
#    user  system elapsed 
#   3.156   0.020   3.175 
system.time(AM <- AMFun(myT))
#    user  system elapsed 
#   0.664   0.016   0.676 

all.equal(OP, Roland)
# [1] TRUE
all.equal(Roland, AM)
# [1] TRUE

【讨论】:

  • @ztl,我认为这无关紧要。多个空间基本上会崩溃。
  • 谢谢@Ananda Mahto,看起来很有希望,我想在我的真实数据上进行测试,但是......愚蠢的问题:如果sep 应该是一个以上,我该怎么办-mstrsplit 中的一个空格?看起来它必须是一个字符值,我无法立即找到解决方案...?!
  • 除非我做错了什么,否则这几个空格对我的实际情况很重要,因为它们会影响ncol 并产生 NA。我发现的解决方法是从 mstrsplit 的参数中省略 sep 并在之后执行 newT &lt;- newT[!is.na(newT)]。这显然比我的解决方案要快,谢谢!
  • @ztl,那么,问题解决了吗?让我知道。谢谢。
  • 是的,我可以按照我的评论中提到的那样实施您的提议,谢谢!这是一个改进——我还不接受你的回答,因为我需要进行进一步的测试来与其他可能性进行比较(也许另一个,更快会弹出?)。但你的优雅高效,谢谢!
【解决方案3】:

mstrsplit(myT, sep = " ", type = "numeric")[, 1] 稍微快一点。请注意,做事的顺序会影响性能。 unlist(lapply(x, as.numeric))as.numeric(unlist(x))

set.seed(2)
N = 1e4
ncol = 10
myT = formatC(matrix(runif(N), ncol = ncol)) # A matrix converted to characters
myT = apply(myT, 1, function(x) paste(x, collapse=' ') ) 
head(myT)

library(microbenchmark)
library(stringi) 
library(data.table)
library(iotools)
microbenchmark(
  original = {
    newT <- lapply(stri_split_regex(myT, "\\s+", omit_empty=T), as.numeric)
    unlist(newT)
  },
  data.table = {
    x <- paste(myT, collapse = "\n")
    DT <- fread(x)
    c(t(DT))
  },
  iotools = {
    as.vector(t(mstrsplit(myT, sep = " ", ncol = 10, type = "numeric")))
  },
  strsplit = {
    as.numeric(unlist(strsplit(myT, " ")))
  },
  original2 = {
     as.numeric(unlist(stri_split_regex(myT, "\\s+", omit_empty = TRUE)))
  },
  iotools2 = {
    mstrsplit(myT, sep = " ", type = "numeric")[, 1]
  }
)
Unit: milliseconds
       expr      min       lq     mean   median       uq       max neval   cld
   original 52.03538 53.56949 56.02025 54.27165 55.40487  94.45513   100   c  
 data.table 93.10810 94.63730 98.04845 95.41537 96.51202 212.66666   100     e
    iotools 18.73776 19.44485 21.00974 19.75573 20.05614  42.47620   100 a    
   strsplit 67.04637 69.24053 70.58916 69.86529 70.95980  84.86132   100    d 
  original2 48.25558 49.47346 51.49833 50.14377 50.96139  84.22928   100  b   
   iotools2 18.53165 19.19126 19.72922 19.52567 19.71340  32.48726   100 a    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 2018-10-14
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多