将矩阵分成N个大小相等的块,带有R余数。

4
如何用R将矩阵或数据框水平分成N个大小相等的块? 我想要将矩阵或数据框水平切割。
例如,给定:
r = 8
c = 10
number_of_chunks = 4
data = matrix(seq(r*c), nrow = r, ncol=c)
>>> data

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    1    9   17   25   33   41   49   57   65    73
[2,]    2   10   18   26   34   42   50   58   66    74
[3,]    3   11   19   27   35   43   51   59   67    75
[4,]    4   12   20   28   36   44   52   60   68    76
[5,]    5   13   21   29   37   45   53   61   69    77
[6,]    6   14   22   30   38   46   54   62   70    78
[7,]    7   15   23   31   39   47   55   63   71    79
[8,]    8   16   24   32   40   48   56   64   72    80

我想要将data划分为4个元素的列表:
第1个元素:
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    1    9   17   25   33   41   49   57   65    73
[2,]    2   10   18   26   34   42   50   58   66    74

元素2:
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[3,]    3   11   19   27   35   43   51   59   67    75
[4,]    4   12   20   28   36   44   52   60   68    76

元素3:
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[5,]    5   13   21   29   37   45   53   61   69    77
[6,]    6   14   22   30   38   46   54   62   70    78

元素4:
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[7,]    7   15   23   31   39   47   55   63   71    79
[8,]    8   16   24   32   40   48   56   64   72    80

使用Python中的NumPy库,我可以使用numpy.array_split函数。
3个回答

5

以下是使用基础R语言的一种方法。使用pretty计算序列行的“漂亮”切割值。使用cut将行号序列分类,并返回在切割值处分割的序列列表,使用split。最后,使用[从拆分行值的列表中提取矩阵子集,使用lapply遍历。

lapply(split(seq_len(nrow(data)),
             cut(seq_len(nrow(data)), pretty(seq_len(nrow(data)), number_of_chunks))),
       function(x) data[x, ])
$`(0,2]`
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    1    9   17   25   33   41   49   57   65    73
[2,]    2   10   18   26   34   42   50   58   66    74

$`(2,4]`
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    3   11   19   27   35   43   51   59   67    75
[2,]    4   12   20   28   36   44   52   60   68    76

$`(4,6]`
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    5   13   21   29   37   45   53   61   69    77
[2,]    6   14   22   30   38   46   54   62   70    78

$`(6,8]`
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    7   15   23   31   39   47   55   63   71    79
[2,]    8   16   24   32   40   48   56   64   72    80

将此内容封装为一个函数:

array_split <- function(data, number_of_chunks) {
  rowIdx <- seq_len(nrow(data))    
  lapply(split(rowIdx, cut(rowIdx, pretty(rowIdx, number_of_chunks))), function(x) data[x, ])
}

然后,您可以使用。
array_split(data=data, number_of_chunks=number_of_chunks)

要返回与上述相同的结果。


@user20650建议的一个不错的简化方法是

split.data.frame(data,
                 cut(seq_len(nrow(data)), pretty(seq_len(nrow(data)), number_of_chunks)))

令我惊讶的是,当split.data.frame方法的第一个参数为矩阵时,它返回一个矩阵列表。

如何使用array_split将一个有3510行的矩阵分成10个相等大小的子矩阵?pretty参数将我的矩阵分成了8个块,而不是10个。 - siegfried

1
number_of_chunks = 4
lapply(seq(1, NROW(data), ceiling(NROW(data)/number_of_chunks)),
       function(i) data[i:min(i + ceiling(NROW(data)/number_of_chunks) - 1, NROW(data)),])

或者

lapply(split(data, rep(1:number_of_chunks, each = NROW(data)/number_of_chunks)),
       function(a) matrix(a, ncol = NCOL(data)))

1
尽量不要显式地分割数据,因为这是另一个副本。您最好拆分要访问的索引。
使用此函数,可以按块数量(用于并行处理)或块大小进行拆分。
CutBySize <- function(m, block.size, nb = ceiling(m / block.size)) {
  int <- m / nb
  upper <- round(1:nb * int)
  lower <- c(1, upper[-nb] + 1)
  size <- c(upper[1], diff(upper))
  cbind(lower, upper, size)
}

CutBySize(nrow(data), nb = number_of_chunks)

     lower upper size
[1,]     1     2    2
[2,]     3     4    2
[3,]     5     6    2
[4,]     7     8    2

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