【问题标题】:How do I use the while() function to evaluate a matrix one row at a time until I find the last row index of the last column to reach <0如何使用 while() 函数一次计算一行矩阵,直到找到最后一列的最后一行索引达到 <0
【发布时间】:2011-05-05 21:16:27
【问题描述】:

-为清楚起见进行了编辑-

我有兴趣找到多维自相关函数的零点。

我可以使用

从我的数据中生成自相关矩阵
acm <- autocorr(x, 1:10)

但是,完整的矩阵可以是 20 x 5000 的数量级,这在计算上是昂贵的。

因此我想一次只计算 1 或 n 行。

这是我想采取的步骤

  1. 计算矩阵的第一行
  2. while(任何列都有所有正值) 计算矩阵的下一行并将其附加到已计算的行中
  3. 确定最后一列的行索引达到零

如果这是完整的矩阵:

acm <- cbind( c(10, 9, 8, 7, 6, 5, 4, 3, 1, -1),
              c(10, 8, 6, 5, 3, 1, -1, 1, -1, 0 ))

我想要一个返回 10 的函数,因为第一个 col 是最后一个达到负值的。如果我先计算完整的矩阵,则以下内容就足够了:

max(which(apply(acm, 2, min)))

但我想避免计算超出需要的 acm,例如因为通常只需要 1 行或一小部分行进行计算。

【问题讨论】:

  • 您的 acm 格式错误,您的功能解决方案无法正常工作:apply 没有给出合乎逻辑的结果。
  • 抱歉,向量的长度不同,但我已经解决了这个问题。

标签: r while-loop


【解决方案1】:

我不确定您的函数到底在做什么,但要回答“如何找到动态生成的矩阵的最后一行,其中列的值低于零?”:

findlastzero = function(mat){
     apply(mat<0, 2, function(x)tail(which(x),1 ))
   }

set.seed(1)
a <- cbind(rnorm(10), rnorm(10), rnorm(10), rnorm(10)) + 0.5

a

            [,1]       [,2]        [,3]        [,4]
 [1,] -0.1264538  2.0117812  1.41897737  1.85867955
 [2,]  0.6836433  0.8898432  1.28213630  0.39721227
 [3,] -0.3356286 -0.1212406  0.57456498  0.88767161
 [4,]  2.0952808 -1.7146999 -1.48935170  0.44619496
 [5,]  0.8295078  1.6249309  1.11982575 -0.87705956
 [6,] -0.3204684  0.4550664  0.44387126  0.08500544
 [7,]  0.9874291  0.4838097  0.34420449  0.10571005
 [8,]  1.2383247  1.4438362 -0.97075238  0.44068660
 [9,]  1.0757814  1.3212212  0.02184994  1.60002537
[10,]  0.1946116  1.0939013  0.91794156  1.26317575


findlastzero(a)
[1] 6 4 8 5

不确定这是否是您要求的,但是..

【讨论】:

  • 谢谢,关闭,但我试图找到最后一个有负数的行的索引;而不是一次检查整个矩阵,从 n 行的子集开始,如果有一些行没有达到零,则添加另外 n 行并进行测试。问题是计算完整矩阵可能需要几分钟时间,而且前 50 行中通常会有一个
【解决方案2】:

不确定我是否正确理解了您的问题,但您可以使用 tapply 隐藏到矩阵中的每一行以提取您想要的信息。

我首先创建一个与您的 a 大小相同的“分组矩阵”。 这用作对要作为输入馈送到 lambda 函数的每一行进行分组的索引。

matrix(rep(1:10,4),nrow=10,ncol=4)

然后我使用分组矩阵在原始矩阵上运行“tapply”。这对矩阵进行了子集化,以便将每个行向量传递给函数:

function(x) { return( x[which(x<0)] ) }

它只返回每行值小于零的所有值。

