inner_join() 其中一个键的值范围(年份)
inner_join() with range of values for one of the keys (year)
我有两个格式如下的数据集:
df1
#> Artist Album Year
#> 1 Beatles Sgt. Pepper's 1967
#> 2 Rolling Stones Sticky Fingers 1971
和
df2
#> Album Year Producer
#> 1 Sgt. Pepper's 1966 George Martin
#> 2 Sticky Fingers 1971 Jimmy Miller
我想按专辑和年份做一个 inner_join
,但有时 'Year' 字段会关闭一年:例如,Sgt. Peppers 在 df1 中被列为 1967 到 1966 年在 df2 中。
所以如果我 运行:
df3 <- inner_join(df1, df2, by = c("Album", "Year"))
我得到:
df3
#> Artist Album Year Producer
#> 1 Rolling Stones Sticky Fingers 1971 Jimmy Miller
然而,我希望两个专辑都加入,只要像 (df1$Year == df2$Year + 1)|(df1$Year == df2$Year - 1)
.
我不能简单地通过 'Album' 加入,因为在我的真实数据集中有一些相同标题的 'Albums' 由 'Year' 区分。
以下数据集的代码:
df1 <- data.frame(stringsAsFactors=FALSE,
Artist = c("Beatles", "Rolling Stones"),
Album = c("Sgt. Pepper's", "Sticky Fingers"),
Year = c(1967, 1971)
)
df1
df2 <- data.frame(stringsAsFactors=FALSE,
Album = c("Sgt. Pepper's", "Sticky Fingers"),
Year = c(1966, 1971),
Producer = c("George Martin", "Jimmy Miller")
)
df2
将Year + 1
添加到df2
然后加入?如果您想覆盖两个方向的范围,您还可以添加 Year - 1
。
library(dplyr)
inner_join(df1, df2 %>% bind_rows(df2 %>% mutate(Year = Year + 1)),
by = c("Album", "Year"))
# Artist Album Year Producer
#1 Beatles Sgt. Pepper's 1967 George Martin
#2 Rolling Stones Sticky Fingers 1971 Jimmy Miller
我们可以在这里尝试使用 sqldf
包,因为您的要求可以很容易地使用 SQL 连接来表达:
library(sqldf)
sql <- "SELECT t1.Artist, t1.Album, t1.Year, t2.Album, t2.Year, t2.Producer
FROM df1 t1
INNER JOIN df2 t2
ON ABS(t1.Year - t2.Year) <= 1"
df3 <- sqldf(sql)
如果您想 select 两个表中的所有字段,请使用:
SELECT t1.*, t2.* FROM ...
但请注意,通常 SELECT *
是不受欢迎的,最好始终列出 select 的列。
也许 rolling join 会解决这个问题。它适用于您的数据样本,但您的实际数据中可能存在棘手的边缘情况。
在下面的代码中,roll="nearest"
将匹配每张专辑的最近年份值("rolling" 部分仅适用于最后一个连接列,在本例中为 Year
)。
library(data.table)
setDT(df1)
setDT(df2)
setkey(df1, Album, Year)
setkey(df2, Album, Year)
joined = df1[df2, roll="nearest"]
joined
Artist Album Year Producer
1: Beatles Sgt. Pepper's 1966 George Martin
2: Rolling Stones Sticky Fingers 1971 Jimmy Miller
如果以后有人在看这个问题,上面的回答都很棒。另一个答案是:
- 加入所有匹配的相册
- 仅过滤掉年份相近的记录:
inner_join(df1, df2, by = c("Album")) %>%
filter(abs(Year.x - Year.y)<2)
> Artist Album Year.x Year.y Producer
> 1 Beatles Sgt. Pepper's 1967 1966 George Martin
> 2 Rolling Stones Sticky Fingers 1971 1971 Jimmy Miller
为了完整起见,这也可以使用 data.table
的 non-equi joins:
来解决
library(data.table)
setDT(df1)[, c(.SD, .(ym1 = Year - 1, yp1 = Year + 1))][
setDT(df2), on = .(Album, ym1 <= Year, yp1 >= Year), nomatch = 0L]
Artist Album Year ym1 yp1 Producer
1: Beatles Sgt. Pepper's 1967 1966 1966 George Martin
2: Rolling Stones Sticky Fingers 1971 1971 1971 Jimmy Miller
或
setDT(df1)[, c("ym1", "yp1") := .(Year - 1, Year + 1)][setDT(df2),
on = .(Album, ym1 <= Year, yp1 >= Year), nomatch = 0L]
Artist Album Year ym1 yp1 Producer
1: Beatles Sgt. Pepper's 1967 1966 1966 George Martin
2: Rolling Stones Sticky Fingers 1971 1971 1971 Jimmy Miller
修改 df1
.
顺便说一句:有一个功能请求 https://github.com/Rdatatable/data.table/issues/1639 允许 on
中的 on-the-fly 列。如果实现,上面的表达式将变为
setDT(df1)[setDT(df2), on = .(Album, Year - 1 <= Year, Year + 1 >= Year), nomatch = 0L]
我有两个格式如下的数据集:
df1
#> Artist Album Year
#> 1 Beatles Sgt. Pepper's 1967
#> 2 Rolling Stones Sticky Fingers 1971
和
df2
#> Album Year Producer
#> 1 Sgt. Pepper's 1966 George Martin
#> 2 Sticky Fingers 1971 Jimmy Miller
我想按专辑和年份做一个 inner_join
,但有时 'Year' 字段会关闭一年:例如,Sgt. Peppers 在 df1 中被列为 1967 到 1966 年在 df2 中。
所以如果我 运行:
df3 <- inner_join(df1, df2, by = c("Album", "Year"))
我得到:
df3
#> Artist Album Year Producer
#> 1 Rolling Stones Sticky Fingers 1971 Jimmy Miller
然而,我希望两个专辑都加入,只要像 (df1$Year == df2$Year + 1)|(df1$Year == df2$Year - 1)
.
我不能简单地通过 'Album' 加入,因为在我的真实数据集中有一些相同标题的 'Albums' 由 'Year' 区分。
以下数据集的代码:
df1 <- data.frame(stringsAsFactors=FALSE,
Artist = c("Beatles", "Rolling Stones"),
Album = c("Sgt. Pepper's", "Sticky Fingers"),
Year = c(1967, 1971)
)
df1
df2 <- data.frame(stringsAsFactors=FALSE,
Album = c("Sgt. Pepper's", "Sticky Fingers"),
Year = c(1966, 1971),
Producer = c("George Martin", "Jimmy Miller")
)
df2
将Year + 1
添加到df2
然后加入?如果您想覆盖两个方向的范围,您还可以添加 Year - 1
。
library(dplyr)
inner_join(df1, df2 %>% bind_rows(df2 %>% mutate(Year = Year + 1)),
by = c("Album", "Year"))
# Artist Album Year Producer
#1 Beatles Sgt. Pepper's 1967 George Martin
#2 Rolling Stones Sticky Fingers 1971 Jimmy Miller
我们可以在这里尝试使用 sqldf
包,因为您的要求可以很容易地使用 SQL 连接来表达:
library(sqldf)
sql <- "SELECT t1.Artist, t1.Album, t1.Year, t2.Album, t2.Year, t2.Producer
FROM df1 t1
INNER JOIN df2 t2
ON ABS(t1.Year - t2.Year) <= 1"
df3 <- sqldf(sql)
如果您想 select 两个表中的所有字段,请使用:
SELECT t1.*, t2.* FROM ...
但请注意,通常 SELECT *
是不受欢迎的,最好始终列出 select 的列。
也许 rolling join 会解决这个问题。它适用于您的数据样本,但您的实际数据中可能存在棘手的边缘情况。
在下面的代码中,roll="nearest"
将匹配每张专辑的最近年份值("rolling" 部分仅适用于最后一个连接列,在本例中为 Year
)。
library(data.table)
setDT(df1)
setDT(df2)
setkey(df1, Album, Year)
setkey(df2, Album, Year)
joined = df1[df2, roll="nearest"]
joined
Artist Album Year Producer 1: Beatles Sgt. Pepper's 1966 George Martin 2: Rolling Stones Sticky Fingers 1971 Jimmy Miller
如果以后有人在看这个问题,上面的回答都很棒。另一个答案是:
- 加入所有匹配的相册
- 仅过滤掉年份相近的记录:
inner_join(df1, df2, by = c("Album")) %>%
filter(abs(Year.x - Year.y)<2)
> Artist Album Year.x Year.y Producer
> 1 Beatles Sgt. Pepper's 1967 1966 George Martin
> 2 Rolling Stones Sticky Fingers 1971 1971 Jimmy Miller
为了完整起见,这也可以使用 data.table
的 non-equi joins:
library(data.table)
setDT(df1)[, c(.SD, .(ym1 = Year - 1, yp1 = Year + 1))][
setDT(df2), on = .(Album, ym1 <= Year, yp1 >= Year), nomatch = 0L]
Artist Album Year ym1 yp1 Producer 1: Beatles Sgt. Pepper's 1967 1966 1966 George Martin 2: Rolling Stones Sticky Fingers 1971 1971 1971 Jimmy Miller
或
setDT(df1)[, c("ym1", "yp1") := .(Year - 1, Year + 1)][setDT(df2),
on = .(Album, ym1 <= Year, yp1 >= Year), nomatch = 0L]
Artist Album Year ym1 yp1 Producer 1: Beatles Sgt. Pepper's 1967 1966 1966 George Martin 2: Rolling Stones Sticky Fingers 1971 1971 1971 Jimmy Miller
修改 df1
.
顺便说一句:有一个功能请求 https://github.com/Rdatatable/data.table/issues/1639 允许 on
中的 on-the-fly 列。如果实现,上面的表达式将变为
setDT(df1)[setDT(df2), on = .(Album, Year - 1 <= Year, Year + 1 >= Year), nomatch = 0L]