通过部分匹配(R)连接不同数量的列

时间:2016-08-09 16:24:55

标签: r data.table concatenation multiple-columns

关于SO的第一个问题,虽然我已经潜伏了一段时间!我试着尽职尽责,接近答案。

我有一个300列的数据框,我希望根据匹配变量名称的模式合并到大约10列。原始数据输出为我提供了一个列,其中包含主变量名称(在示例中,“之前”和“之后”)和一个数字。在我的“真实”数据中,每个变量大约有30个副本。

我希望将名称中包含“之前”的每一列或“之后”等组合在一起。 我使用data.table的语法为这种类型的“计算”列成功创建了变量“new”。

myTable2[, new := paste(before1, before2, sep = "")]

> myTable2
 herenow     before1 before2 before3  after1 after2 after3         new
1: 0.3399679      if     and   where     not   here  blank       ifand
2: 0.8181909     for      in      by through  blank  blank       forin
3: 0.2237681     and   where            mine  yours   ours    andwhere
4: 0.6161998     and   where              ha    hey    hon    andwhere
5: 0.7606252   fifth  eighth     and   where    not   beet fiftheighth
6: 0.5525105     and   where     not    fill           are    andwhere

但是正如你所看到的,那就是明确地说我想要合并的列。我想灵活地结合起来,这样如果我有一个变量的31个副本和另一个变量的86个,我不会a)必须知道或b)必须输入它。我只想基于基本变量名称(例如“之前”)匹配并组合列。

我尝试使用grep ...进入下一个级别

> newvar2 <- paste(grep("before", colnames(myTable2), value = TRUE), collapse = "")
> newvar2
[1] "before1before2before3"

并且向我确认我可以将可变数量的值与grep模式匹配组合在一起。

下一步:如何将这两个步骤结合起来

new := paste(etc....)

将grep步骤作为参数,并将名称与模式匹配的所有组合在一起? 这就是我想要的:

 herenow        before_Final    after_Final
1: 0.339967856  ifandwhere      nothereblank
2: 0.818190875  forinby         throughblankblank
3: 0.223768051  andwhere        mineyoursours
4: 0.616199835  andwhere        haheyhon
5: 0.760625218  fiftheighthand  wherenotbeet
6: 0.552510532  andwherenot     fillare

我正在研究有关矢量化的更多信息,但是如果我甚至可以列出我想要组合的变量类型(例如之前,之后,之间),然后通过那些,可能在循环中运行,那将是大!像

这样的东西
finalVarNames <- c("Before_final", "After_final", "Between_final")
whatToMatch <- c("before", "after", "between")

(For loop here ...)

myTable2[, finalVarNames[i] := paste(grep(whatToMatch[i], myTable2, value = TRUE), collapse = "")]

我知道语法不正确,可能在value参数之前的第二个“myTable2”引用中。此代码确实成功创建了新变量,但它是空白的。如何将连接的grep匹配变量组合并到其中?

感谢您提供任何帮助!

1 个答案:

答案 0 :(得分:1)

您可以使用Reduce功能将所选列粘贴在一起,方法是在grep语法中按.SD指定列。以下是使用data.table包获取结果的示例:

library(stringi); library(data.table)
myTable2[, paste(stri_trans_totitle(whatToMatch), "final", sep = "_") := 
           lapply(whatToMatch, function(wtm) Reduce(function(x,y) paste(x, y, sep = ""), 
                                             .SD[, grep(wtm, names(myTable2)), with = F]))]

myTable2
#      herenow before1 before2 before3  after1 after2 after3   Before_final       After_final
# 1: 0.3399679      if     and   where     not   here  blank     ifandwhere      nothereblank
# 2: 0.8181909     for      in      by through  blank  blank        forinby throughblankblank
# 3: 0.2237681     and   where            mine  yours   ours       andwhere     mineyoursours
# 4: 0.6161998     and   where              ha    hey    hon       andwhere          haheyhon
# 5: 0.7606252   fifth  eighth     and   where    not   beet fiftheighthand      wherenotbeet
# 6: 0.5525105     and   where     not    fill           are    andwherenot           filler

do.callReduce的一些基准:

dim(myTable2)
# [1] 1572864       9

reduce <- function() myTable2[, paste(stri_trans_totitle(whatToMatch[1:2]), "final", sep = "_") := lapply(whatToMatch[1:2], function(wtm) Reduce(function(x,y) paste(x, y, sep = ""), .SD[, grep(wtm, names(myTable2)), with = F]))]    
docall <- function() myTable2[, paste(stri_trans_totitle(whatToMatch[1:2]), "final", sep = "_") := lapply(whatToMatch[1:2], function(wtm) do.call(paste, c(sep = "", .SD[, grep(wtm, names(myTable2)), with = F])))]

microbenchmark::microbenchmark(docall(), reduce(), times = 10)
# Unit: milliseconds
#     expr      min        lq      mean    median        uq       max neval
# docall() 707.7818  722.6037  767.8923  737.6272  852.4909  868.8202    10
# reduce() 999.4925 1009.5146 1026.6200 1020.4637 1046.7073 1067.7479    10