> a
            [,1]       [,2]       [,3]       [,4]
 [1,]  0.5341781 -0.9263866 -0.5380141 -1.2453310
 [2,]  0.2931630  1.0490300  0.8127472  0.2473263
 [3,]  1.0936143 -0.3399709  1.8199833  1.0053080
 [4,]  1.0002433  0.2002659  1.7730118  1.7578414
 [5,]  0.8116914  0.9371518  0.8727981  1.4236349
 [6,] -0.1127914  1.1563594  1.0331311  0.7658510
 [7,] -0.5423493  1.8905533 -0.8121652  0.1355076
 [8,] -1.6589310  0.4081290  0.3560005  1.6043205
 [9,]  1.8760435  0.8826245  1.4457357  0.7561550
[10,] -0.8503400  0.2302597  0.5838986  0.1252952
> matrix(rep(1:10,4),nrow=10,ncol=4)
      [,1] [,2] [,3] [,4]
 [1,]    1    1    1    1
 [2,]    2    2    2    2
 [3,]    3    3    3    3
 [4,]    4    4    4    4
 [5,]    5    5    5    5
 [6,]    6    6    6    6
 [7,]    7    7    7    7
 [8,]    8    8    8    8
 [9,]    9    9    9    9
[10,]   10   10   10   10
> tapply(a, matrix(rep(1:10,4),nrow=10,ncol=4), function(x) { return(x[which(x<0)])})
$`1`
[1] -0.9263866 -0.5380141 -1.2453310

$`2`
numeric(0)

$`3`
[1] -0.3399709

$`4`
numeric(0)

$`5`
numeric(0)

$`6`
[1] -0.1127914

$`7`
[1] -0.5423493 -0.8121652

$`8`
[1] -1.658931

$`9`
numeric(0)

$`10`
[1] -0.85034

【讨论】:

    【解决方案3】:

    有一个循环解决方案,使用 break 函数。这是使用索引和向量 tt 来跟踪哪些列已经显示负值的 hack。

    find.point <- function(x){
        tt <- rep(F,ncol(x))         # control vector tt
    
        for (i in 1:nrow(x)){
            tt[which(x[i,]<0)] <- T  # check which columns have negative value
            if(all(tt)) break        # if all have reached negative, get out of loop
        }
        i                          # return index
    }
    

    输出和oneliner一样

    max(apply(acm<0,2,function(x) match(T,x)))
    

    我相信您在问题中试图提及的内容。我真的不明白你的性能问题来自哪里。这取决于您是有 5000 列还是 5000 行。在任何情况下,即使数据集大 10 倍,使用 oneliner 对我来说也能在一秒钟内完成计算:

    时间安排:

    > acm <- matrix(rep(seq.int(5000,-5999),100),ncol=22)
    
    > dim(acm)
    [1] 50000    22
    
    > system.time(max(apply(acm<0,2,function(x) match(T,x))))
       user  system elapsed 
       0.05    0.00    0.05 
    
    > system.time(find.point(acm))
       user  system elapsed 
       0.05    0.00    0.05 
    

    然而,当您有很多列时,使用 oneliner 上的功能可以大大改善时间:

    > acm <- matrix(rep(seq.int(5000,-5999),100),ncol=50000)
    
    > dim(acm)
    [1]    22 50000
    
    > system.time(max(apply(acm<0,2,function(x) match(T,x))))
       user  system elapsed 
       0.85    0.01    0.86 
    
    > system.time(find.point(acm))
       user  system elapsed 
       0.03    0.00    0.04 
    

    哎呀,你迫使我想出一个比 oneliner 更快的 for 循环解决方案。很酷的问题!

    【讨论】:

    • 这是一个不错的解决方案。我没有意识到这样会更快,但是证明了一点是很整洁的。性能问题来自使用 coda 包中的 autocorr.diag() 计算自相关矩阵,这在相当快的服务器上可能需要 50 秒以上,例如acf
    • @David:所以实际上你想逐行计算自相关矩阵......哦,男孩,这将是一个困难的问题。您可能想在 stats.stackexchange.com 上尝试一下。这应该是可能的,但我现在真的想不出一个快速的解决方案。
    • 是的,或者分段。我有一个相关的问题,要求提供更通用的解决方案,我提出的答案包含您的代码,已经在 stats.stackexchange 上:stats.stackexchange.com/q/4258/1381
    猜你喜欢
    • 2019-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    相关资源
    最近更新 更多