У меня есть несколько фреймов данных с одинаковыми именами столбцов, и ID
, следующие являются началом from
и концом to
диапазона и group
меткой каждого из них.
Я хочу найти, какие значения from
и to
из одного из data frames
входят в диапазон другого. Я оставляю пример изображения, чтобы проиллюстрировать, чего я хочу достичь (на данный момент график не нужен)
Я думал, что смогу сделать это, используя between()
из dplyr package
, но нет. Этого можно добиться, если between()
возвращает true, а затем возвращает максимальное значение from
и минимальное значение to
между фреймами данных.
Я оставляю примеры кадров данных и 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))
Я попытался использовать эту функцию, которая вернет мне значения при совпадении, но не вернет мне общий диапазон между ними.
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
с предыдущим значением lag(from)
, чтобы увидеть, меньше ли фактическое значение. Также вы сравниваете предыдущий столбец lag(to)
с фактическим столбцом to
, чтобы увидеть, перекрывает ли максимальное значение диапазона предыдущий диапазон или нет.
Важно отметить, что эти операции не различают, относятся ли две сравниваемые строки к одной и той же группе (a или b). Поэтому, фильтруя NA в point_1
(новый измененный столбец «из»), вы удалите неправильные измененные значения.
Также обратите внимание, что я предполагаю, что, например, диапазон в «a» не может перекрывать две строки в «b». В вашей таблице результатов этого не происходит, но вы должны проверить это в своих кадрах данных.
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
Это сделало трюк. Действительно полезный ваш ответ!