返回其元素(列)都与引用向量

时间:2015-12-08 14:42:43

标签: r

使用以下代码;

  c <- NULL
  for (a in 1:4){
    b <- seq(from = a, to = a + 5)
    c <- rbind(c,b)
    }
  c <- rbind(c,c); rm(a,b)

此矩阵中的结果,

> c
  [,1] [,2] [,3] [,4] [,5] [,6]
b    1    2    3    4    5    6
b    2    3    4    5    6    7
b    3    4    5    6    7    8
b    4    5    6    7    8    9
b    1    2    3    4    5    6
b    2    3    4    5    6    7
b    3    4    5    6    7    8
b    4    5    6    7    8    9

如何为匹配特定输入的行返回行索引?

例如,搜索字词为

z <- c(3,4,5,6,7,8)

我需要返回以下内容,

[1] 3 7

这将用于与时间步长列相关的相当大的测试数据数据框,以通过累积匹配行的时间步来减少数据。

问题得到了其他人的好评。由于我的数据集大小(9.5M行),我想出了一个有效的方法,需要几个步骤。

1)对包含时间步长的大数据帧'dc'进行排序,以便在第1列中累积。

dc <- dc[order(dc[,2],dc[,3],dc[,4],dc[,5],dc[,6],dc[,7],dc[,8]),]

2)创建一个包含唯一条目的新数据框(第1列除外)。

dcU <- unique(dc[,2:8])

3)写入Rcpp(C ++)函数来循环遍历唯一的数据帧,该数据帧在行相等时迭代原始数据帧累积时间,并在识别出不相等的行时索引到下一个循环步骤。

  require(Rcpp)
  getTsrc <-
    '
  NumericVector getT(NumericMatrix dc, NumericMatrix dcU)
  {
  int k = 0;
  int n = dcU.nrow();
  NumericVector tU(n);
  for (int i = 0; i<n; i++)
    {
    while ((dcU(i,0)==dc(k,1))&&(dcU(i,1)==dc(k,2))&&(dcU(i,2)==dc(k,3))&&
           (dcU(i,3)==dc(k,4))&&(dcU(i,4)==dc(k,5))&&(dcU(i,5)==dc(k,6))&&
           (dcU(i,6)==dc(k,7)))
      {
      tU[i] = tU[i] + dc(k,0);
      k++;
      }
    }
  return(tU);
  }
    '
  cppFunction(getTsrc) 

4)将函数输入转换为矩阵。

  dc1 <- as.matrix(dc)
  dcU1 <- as.matrix(dcU)

5)运行函数并计时(返回匹配唯一数据框的时间向量)

  pt <- proc.time()
  t <- getT(dc1, dcU1)
  print(proc.time() - pt)

   user  system elapsed 
   0.18    0.03    0.20 

6)自我高五,多喝咖啡。

3 个答案:

答案 0 :(得分:7)

@jeremycg的回答肯定会有效,如果你有很多列和几行,它的速度很快。但是,如果您有很多行,则可以通过避免在行维度上使用apply()来提高速度。

这是另一种选择:

l <- unlist(apply(c, 2, list), recursive=F)
logic <- mapply(function(x,y)x==y, l, z)
which(.rowSums(logic, m=nrow(logic), n=ncol(logic)) == ncol(logic))

[1] 3 7

首先将每列转换为列表。然后,它获取每个列列表并在z中搜索相应的元素。在最后一步中,您将找到哪些行包含z中具有相应匹配项的所有列。尽管最后一步是行式操作,但使用.rowSums(请注意前面的.)我们可以指定矩阵的尺寸,并获得加速。

让我们测试两种方法的时间安排。

功能

f1 <- function(){
    which(apply(c, 1, function(x) all(x == z)))
}

f2 <- function(){
    l <- unlist(apply(c, 2, list), recursive=F)
    logic <- mapply(function(x,y)x==y, l, z)
    which(.rowSums(logic, m=nrow(logic), n=ncol(logic)) == ncol(logic))
}

有8行(示例中为暗淡):

> time <- microbenchmark(f1(), f2())
> time
Unit: microseconds
 expr    min      lq     mean  median     uq     max neval cld
 f1() 21.147 21.8375 22.86096 22.6845 23.326  30.443   100  a 
 f2() 42.310 43.1510 45.13735 43.7500 44.438 137.413   100   b

有80行:

Unit: microseconds
 expr     min      lq     mean   median       uq     max neval cld
 f1() 101.046 103.859 108.7896 105.1695 108.3320 166.745   100   a
 f2()  93.631  96.204 104.6711  98.1245 104.7205 236.980   100   a

有800行:

> time <- microbenchmark(f1(), f2())
> time
Unit: microseconds
 expr     min       lq      mean    median        uq       max neval cld
 f1() 920.146 1011.394 1372.3512 1042.1230 1066.7610 31290.593   100   b
 f2() 572.222  579.626  593.9211  584.5815  593.6455  1104.316   100  a 

请注意,我的时序评估每个只有100个重复,虽然这些结果是反复的,但在两个方法相等之前,所需的行数有一点变化。

无论如何,我认为一旦你有100多行,我的方法可能会更快。

另请注意,您无法简单地转置c以使f1()更快。首先,t()占用时间;第二,因为你要与z进行比较,所以你只需要进行逐列(在转置之后)比较,所以它在那一点上没有什么不同。

最后,我确信有更快的方法可以做到这一点。我的回答只是我想到的第一件事,并没有要求安装任何软件包。如果你想使用data.table,这可能会快得多。此外,如果你有很多列,你甚至可以并行化这个过程(尽管,值得的是数据集必须是巨大的。)

如果您的数据无法容忍这些时间安排,您可以考虑使用数据集的维度进行报告。

答案 1 :(得分:4)

您可以使用apply

我们在apply上使用c,跨行(1),并在每行上使用函数function(x) all(x == z)

然后拉出行的整数位置。

which(apply(c, 1, function(x) all(x == z)))
b b 
3 7

编辑:如果您的真实数据存在问题,并且只有9列(不是太多输入),您可以尝试完全向量化的解决方案:

which((c[,1]==z[1] & c[,2]==z[2] & c[,3]==z[3] & c[,4]==z[4]& c[,5]==z[5]& c[,6]==z[6]))

答案 2 :(得分:-4)

在您的代码中,c不是数据框。尝试将其转换为一个:

c <- data.frame(c)