WHB533
WHB533

Reputation: 3

How to automatically extract values from matrices

I am a newbie in R, I now have a matrix of 3 columns and 8, 000 rows, with groups of 500 rows, which means 16 sets of 500*3 matrices stacked on top of each other in rows. Now I want to take the first 300 rows of each group of matrices, put 16 groups of 300 by 3 into a new matrix, what do I do?

Upvotes: 0

Views: 66

Answers (4)

SteveM
SteveM

Reputation: 2301

A simple way to generate an array that mimics the fill of your matrix is to use the transpose of the matrix as the input for the array function. Here is a simple example:

n <- rep(1:3, each = 4)
m1 <- matrix(n, ncol = 2, byrow = TRUE)
> m1
     [,1] [,2]
[1,]    1    1
[2,]    1    1
[3,]    2    2
[4,]    2    2
[5,]    3    3
[6,]    3    3
m2 <- t(m1)
a1 <- array(m2, c(2, 2, 3))
> a1
, , 1

     [,1] [,2]
[1,]    1    1
[2,]    1    1

, , 2

     [,1] [,2]
[1,]    2    2
[2,]    2    2

, , 3

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

Upvotes: 0

Edo
Edo

Reputation: 7818

If you're looking for just a way to select the first 300 rows from your matrix for each group, this could be a solution.

Given m your matrix of 8000x3 composed by 16 groups on top of each other, then:

r <- 500 # rows for each group
g <- 16  # number of groups
n <- 300 # first n rows to select

new_m <- m[rep(rep(c(T,F), c(n,r-n)), g), ]
dim(new_m)
#> [1] 4800    3

new_m is now a matrix 4800x3


In case you are working with keras or reticulate, you could use array_reshape.

#### 0. parameters
nrows <- 4 # 500 in your example # rows for each group
ncols <- 3 #   3 in your example
ngrps <- 2 #  16 in your example # number of groups
nslct <- 3 # 300 in your example # first n rows to select


#### 1. create an example matrix
m <- matrix(1:24, nrows*ngrps, ncols)
m 
#>      [,1] [,2] [,3]
#> [1,]    1    9   17
#> [2,]    2   10   18
#> [3,]    3   11   19
#> [4,]    4   12   20
#> [5,]    5   13   21
#> [6,]    6   14   22
#> [7,]    7   15   23
#> [8,]    8   16   24
dim(m) 
#> [1] 8 3
#--> c(ngrps * nrows, ncols)


#### 2. reshape in groups
m <- reticulate::array_reshape(m, c(ngrps,nrows,ncols))
dim(m)
#> [1] 2 4 3
# --> c(n_groups, n_rows, n_cols)

m[1,,]
#>      [,1] [,2] [,3]
#> [1,]    1    9   17
#> [2,]    2   10   18
#> [3,]    3   11   19
#> [4,]    4   12   20
m[2,,]
#>      [,1] [,2] [,3]
#> [1,]    5   13   21
#> [2,]    6   14   22
#> [3,]    7   15   23
#> [4,]    8   16   24


#### 3. select first nslct rows for each group
new_m <- m[,seq_len(nslct),]

# that's the result for each group
new_m[1,,]
#>      [,1] [,2] [,3]
#> [1,]    1    9   17
#> [2,]    2   10   18
#> [3,]    3   11   19
new_m[2,,]
#>      [,1] [,2] [,3]
#> [1,]    5   13   21
#> [2,]    6   14   22
#> [3,]    7   15   23


#### 4. recreate one matrix
reticulate::array_reshape(new_m, c(nslct*ngrps,ncols))
#>      [,1] [,2] [,3]
#> [1,]    1    9   17
#> [2,]    2   10   18
#> [3,]    3   11   19
#> [4,]    5   13   21
#> [5,]    6   14   22
#> [6,]    7   15   23

Created on 2020-11-23 by the reprex package (v0.3.0)

Upvotes: 0

Roland
Roland

Reputation: 132706

Two 6 * 2 matrices on top of each other:

m <- matrix(1:24, ncol = 2)
#      [,1] [,2]
# [1,]    1   13
# [2,]    2   14
# [3,]    3   15
# [4,]    4   16
# [5,]    5   17
# [6,]    6   18
# [7,]    7   19
# [8,]    8   20
# [9,]    9   21
#[10,]   10   22
#[11,]   11   23
#[12,]   12   24

Make it an array:

a <- array(m, c(6, 2, 2))
a <- aperm(a, c(1, 3, 2))

First three rows of each matrix:

a[1:3,,]
#, , 1
#
#     [,1] [,2]
#[1,]    1   13
#[2,]    2   14
#[3,]    3   15
#
#, , 2
#
#     [,1] [,2]
#[1,]    7   19
#[2,]    8   20
#[3,]    9   21

Use this if you need a matrix:

matrix(aperm(a[1:3,,], c(1, 3, 2)), ncol = 2)
#     [,1] [,2]
#[1,]    1   13
#[2,]    2   14
#[3,]    3   15
#[4,]    7   19
#[5,]    8   20
#[6,]    9   21

Upvotes: 1

Allan Cameron
Allan Cameron

Reputation: 173803

You need to generate the sequence 1:300, 501:800, ... etc, then subset out these rows. If your matrix is called mat you can do that like this:

new_mat <- mat[as.numeric(sapply((0:15 * 500), "+", 1:300)),]

Upvotes: 0

Related Questions