Matching a column in a dataframe with the closest values ​​in a column of another dataframe

Hello I have one question about two data.frames match.

I have two datasets:

Dataframe 1:

"A" "B" 
91   1 
92   3
93   11
94   4
95   10 
96   6 
97   7
98   8 
99   9 
100  2

 structure(list(A = 91:100, B = c(1, 3, 11, 4, 10, 6, 7, 8, 9, 
2)), .Names = c("A", "B"), row.names = c(NA, -10L), class = "data.frame")

      

Dataframe 2:

"C"    "D"
91.12   1 
92.34   3
93.65   11
94.23   4
92.14   10 
96.98   6 
97.22   7
98.11   8 
93.15   9 
100.67  2
91.45   1 
96.45   3
83.78   11
84.66   4
100     10 

structure(list(C = c(91.12, 92.34, 93.65, 94.23, 92.14, 96.98, 
97.22, 98.11, 93.15, 100.67, 91.25, 96.45, 83.78, 84.66, 100), 
    D = c(1, 3, 11, 4, 10, 6, 7, 8, 9, 2, 1, 3, 11, 4, 10)), .Names = c("C", 
"D"), row.names = c(NA, -15L), class = "data.frame")

      

Now I want to find the matched matches between columns A and C and replace column D with the corresponding value in column B from Dataframe 1. If there is no matching value (rounded matches between A and C), I want to get NaN for the replaced column D.

result:
"C"    "newD"
91.12   1 
92.34   3
93.65   4
94.23   4
92.14   3 
96.98   7 
97.22   7
98.11   8 
93.15   11 
100.67  NaN
91.25   1 
96.45   6
83.78   NaN
84.66   NaN
100     2 

structure(list(C = c(91.12, 92.34, 93.65, 94.23, 92.14, 96.98, 
97.22, 98.11, 93.15, 100.67, 91.25, 96.45, 83.78, 84.66, 100), 
    D = c(1, 3, 4, 4, 3, 7, 7, 8, 11, NaN, 1, 6, NaN, NaN, 2)), .Names = c("C", 
"D"), row.names = c(NA, -15L), class = "data.frame")

      

Does anyone know how to do this for large datasets?

Thank you so much!

+3


source to share


3 answers


Making an update connection using data.table:

library(data.table)
setDT(DF1); setDT(DF2)

DF2[, A := round(C)] 
DF2[, D := DF1[DF2, on=.(A), x.B] ]

# alternately, chain together in one step:
DF2[, A := round(C)][, D := DF1[DF2, on=.(A), x.B] ]

      

It delivers NA

in unmatched lines. To switch it ... DF2[is.na(D), D := NaN]

.

To drop the new column DF2$A

use DF2[, A := NULL]

.



Does anyone know how to do this for large datasets?

This modifies DF2 in place (instead of creating a new table like a vanilla join like in Mike's answer), so it should be efficient enough for large tables. It might perform better if A is stored as an integer and not a float in both tables.


In datasheet 1.9.6 use on="A", B

instead on=.(A), x.B

. Thanks to Mike H for checking this out.

+3


source


You can create a lookup table where values ​​in are used to find values ​​in B.



Lookup = df1$B
names(Lookup) = df1$A
df3 = data.frame(C = df2$C, newD = Lookup[as.character(round(df2$C))])
df3$newD[is.na(df3$newD)] = NaN

      

+2


source


For these types of merges, I like sql:

library(sqldf)
res <- sqldf("SELECT     l.C, r.B
              FROM       df2 as l
              LEFT JOIN  df1 as r
              on round(l.C) = round(r.A)")
res
#        C  B
#1   91.12  1
#2   92.34  3
#3   93.65  4
#4   94.23  4
#5   92.14  3
#6   96.98  7
#7   97.22  7
#8   98.11  8
#9   93.15 11
#10 100.67 NA
#11  91.45  1
#12  96.45  6
#13  83.78 NA
#14  84.66 NA
#15 100.00  2

      

+2


source







All Articles