将矩阵的每三行放入一个新矩阵中。

4

我想从一个大矩阵中创建3个子矩阵。

新矩阵应包含:

  • 新矩阵1:旧矩阵的第1个、第4个、第7个...元素
  • 新矩阵2:旧矩阵的第2个、第5个、第8个...元素
  • 新矩阵3:旧矩阵的第3个、第6个、第9个...元素

如果我的矩阵长这样:

    m<-matrix(c(1:3),nrow=12, ncol=2)
      [,1] [,2]
 [1,]    1    1
 [2,]    2    2
 [3,]    3    3
 [4,]    1    1
 [5,]    2    2
 [6,]    3    3
 [7,]    1    1
 [8,]    2    2
 [9,]    3    3
[10,]    1    1
[11,]    2    2
[12,]    3    3

我尝试使用如下的for循环:

for循环代码示例:

for(i in 1:4){
  m1<-m[i+3,]
  m2<-m[i+4,]
  m3<-m[i+5,]
}

但这不仅不能给我第1/2/3行,而且也不能给我所有的行。

必须有一种更优雅的方法来做到这一点。

4个回答

8

利用R中的索引循环规则:

m[c(T, F, F),]
#      [,1] [,2]
# [1,]    1    1
# [2,]    1    1
# [3,]    1    1
# [4,]    1    1

m[c(F, T, F),]
#      [,1] [,2]
# [1,]    2    2
# [2,]    2    2
# [3,]    2    2
# [4,]    2    2

m[c(F, F, T),]
#      [,1] [,2]
# [1,]    3    3
# [2,]    3    3
# [3,]    3    3
# [4,]    3    3

当我们使用长度与矩阵行数不同的向量来索引矩阵时,长度较小的向量将循环直到它们的长度匹配。例如,在第一个情况中,实际索引向量扩展为 c(T, F, F, T, F, F, T, F, F) ,这将按预期选择第一、第四和第七行。对于第二个和第三个情况也是如此。

这个非常好用。谢谢你。你能解释一下为什么它有效吗?理解一下会很好 :) - Kevin Roth
@KevinRoth,你在创建上面的示例矩阵m时,实际上已经使用了循环规则,而你甚至没有意识到它 :) - Richard Border
这只是一个构造的例子,以简化问题。我不想分享我的实际数据 ;) 但它在那里也起作用了,所以我非常高兴,谢谢。 - Kevin Roth

5
我们可以使用seq来实现这一点。对于大型数据集,这将更快。
 m[seq(1, nrow(m), by =3),]

2

或者我们可以这样做:

m[seq(nrow(m))%%3==1,] # 1th, 3th, 7th, ...
m[seq(nrow(m))%%3==2,] # 2th, 5th, 8th, ...
m[seq(nrow(m))%%3==0,] # 3th, 6th, 9th, ...

基准测试

library(microbenchmark)

m <- matrix(c(1:3),nrow=12, ncol=2)

func_Psidom <- function(m){m[c(T, F, F),]}
func_akrun <- function(m){ m[seq(1, nrow(m), by =3),]}
func_42 <- function(m){ m[c(TRUE,FALSE,FALSE), ]}
func_m0h3n <- function(m){m[seq(nrow(m))%%3==1,]}

r <- func_Psidom(m)
all(func_akrun(m)==r)
# [1] TRUE
all(func_42(m)==r)
# [1] TRUE
all(func_m0h3n(m)==r)
# [1] TRUE

microbenchmark(func_Psidom(m), func_akrun(m), func_42(m), func_m0h3n(m))

# Unit: microseconds
           # expr    min     lq     mean  median      uq     max neval
 # func_Psidom(m)  2.566  3.850  4.49990  4.2780  4.7050  14.543   100
  # func_akrun(m) 38.923 39.779 43.58536 40.2065 41.0615 252.359   100
     # func_42(m)  2.994  3.422  4.13628  4.2770  4.7050  13.688   100
  # func_m0h3n(m) 18.820 20.103 22.37447 20.7445 21.3860 104.365   100

# ============================================================

m <- matrix(c(1:3),nrow=1200, ncol=2)
r <- func_Psidom(m)
all(func_akrun(m)==r)
# [1] TRUE
all(func_42(m)==r)
# [1] TRUE
all(func_m0h3n(m)==r)
# [1] TRUE

microbenchmark(func_Psidom(m), func_akrun(m), func_42(m), func_m0h3n(m))

# Unit: microseconds
           # expr    min      lq     mean median     uq      max neval
 # func_Psidom(m) 12.832 13.6875 14.41458 14.542 14.543   22.242   100
  # func_akrun(m) 56.033 57.3150 65.17700 57.743 58.599  289.998   100
     # func_42(m) 12.832 13.4735 14.76962 14.115 14.543   56.032   100
  # func_m0h3n(m) 76.990 78.2730 97.82522 78.702 79.557 1873.437   100

# ============================================================

m <- matrix(c(1:3),nrow=120000, ncol=2)
r <- func_Psidom(m)
all(func_akrun(m)==r)
# [1] TRUE
all(func_42(m)==r)
# [1] TRUE
all(func_m0h3n(m)==r)
# [1] TRUE

microbenchmark(func_Psidom(m), func_akrun(m), func_42(m), func_m0h3n(m))

# Unit: microseconds
           # expr      min        lq     mean   median       uq       max neval
 # func_Psidom(m)  963.665  978.6355 1168.161 1026.113 1076.798  3648.498   100
  # func_akrun(m) 1674.117 1787.6785 2808.231 1890.760 2145.043 58450.377   100
     # func_42(m)  960.672  976.2835 1244.467 1033.812 1115.507  3114.268   100
  # func_m0h3n(m) 5817.920 6127.8070 7697.345 7455.895 8055.565 62414.963   100

1
好的使用微基准测试。我原以为回收会更慢一些。 - akrun

1
逻辑向量在矩阵索引时会被循环使用,直到与行数或列数相等:
 m[c(TRUE,FALSE,FALSE), ]

     [,1] [,2]
[1,]    1    1
[2,]    1    1
[3,]    1    1
[4,]    1    1

m[c(TRUE,FALSE,FALSE)[c(2,1,3)], ]  # the numeric vector permutes the logical values

     [,1] [,2]
[1,]    2    2
[2,]    2    2
[3,]    2    2
[4,]    2    2

m[c(TRUE,FALSE,FALSE)[c(2,3,1)], ]

     [,1] [,2]
[1,]    3    3
[2,]    3    3
[3,]    3    3
[4,]    3    3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接