ChrKoenig
ChrKoenig

Reputation: 973

Vectorizing a for-loop that merges two data frames by column

Suppose I have two dataframes df1 and df2.

df1 <- data.frame(matrix(c(0,0,1,0,0,1,1,1,0,1),ncol=10,nrow=1))
colnames(df1) <- LETTERS[seq(1,10)]
df2 <- data.frame(matrix(c(1,1,1,1),ncol=4,nrow=1))
colnames(df2) <- c("C","D","A","I")

Some of the column names in df2 match column names in df1 and df1 always contains every possible column name that can occur in df2. I want to append df1 with a new row which holds the value of df2 for matching columns and a 0 for non-matching columns. My current approach uses a for-loop:

for(i in 1:ncol(df1)){
  if(colnames(df1)[i] %in% colnames(df2)){
    df1[2,i] <- df2[1,which(colnames(df2)==colnames(df1)[i])]
  } else {
    df1[2,i] <- 0
  }
}

Well, it works. But I wonder if there is a cleaner (and faster) solution for this task, perhaps taking advantage of vectorized operations.

Upvotes: 0

Views: 101

Answers (3)

thelatemail
thelatemail

Reputation: 93938

Just using assignment:

df1[2,] <- 0
df1[2,names(df2)] <- df2

#  A B C D E F G H I J
#1 0 0 1 0 0 1 1 1 0 1
#2 1 0 1 1 0 0 0 0 1 0

...and just to prove it works with other values:

df2$C <- 8
df1[2,] <- 0
df1[2,names(df2)] <- df2

#  A B C D E F G H I J
#1 0 0 1 0 0 1 1 1 0 1
#2 1 0 8 1 0 0 0 0 1 0

Upvotes: 1

A5C1D2H2I1M1N2O1R2T1
A5C1D2H2I1M1N2O1R2T1

Reputation: 193687

Possibly more efficient would be rbind_all from "dplyr":

library(dplyr)
rbind_list(df1, df2)
#   A  B C D  E  F  G  H I  J
# 1 0  0 1 0  0  1  1  1 0  1
# 2 1 NA 1 1 NA NA NA NA 1 NA

Assign to "res" and replace NA with "0" in the same way identified by @akrun.

Upvotes: 1

akrun
akrun

Reputation: 887891

res <-merge(df1,df2,all=T)[,colnames(df1)]
res[is.na(res)] <- 0
res
#     A B C D E F G H I J
#   1 0 0 1 0 0 1 1 1 0 1
#   2 1 0 1 1 0 0 0 0 1 0

Upvotes: 2

Related Questions