Reputation: 1057
I have two tibbles, ranges and sites. The first contains a set of coordinates (region, start, end, plus other character variables) and the other contains a sites (region, site). I need to get all sites in the second tibble that fall within a given range (row) in the first tibble. Complicating matters, the ranges in the first tibble overlap.
# Range tibble
region start end var_1 ... var_n
1 A 1 5
2 A 3 10
3 B 20 100
# Site tibble
region site
1 A 4
2 A 8
3 B 25
The ~200,000 ranges can be 100,000s long over about a billion sites, so I don't love my idea of a scheme of making a list of all values in the range, unnesting, semi_join'ing, grouping, and summarise(a_list = list(site))'ing.
I was hoping for something along the lines of:
range_tibble %>%
rowwise %>%
mutate(site_list = site_tibble %>%
filter(region.site == region.range, site > start, site < end) %>%
.$site %>% as.list))
to produce a tibble like:
# Final tibble
region start end site_list var_1 ... var_n
<chr> <dbl> <dbl> <list> <chr> <chr>
1 A 1 5 <dbl [1]>
2 A 3 10 <dbl [2]>
3 B 20 100 <dbl [1]>
I've seen answers using "gets" of an external variable (i.e. filter(b == get("b")), but how would I get the variable from the current line in the range tibble? Any clever pipes or syntax I'm not thinking of? A totally different approach is great, too, as long as it plays well with big data and can be turned back into a tibble.
Upvotes: 2
Views: 786
Reputation: 35604
Use left_join()
to merge two data frames and summarise()
to concatenate the sites contained in the specified range.
library(dplyr)
range %>%
left_join(site) %>%
filter(site >= start & site <= end) %>%
group_by(region, start, end) %>%
summarise(site = list(site))
# region start end site
# <fct> <dbl> <dbl> <list>
# 1 A 1 5 <dbl [1]>
# 2 A 3 10 <dbl [2]>
# 3 B 20 100 <dbl [1]>
Data
range <- data.frame(region = c("A", "A", "B"), start = c(1, 3, 20), end = c(5, 10, 100))
site <- data.frame(region = c("A", "A", "B"), site = c(4, 8, 25))
Upvotes: 2