跑步"申请"命令在一个非常大的数据帧上

时间:2018-04-04 07:22:05

标签: r dataframe parallel-processing tibble

我在R中有一个尺寸为15,000,000 x 140的tibble。尺寸方面它大约6 gb。

我想检查给定行的第11-40列是否在特定列表中开始。我想得到一个1&的向量0' s然后是15,000,000长。

我可以使用以下方法执行此操作:

subResult <- apply(rawData[,11:40], c(1,2), function(x){substring(x,1,3) %in% c("295", "296", "297", "298", "299")})

result <- apply(subResult, 1, sum)

问题是这太慢了 - 第一行只需要1天就可以了。

有没有办法更快地完成此操作 - 可能直接通过dplyr或data.table?

谢谢!

此处的数据采样仅修剪为第11-40列。

!> head(rawData)
 # A tibble: 6 x 30                                                                                                                                                                               
   X1    X2    X3    X4    X5    X6    X7    X8    X9    X10   X11   X12   X13
   <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
 1 39402 39451 3fv3i 19593 fk20 14p4  59304  329fj2 NA    NA    NA    NA    NA
 2 39422 f203ff vmio2  vo2493  19149 59833 13404 394034 43920  349304   59302 1934 34834
 3 3432f32 fe493  43943 H2344 53049  V602  3124  K148 K13  NA    NA    NA    NA
 # ... with 17 more variables: X14 <chr>, X15 <chr>, X16 <chr>, X17 <chr>,                                                                                                                         
 #   X18 <chr>, X19 <chr>, X20 <chr>, X21 <chr>, X22 <chr>, X23 <chr>,                                                                                                                             
 #   X24 <chr>, X25 <chr>, X26 <chr>, X27 <chr>, X28 <chr>, X29 <chr>, X30 <chr> 

3 个答案:

答案 0 :(得分:3)

我的评论:

  • apply将您的数据转换为矩阵
  • 数据框首先是列表,而不是矩阵
  • substring()是一个矢量化函数(%in%

所以,我会这样做:

sapply(rawData[11:40], function(var) {
  substring(var, 1, 3) %in% c("295", "296", "297", "298", "299")
})

然后使用rowSums()代替apply(subResult, 1, sum)

答案 1 :(得分:2)

根据说明,可以使用tidyverse

完成此操作
library(tidyverse)
rawData %>%
   select(11:40) %>% #select the columns
   #convert to logical columns
   mutate_all(funs(substring(.,1,3) %in% c("295", "296", "297", "298", "299"))) %>% 
   reduce('+') %>% #get the rowwise sum
   mutate(rawData, newcol = .) # assign a new column to the original data

或者通过将'data.frame'转换为'data.table'(data.table)来setDT(rawData),在.SDcols中指定感兴趣的列,循环遍历列,转换通过使用OP的条件Reduce获取每行的sum并将(:=)分配给'newcol'

library(data.table)
setDT(rawData)[, newCol := Reduce('+', lapply(.SD, function(x) 
      substring(x, 1, 3) %chin% c("295", "296", "297", "298", "299"))), 
     .SDcols = 11:40]

答案 2 :(得分:2)

尝试使用Rcpp包。

这是一个简单的C ++程序,它接受两个字符串向量,并检查第一个元素的3个字符是否等于第二个元素。因此它将输出大小长度(第一矢量)x长度(第二矢量)的逻辑矩阵。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
LogicalMatrix IndicatorMatrix(std::vector<std::string> target, std::vector<std::string> tocheck) {

  int nrows = target.size();
  int ncols = tocheck.size();

  LogicalMatrix ind(nrows, ncols);

  for(int r=0; r<nrows; r++) {
    for(int c=0; c<ncols; c++) {

      bool found = target[r].substr(0,3) == tocheck[c];
      ind(r,c) = found;

    }
  }

  return ind;

}

之后,您可以将此程序导入R并使用您的IndicatorMatrix函数,就像它将是R函数对象一样。

library(Rcpp)
sourceCpp("C:/Users/Desktop/indicatorMatrix.cpp")

rep("123456", 15000000) -> x
df <- data.frame(x,x,x,x,x,x,x,x, stringsAsFactors=FALSE)
y <- c("123", "124", "345", "231", "675", "344", "222")


t1 <- Sys.time()
out <- lapply(1:length(df), function(col) {

  res <- IndicatorMatrix(unlist(df[,col]), y)
  res

})
t2 <- Sys.time()
t2-t1

程序在8列数据框中搜索了8个3字符的字符串,在大约100秒内搜索了15百万行。所以这对你来说可能是正确的方向。