Reputation: 471
I have two data frames: (these are shortened versions of them)
A
Link VU U P
1 DVH1 7 1 37
2 DVH2 7 0 38
3 DVH3 10 1 35
B
Link VU U P
1 DVH1 2 0 15
2 DVH2 4 0 14
3 DVH3 0 0 5
I want to substract the values in data frame B from those in A based on their location. So for example: For DVH1, VU would be 7-2 (or 5), and the resulting data frame would look like:
Link VU U P
1 DVH1 5 1 22
2 DVH2 3 0 24
3 DVH3 10 1 30
Upvotes: 18
Views: 21793
Reputation: 1636
If the values of the two data frames are in the same position, and the columns have the same names, then merge()
is not necessary anymore:
## provide the sample data
df1 <- tibble::tibble(
Link = c("DVH1", "DVH2", "DVH3"),
VU = c(7,7,10),
U = c(1,0,1),
P = c(37, 38, 35)
)
df2 <- tibble::tibble(
Link = c("DVH1", "DVH2", "DVH3"),
VU = c(2,4,0),
U = c(0, 0, 0),
P = c(15, 14, 5)
)
df1
#> # A tibble: 3 × 4
#> Link VU U P
#> <chr> <dbl> <dbl> <dbl>
#> 1 DVH1 7 1 37
#> 2 DVH2 7 0 38
#> 3 DVH3 10 1 35
df2
#> # A tibble: 3 × 4
#> Link VU U P
#> <chr> <dbl> <dbl> <dbl>
#> 1 DVH1 2 0 15
#> 2 DVH2 4 0 14
#> 3 DVH3 0 0 5
## subtract df2 from df1
df3 <- df1[, 2:4] - df2[, 2:4]
dplyr::bind_cols(df1[, 1], df3)
#> # A tibble: 3 × 4
#> Link VU U P
#> <chr> <dbl> <dbl> <dbl>
#> 1 DVH1 5 1 22
#> 2 DVH2 3 0 24
#> 3 DVH3 10 1 30
Created on 2024-02-22 with reprex v2.1.0
Upvotes: 0
Reputation: 193517
A faster way than merge
(most likely) is to just make sure the second data.frame
is in the same row and column order as the first and subtract them from each other:
z <- names(A)[-1]
cbind(A[1], A[z] - B[match(A$Link, B$Link), z])
# Link VU U P
# 1 DVH1 5 1 22
# 2 DVH2 3 0 24
# 3 DVH3 10 1 30
Here's some sample data:
A <- structure(list(Link = c("DVH1", "DVH2", "DVH3"), VU = c(7L, 7L,
10L), U = c(1L, 0L, 1L), P = c(37L, 38L, 35L)), .Names = c("Link",
"VU", "U", "P"), class = "data.frame", row.names = c("1", "2", "3"))
B <- structure(list(Link = c("DVH1", "DVH3", "DVH2"), P = c(15L, 5L,
14L), U = c(0L, 0L, 0L), VU = c(2L, 0L, 4L)), .Names = c("Link",
"P", "U", "VU"), class = "data.frame", row.names = c("1", "3", "2"))
Upvotes: 11
Reputation: 12819
Use this:
within(merge(A,B,by="Link"), {
VU <- VU.x - VU.y
U <- U.x - U.y
P <- P.x - P.y
})[,c("Link","VU","U","P")]
EDIT: Bonus: if there are too many paired columns (not just VU, U and P) you can use this:
M <- merge(A,B,by="Link")
S <- M[,grepl("*\\.x$",names(M))] - M[,grepl("*\\.y$",names(M))]
cbind(M[,1,drop=FALSE],S)
# Link VU.x U.x P.x
#1 DVH1 5 1 22
#2 DVH2 3 0 24
#3 DVH3 10 1 30
Upvotes: 14