5

Suppose I have a data frame that looks like this:

dframe = data.frame(x = c(1, 2, 3), y = c(4, 5, 6))
#   x y
# 1 1 4
# 2 2 5
# 3 3 6

And a vector of column names, one per row of the data frame:

colname = c('x', 'y', 'x')

For each row of the data frame, I would like to select the value from the corresponding column in the vector. Something similar to dframe[, colname] but for each row.

Thus, I want to obtain c(1, 5, 3) (i.e. row 1: col "x"; row 2: col "y"; row 3: col "x")

2 Answers 2

5

My favourite old matrix-indexing will take care of this. Just pass a 2-column matrix with the respective row/column index:

rownames(dframe) <- seq_len(nrow(dframe))
dframe[cbind(rownames(dframe),colname)]
#[1] 1 5 3

Or, if you don't want to add rownames:

dframe[cbind(seq_len(nrow(dframe)), match(colname,names(dframe)))]
#[1] 1 5 3
Sign up to request clarification or add additional context in comments.

2 Comments

@Onyambu - I assure you that dframe[cbind(rownames(dframe),colname)] will not work unless I force the rownames into it.
@Onyambu - there is a slight difference between the default row.names and explicitly adding 1:n - see row.names = c(NA,-3L) vs row.names = c(NA, 3L) when dput-ing before and after adding rownames.
1

One can use mapply to pass arguments for rownumber (of dframe) and vector for column name (for each row) to return specific column value.

The solution using mapply can be as:

dframe = data.frame(x = c(1, 2, 3), y = c(4, 5, 6))
colname = c('x', 'y', 'x')

mapply(function(x,y)dframe[x,y],1:nrow(dframe),  colname)

#[1] 1 5 3

Although, the next option may not be very intuitive but if someone wants a solution in dplyr chain then a way using gather can be as:

library(tidyverse)

data.frame(colname = c('x', 'y', 'x'), stringsAsFactors = FALSE) %>%
  rownames_to_column() %>%
  left_join(dframe %>% rownames_to_column() %>%
              gather(colname, value, -rowname), 
            by = c("rowname", "colname" )) %>%
  select(rowname, value)

#   rowname value
# 1       1     1
# 2       2     5
# 3       3     3

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.