For loop in R subsetting

Viewed 52

I am cracking my head trying to figure out how to run a for loop to subset a matrix.

Essentially, I have a matrix m, and would like to subset the data at regular interval, and finally rbind them together. The laborious manner goes like this:

m1 <- m[7:22,2:25]
m2 <- m[30:45,2:25]
m3 <- m[53:68,2:25]
...
m100 <- .... 

m_all <- rbind(m1,m2,m3 .... m100)

As you can see, the intervals is 23....

I would like to have a for loop command but am failing to remember what I learnt during my R classes. This is what I have thought of so far....

for (i=2 ; i<=100; i++)
  {
  m[i] <- m[(7+{i}*23):(22+{i}*23),2:25]
  }

But my efforts are failing....

Is someone able to teach me how to design a for loop command?

Thanks for your help.

4 Answers

I suggest using the seq() function to generate the sequence. Specifying the by = option allows you to do regular intervals. From there you can compute the lower and upper bounds and use them to subset the matrix rows.

for ( i in seq(from = 7, to = 100, by = 23) ) {
    lower_bound <- i
    upper_bound <- i + 15
    print(paste("lower bound:", lower_bound, "upper bound:", upper_bound))
}

Result

[1] "lower bound: 7 upper bound: 22"
[1] "lower bound: 30 upper bound: 45"
[1] "lower bound: 53 upper bound: 68"
[1] "lower bound: 76 upper bound: 91"
[1] "lower bound: 99 upper bound: 114"

Replace the print in the body with your matrix subset

Try mapply with seq like below

m[c(mapply(seq, seq(7, 99 * 23 + 7, 23), seq(22, 99 * 23 + 22, 23))),2:25]

You could use something like this to create each sub matrix in turn.

What you do with them, or how you store them, you'll need to add yourself or supply further information.

for (i in seq(7, 100, 23))
{
  if (i+15< 100){
    
    sub_matrix <- m[i:(i+15),2:25]

  }
}

The following code will store all the sub matrices in a list, data.

idx<-0

m <- matrix(0L, nrow=100, ncol=30)

data <- list()

idx <- 1

for (i in seq(7, 100, 23))
{
  if (i+15< 100){
        
    sub_matrix <- m[i:(i+15),2:25]
    data[[idx]] <- sub_matrix
    idx<-idx+1
  }
}

If I understand correctly, the OP wants only to keep certain rows of matrix m.

Instead of creating the indices of rows to select, this approach creates negative indices of rows to leave out from the selection.

In OP's sample, the unwanted rows are 1:6, 23:29, 46:52, ....

# create minimal, reproducible example
m <- matrix(rep(1:70, 2L), ncol = 2L)

# leave out unwanted rows 
m_all <- m[-outer(seq(0L, NROW(m), by = 23L), 0:6, `+`), 1:2]
m_all
      [,1] [,2]
 [1,]    7    7
 [2,]    8    8
 [3,]    9    9
 [4,]   10   10
 [5,]   11   11
 [6,]   12   12
 [7,]   13   13
 [8,]   14   14
 [9,]   15   15
[10,]   16   16
[11,]   17   17
[12,]   18   18
[13,]   19   19
[14,]   20   20
[15,]   21   21
[16,]   22   22
[17,]   30   30
[18,]   31   31
[19,]   32   32
[20,]   33   33
[21,]   34   34
[22,]   35   35
[23,]   36   36
[24,]   37   37
[25,]   38   38
[26,]   39   39
[27,]   40   40
[28,]   41   41
[29,]   42   42
[30,]   43   43
[31,]   44   44
[32,]   45   45
[33,]   53   53
[34,]   54   54
[35,]   55   55
[36,]   56   56
[37,]   57   57
[38,]   58   58
[39,]   59   59
[40,]   60   60
[41,]   61   61
[42,]   62   62
[43,]   63   63
[44,]   64   64
[45,]   65   65
[46,]   66   66
[47,]   67   67
[48,]   68   68

The nested sequences of indices are created by

outer(seq(0L, NROW(m), by = 23L), 0:6, `+`)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,]    0    1    2    3    4    5    6
[2,]   23   24   25   26   27   28   29
[3,]   46   47   48   49   50   51   52
[4,]   69   70   71   72   73   74   75
Related