Tom Kim
Tom Kim

Reputation: 39

Create new column in R dataframe with values in other columns

My R dataframe's headers include Forward, Backward, SideLeft, SideRight, and the new column I am trying to create is the Direction column.

The columns started with just TRUE/FALSE values, and I converted the TRUE values into the header names and made them all characters.

df[df==TRUE] <- colnames(df)[which(df==TRUE, arr.ind=TRUE)[,'col']]

Below is what the dataframe looks like:

> df
    For  Back SLeft SRight Direction
1   For FALSE FALSE  FALSE     FALSE
2 FALSE FALSE SLeft  FALSE     FALSE
3 FALSE  Back FALSE  FALSE     FALSE
4 FALSE FALSE FALSE SRight     FALSE

What I am trying to produce:

> df
    For  Back SLeft SRight Direction
1   For FALSE FALSE  FALSE       For
2 FALSE FALSE SLeft  FALSE     SLeft
3 FALSE  Back FALSE  FALSE      Back
4 FALSE FALSE FALSE SRight    SRight

With this code:

for (i in df){
  for (index in 1:length(i)){
    if (i[index]!="FALSE"){
      df$Direction[i] = i[index]
    }
  }
}

What I am getting:

> df
    For  Back SLeft SRight Direction
1   For FALSE FALSE  FALSE     FALSE
2 FALSE FALSE SLeft  FALSE     FALSE
3 FALSE  Back FALSE  FALSE     FALSE
4 FALSE FALSE FALSE SRight     FALSE

First post, have mercy on my description/edits

Upvotes: 1

Views: 807

Answers (3)

akrun
akrun

Reputation: 887118

We can use row/column indexing to extract the values. The column index is derived from max.col, cbind it with row index, extract the values and assign it to create 'Direction'

df$Direction <- df[1:4][cbind(seq_len(nrow(df)), max.col(df[1:4] != FALSE, 'first'))]
df
#    For  Back SLeft SRight Direction
#1   For FALSE FALSE  FALSE       For
#2 FALSE FALSE SLeft  FALSE     SLeft
#3 FALSE  Back FALSE  FALSE      Back
#4 FALSE FALSE FALSE SRight    SRight

If it was only a logical matrix, then also the max.col to create the column index would work and is faster

df$Direction <- names(df)[1:4][cbind(seq_len(nrow(df)), max.col(df[1:4], 'first'))]

Upvotes: 1

Onyambu
Onyambu

Reputation: 79228

 transform(df,Direction=df[(s<-which((df!=F),T))[order(s[,1]),]])
    For  Back SLeft SRight Direction
1   For FALSE FALSE  FALSE       For
2 FALSE FALSE SLeft  FALSE     SLeft
3 FALSE  Back FALSE  FALSE      Back
4 FALSE FALSE FALSE SRight    SRight

Upvotes: 1

Gregor Thomas
Gregor Thomas

Reputation: 145775

Data frame columns have to have a class, like numeric, character, factor, or logical. You had nice columns of logical class, and you should keep them that way!

"I converted the TRUE values into the header names and made them all characters" - this was a really bad idea. Don't do this step, and the rest will be easy. FALSE and TRUE are useful and have good meaning as logical values. As characters, "FALSE" and "TRUE" are more difficult to work with and will cause confusion when they don't behave like logicals.

If you still had TRUE and FALSE, then your solution would be

df$Direction = names(df)[apply(df, 1, which)]

Upvotes: 1

Related Questions