如何 return R 中两个数据帧之间共享的值范围?
How to return the range of values shared between two data frames in R?
我有几个具有相同列名的数据框,ID
,以下是范围的开始 from
和结束 to
以及每个范围的 group
标签。
我想要的是找出data frames
其中一个的from
和to
的哪些值包含在另一个的范围内。我留下一个示例图片来说明我想要实现的目标(暂时不需要图表)
我以为我可以使用 dplyr package
的 between()
来完成此操作,但不行。这可以通过使用 if between()
returns true then return the maximum value of from
and the minimum value of to
between the data frames.
我留下示例数据框和results
我愿意获得。
a <- data.frame(ID = c(1,1,1,2,2,2,3,3,3),from=c(1,500,1000,1,500,1000,1,500,1000),
to=c(400,900,1400,400,900,1400,400,900,1400),group=rep("a",9))
b <- data.frame(ID = c(1,1,1,2,2,2,3,3,3),from=c(300,1200,1900,1400,2800,3700,1300,2500,3500),
to=c(500,1500,2000,2500,3000,3900,1400,2800,3900),group=rep("b",9))
results <- data.frame(ID = c(1,1,1,2,3),from=c(300,500,1200,1400,1300),
to=c(400,500,1400,1400,1400),group=rep("a, b",5))
我尝试使用这个函数,它会 return 匹配时的值,但它不会 return 它们之间共享的范围
f <- function(vec, id) {
if(length(.x <- which(vec >= a$from & vec <= a$to & id == a$ID))) .x else NA
}
b$fromA <- a$from[mapply(f, b$from, b$ID)]
b$toA <- a$to[mapply(f, b$to, b$ID)]
我们可以假设起点和终点在不同的列中,并且同一组(a 和 b)的范围不重叠。这是我的解决方案。为了清楚起见,我已将 'point_1' 和 'point_2' 称为您的变异 'from' 和 'to'。
可以绑定两个dataframes,将from
col与之前的值lag(from)
进行比较,看实际值是否更小。您还将之前的 lag(to)
与实际的 to
col 进行比较,以查看范围的最大值是否与之前的范围重叠。
重要的是,这些操作不会区分它们比较的两行是否来自同一组(a 或 b)。因此,过滤 point_1
(新的突变 'from' 列)中的 NA,您将删除错误的突变值。
另请注意,我假设 'a' 中的范围不能与 'b' 中的两行重叠。在你的 'results' table 中没有发生,但你应该在你的数据框中检查。
res = rbind(a,b) %>% # Bind by rows
arrange(ID,from) %>% # arrange by ID and starting point (from)
group_by(ID) %>% # perform the following operations grouped by IDs
# Here is the trick. If the ranges for the same ID and group (i.e. 1,a) do
# not overlap, when you mutate the following cols the result will be NA for
# point_1.
mutate(point_1 = ifelse(from <= lag(to), from, NA),
point_2 = ifelse(lag(to)>=to, to, lag(to)),
groups = paste(lag(group), group, sep = ',')) %>%
filter(! is.na(point_1)) %>% # remove NAs in from
select(ID,point_1, point_2, groups) # get the result dataframe
如果您尝试一下代码,而不是使用 filter()
和 select()
,您就会明白它是如何工作的。
> res
# A tibble: 5 x 4
# Groups: ID [3]
ID point_1 point_2 groups
<dbl> <dbl> <dbl> <chr>
1 1 300 400 a,b
2 1 500 500 b,a
3 1 1200 1400 a,b
4 2 1400 1400 a,b
5 3 1300 1400 a,b
我有几个具有相同列名的数据框,ID
,以下是范围的开始 from
和结束 to
以及每个范围的 group
标签。
我想要的是找出data frames
其中一个的from
和to
的哪些值包含在另一个的范围内。我留下一个示例图片来说明我想要实现的目标(暂时不需要图表)
我以为我可以使用 dplyr package
的 between()
来完成此操作,但不行。这可以通过使用 if between()
returns true then return the maximum value of from
and the minimum value of to
between the data frames.
我留下示例数据框和results
我愿意获得。
a <- data.frame(ID = c(1,1,1,2,2,2,3,3,3),from=c(1,500,1000,1,500,1000,1,500,1000),
to=c(400,900,1400,400,900,1400,400,900,1400),group=rep("a",9))
b <- data.frame(ID = c(1,1,1,2,2,2,3,3,3),from=c(300,1200,1900,1400,2800,3700,1300,2500,3500),
to=c(500,1500,2000,2500,3000,3900,1400,2800,3900),group=rep("b",9))
results <- data.frame(ID = c(1,1,1,2,3),from=c(300,500,1200,1400,1300),
to=c(400,500,1400,1400,1400),group=rep("a, b",5))
我尝试使用这个函数,它会 return 匹配时的值,但它不会 return 它们之间共享的范围
f <- function(vec, id) {
if(length(.x <- which(vec >= a$from & vec <= a$to & id == a$ID))) .x else NA
}
b$fromA <- a$from[mapply(f, b$from, b$ID)]
b$toA <- a$to[mapply(f, b$to, b$ID)]
我们可以假设起点和终点在不同的列中,并且同一组(a 和 b)的范围不重叠。这是我的解决方案。为了清楚起见,我已将 'point_1' 和 'point_2' 称为您的变异 'from' 和 'to'。
可以绑定两个dataframes,将from
col与之前的值lag(from)
进行比较,看实际值是否更小。您还将之前的 lag(to)
与实际的 to
col 进行比较,以查看范围的最大值是否与之前的范围重叠。
重要的是,这些操作不会区分它们比较的两行是否来自同一组(a 或 b)。因此,过滤 point_1
(新的突变 'from' 列)中的 NA,您将删除错误的突变值。
另请注意,我假设 'a' 中的范围不能与 'b' 中的两行重叠。在你的 'results' table 中没有发生,但你应该在你的数据框中检查。
res = rbind(a,b) %>% # Bind by rows
arrange(ID,from) %>% # arrange by ID and starting point (from)
group_by(ID) %>% # perform the following operations grouped by IDs
# Here is the trick. If the ranges for the same ID and group (i.e. 1,a) do
# not overlap, when you mutate the following cols the result will be NA for
# point_1.
mutate(point_1 = ifelse(from <= lag(to), from, NA),
point_2 = ifelse(lag(to)>=to, to, lag(to)),
groups = paste(lag(group), group, sep = ',')) %>%
filter(! is.na(point_1)) %>% # remove NAs in from
select(ID,point_1, point_2, groups) # get the result dataframe
如果您尝试一下代码,而不是使用 filter()
和 select()
,您就会明白它是如何工作的。
> res
# A tibble: 5 x 4
# Groups: ID [3]
ID point_1 point_2 groups
<dbl> <dbl> <dbl> <chr>
1 1 300 400 a,b
2 1 500 500 b,a
3 1 1200 1400 a,b
4 2 1400 1400 a,b
5 3 1300 1400 a,b