I have 3 data frames of unknown length.
Data frame A
looks like this:
A1 A2 n
1 1 2 1
2 3 2 2
3 2 4 3
In a similar manner, data frame B
looks like this:
B1 B2 n
1 3 4 1
2 4 1 2
3 1 3 3
Note that for every row A1, A2, B1, B3 are all different and comprise the numbers from 1 to 4.
Finally, I have data frame C
:
n C1
1 1 3
2 1 1
3 1 4
4 2 0
5 2 2
6 2 3
7 3 3
8 3 0
9 3 1
Note that the values of C1 are all between 0 and 4.
The n
column connects all the data frames. What I want to do is check if the values of C1
are located in the A
dataframe or the B
, and this for each n
. And replace it diretcly in C1. If if the value is 0 it should remain 0. This is the result I'm expecting:
n C1
1 1 B
2 1 A
3 1 B
4 2 0
5 2 A
6 2 A
7 3 B
8 3 0
9 3 B
How can I accomplish this? Thank you for your inputs.
Here is one idea. We first merge
the first two data frames. Once we merge
, we can now create a new data frame by stack
ing all columns (except n
). By creating this new data frame ( df5
in our case) we can now match
the pasted n
- value
from df5
with the pasted n
- C1
from your third data frame ( df4
in our case). A simple gsub
operation then extracts just the letters from the matched values. As a last step, we set the NAs with 0.
df_all <- merge(df2, df3, by = 'n')
# n A1 A2 B1 B2
#1 1 1 2 3 4
#2 2 3 2 4 1
#3 3 2 4 1 3
df5 <- data.frame(n = 1:nrow(df_all), stack(df_all[-1]), stringsAsFactors = FALSE)
#head(df5)
# n values ind
#1 1 1 A1
#2 2 3 A1
#3 3 2 A1
#4 1 2 A2
#5 2 2 A2
#6 3 4 A2
ind <- gsub('\\d+', '', df5$ind)[match(do.call(paste, df4), do.call(paste, df5[-3]))]
ind[is.na(ind)] <- 0
ind
#[1] "B" "A" "B" "0" "A" "A" "B" "0" "B"
Another, slightly different, approach is to left outer join both A
and B
to C
first, then find the column added by the joins that is equal to C1
:
## Do the left outer joins with merge by n and all.x=TRUE
out <- merge(merge(C,A,by="n",all.x=TRUE),B,by="n",all.x=TRUE)
## Loop over rows and extract the name of the column whose value matches C1
## first define a function to do so
extract.name <- function(i,out) {
j <- which(out$C1[i]==out[i,3:ncol(out)])
if (length(j)==0) return("0") else return(substr(colnames(out)[j[1]+2],1,1))
}
## Then, apply it to all rows
out$C1 <- sapply(1:nrow(out),extract.name,out)
## Keep only the n and C1 columns as output
out <- out[,1:2]
## n C1
##1 1 B
##2 1 A
##3 1 B
##4 2 0
##5 2 A
##6 2 A
##7 3 B
##8 3 0
##9 3 B
Data:
A <- structure(list(A1 = c(1L, 3L, 2L), A2 = c(2L, 2L, 4L), n = 1:3), .Names = c("A1",
"A2", "n"), class = "data.frame", row.names = c("1", "2", "3"
))
## A1 A2 n
##1 1 2 1
##2 3 2 2
##3 2 4 3
B <- structure(list(B1 = c(3L, 4L, 1L), B2 = c(4L, 1L, 3L), n = 1:3), .Names = c("B1",
"B2", "n"), class = "data.frame", row.names = c("1", "2", "3"
))
## B1 B2 n
##1 3 4 1
##2 4 1 2
##3 1 3 3
C <- structure(list(n = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), C1 = c(3L,
1L, 4L, 0L, 2L, 3L, 3L, 0L, 1L)), .Names = c("n", "C1"), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6", "7", "8", "9"))
## n C1
##1 1 3
##2 1 1
##3 1 4
##4 2 0
##5 2 2
##6 2 3
##7 3 3
##8 3 0
##9 3 1
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.