I have two data.frames, (df1, df2) and I would like to replace the values in columns P1-P10 the letters with the values of df1$V2
but keeping the first two colu
You can match
the values of df2[3:12]
in df1[[1]]
. These row numbers are used to extract the values from df1[2]
.
df2[3:12] <- df1[match(as.character(unlist(df2[3:12])),
as.character(df1[[1]])), 2]
The result (df2
):
Name bd P1 P2 P3 P4 P5 P6 P7 P8 P9 P10
1 H 5 0.1199355 0.3752010 -0.3926061 -1.1039548 -0.1107821 0.9867373 -0.3360094 -0.7488000 -0.3926061 2.0667704
2 U 4 0.1168599 0.1168599 0.9867373 1.3521418 0.9867373 -0.3360094 -0.7724007 -0.3926061 -0.3360094 -1.2543480
3 R 3 -1.2337890 -0.1107821 -0.7724007 2.0667704 0.3752010 0.4645504 0.9867373 0.1168599 -0.0981773 -0.3926061
4 G 2 -0.3926061 0.3199261 -0.0981773 -0.1107821 2.0667704 -1.1039548 -1.2337890 0.3199261 -1.2337890 -2.1534678
5 C 6 -2.1534678 -1.1039548 -1.1039548 -0.7488000 0.4645504 0.3199261 -2.1534678 -0.3360094 0.9867373 0.8771467
6 I 1 0.6171634 0.6224091 1.8011711 0.7292998 0.8771467 2.0667704 0.3752010 0.4645504 -2.1534678 -0.7724007
If you don't want to replace the values inside df2
, you can create a new data frame df4
with
df4 <- "[<-"(df2, 3:12, value = df1[match(as.character(unlist(df2[3:12])),
as.character(df1[[1]])), 2])
Try some *pply
magic:
lookup<-tapply(df1$V2, df1$V1, unique) #Creates a lookup table
lookup.function<-function(x) as.numeric(lookup[as.character(x)]) #The function
df4<-data.frame(df2[,1:2], apply(df2[,3:12], 2,lookup.function )) #Builds the output
Update:
The *pply
family is much faster than merge
, at least an order of magnitude. Check this out
num<-1000
df1 = data.frame(V1=LETTERS, V2=rnorm(26))
df2<-data.frame(cbind(first=1:num,second=1:num, matrix(sample(LETTERS, num^2, replace=T), nrow=num, ncol=num)))
start<-Sys.time()
lookup<-tapply(df1$V2, df1$V1, unique)
lookup.function<-function(x) as.numeric(lookup[as.character(x)])
df4<-data.frame(cbind(df2[,1:2], data.frame(apply(df2[,3:(num+2)], 2, lookup.function ))))
(difftime(Sys.time(),start))
start<-Sys.time()
df4.merge <- "[<-"(df2, 3:num, value = df1[match(as.character(unlist(df2[3:num])), as.character(df1[[1]])), 2])
(difftime(Sys.time(),start))
sum(df4==df4.merge)==num^2
For 3000 columns and rows the *pply
combination needs 4.3s whereas merge
needs about 22s on my slow Intel. And it scales nicely. For 4000 columns and rows the respective times are 7.4 sec and 118 sec.