Selecting multiple odd or even columns/rows for dataframe
Asked Answered
J

5

47

Is there a way in R to select many non-consecutive i.e. odd or even rows/columns?

I'm plotting the loadings for my Principal Components Analysis. I have 84 rows of data ordered like this: x_1 y_1 x_2..... x_42 y_42

And at the moment I am creating the dataframes for the x and y loadings figures like this:

data.pc = princomp(as.matrix(data))

x.loadings <- data.frame(x=data.pc$loadings[c(1, 3, 5, 7, 9, 11, 13 ,15, 17, 19, 
21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41), 1])

yloadings <- data.frame(y=data.pc$loadings[c(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 
22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42), 1])

Surely there's an easier way to do this?

Jayme answered 26/6, 2014 at 21:8 Comment(2)
Take a look at ?seqBlanton
Note that you're talking about selecting columns, but your code selects rows from column 1.Aalto
T
42

You can always generate sequences with seq:

even_indexes<-seq(2,42,2)
odd_indexes<-seq(1,41,2)

Then,

  x.loadings <- data.frame(x=data.pc$loadings[odd_indexes,1])
Tanishatanitansy answered 26/6, 2014 at 21:15 Comment(1)
I don't understand why the accepted answer to a question about SELECTING odd/even rows or columns is about GENERATING odd or even numbers.Lee
C
88

When logical vectors are used for indexing, they are recycled so this gets you odd columns or odd rows

 calld[ c(TRUE,FALSE), ]  # rows
 calld[ , c(TRUE,FALSE) ] #columns

Even rows or columns:

 calld[ !c(TRUE,FALSE), ]  # rows
 calld[ , !c(TRUE,FALSE) ] #columns

Every third column:

  calld[ , c(TRUE,FALSE, FALSE) ]   #columns 1,4,7 , ....

A recent commenter claims this no longer works. I'm not finding that in R 4.0.4 running in Ubuntu:

> d <- data.frame(as.list(1:10))  # simple example construction
> d
  X1L X2L X3L X4L X5L X6L X7L X8L X9L X10L
1   1   2   3   4   5   6   7   8   9   10
> d[, c(TRUE,FALSE)]
  X1L X3L X5L X7L X9L
1   1   3   5   7   9
> d[, c(TRUE,FALSE,FALSE)]  # example: # of columns not exact multiple of length of logical vector
  X1L X4L X7L X10L
1   1   4   7   10
Curable answered 26/6, 2014 at 23:24 Comment(5)
Beste answer. If N becomes big in "every Nth column/row" then c(TRUE, rep(FALSE,7) (with 7 being N-1) may be used as readable and concise alternative.Frye
Could you explain the above code? calld[ !c(TRUE,FALSE), ]Superintendent
@Superintendent : Not sure what part is confusing you. The "!" basically inverts the logical vector so that it really means: calld[ c(FALSE,TRUE) , ]Curable
in R 4.0.0 very unfortunately, the syntax ` calld[ , !c(TRUE,FALSE) ]` doesn't work any more. You must specify exactly the correct number of columns or rows to repeat.Colettacolette
@AgileBean: I just tested it again on a simple 10 column dataframe and it seems to work for me. You need to post a counter example if you are still seeing evidence of failure to adhere to R's admittedly unusual feature of extending vectors by implicit repetition(AKA "recycling").Curable
T
42

You can always generate sequences with seq:

even_indexes<-seq(2,42,2)
odd_indexes<-seq(1,41,2)

Then,

  x.loadings <- data.frame(x=data.pc$loadings[odd_indexes,1])
Tanishatanitansy answered 26/6, 2014 at 21:15 Comment(1)
I don't understand why the accepted answer to a question about SELECTING odd/even rows or columns is about GENERATING odd or even numbers.Lee
A
41

I wish to add the tidyverse style approach to this problem, using the %% operator.

library(dplyr)
df <- data.frame(V1 = seq(26), V2 = letters)

df %>% filter(row_number() %% 2 == 0) ## Select even rows
df %>% filter(row_number() %% 2 == 1) ## Select odd rows
df %>% filter(row_number() %% 3 == 1) ## Select every 3rd row starting from first row

You can use the same idea to delete every n-th row, of course. See here.

Autochthonous answered 4/5, 2018 at 0:24 Comment(0)
A
7

Use %% in combination with seq_len to create vector for indexing your data frame to find even and odds columns/rows

Try something like this:

even <- seq_len(ncol(data.pc)) %% 2   # index
x.loadings <- data.frame(x=data.pc$loadings[even, ])
y.loadings <- data.frame(x=data.pc$loadings[!even, ] )
Aalto answered 26/6, 2014 at 21:12 Comment(0)
P
1

Here is data.table approach

  1. Make a simple data.table with columns (10) and rows (100)

df = data.table(sapply(1:10, rnorm, n=100))

  1. Get the even/odd rows:

Even df[df[, .I%%2==0]] or df[seq(2,.N,2)]

Odd df[df[, .I%%2==1]] or df[seq(1,.N,2)]

  1. Get the even/odd columns

Even df[,.SD, .SDcols=seq(2,ncol(df),2)]

Odd df[,.SD, .SDcols=seq(1,ncol(df),2)]

Phraseogram answered 26/8, 2021 at 20:21 Comment(3)
Can you actually use .SD inside the brackets?Tanishatanitansy
hmm, not sure.. Can you show me what you mean?Phraseogram
@MaliRemorker I added the use of .SD for selecting odd/even columns - thanks!Phraseogram

© 2022 - 2024 — McMap. All rights reserved.