У меня есть огромный фрейм данных, который выглядит так.
Хочу group_by(chr)
, а потом для каждого chr
найти
library(dplyr)
df1 <- tibble(chr=c(1,1,2,2),
start1=c(100,200,100,200),
end1=c(150,400,150,400),
species=c("Penguin"),
start2=c(200,200,500,1000),
end2=c(250,240,1000,2000)
)
df1
#> # A tibble: 4 × 6
#> chr start1 end1 species start2 end2
#> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
#> 1 1 100 150 Penguin 200 250
#> 2 1 200 400 Penguin 200 240
#> 3 2 100 150 Penguin 500 1000
#> 4 2 200 400 Penguin 1000 2000
Created on 2023-01-05 with reprex v2.0.2
Я хочу, чтобы мои данные выглядели так. По сути, я хочу проверить, перекрывается ли диапазон2 с любым диапазоном1. Новые данные не меняют вопроса, но код проверяется доказательством
# A tibble: 4 × 6
chr start1 end1 species start2 end2 OVERLAP
1 100 150 Penguin 200 250 TRUE
1 200 400 Penguin 200 240 TRUE
2 100 150 Penguin 500 1000 FALSE
2 200 400 Penguin 1000 2000 FALSE
Я много боролся с пакетом ivs
и iv_overlaps
безуспешно добился того, что хочу.
Основное Обновлено:
Когда я применяю любой из кодов к реальным данным, я не получаю желаемых результатов, и я так запутался. Почему? Новый набор данных не меняет вопрос, но код проверяется доказательствами.
data <- tibble::tribble(
~chr, ~start1, ~end1, ~strand, ~gene, ~start2, ~end2,
"Chr2", 2739, 2840, "+", "A", 740, 1739,
"Chr2", 12577, 12678, "+", "B", 10578, 11577,
"Chr2", 22431, 22532, "+", "C", 20432, 21431,
"Chr2", 32202, 32303, "+", "D", 30203, 31202,
"Chr2", 42024, 42125, "+", "E", 40025, 41024,
"Chr2", 51830, 51931, "+", "F", 49831, 50830,
"Chr2", 82061, 84742, "+", "G", 80062, 81061,
"Chr2", 84811, 86692, "+", "H", 82812, 83811,
"Chr2", 86782, 88106, "-", "I", 88107, 89106,
"Chr2", 139454, 139555, "+", "J", 137455, 138454,
)
data %>%
group_by(chr) %>%
mutate(overlap = any(iv_overlaps(iv(start1, end1), iv(start2, end2))))
то он дает в качестве вывода
chr start1 end1 strand gene start2 end2 overlap
<chr> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <lgl>
1 Chr2 2739 2840 + A 740 1739 TRUE
2 Chr2 12577 12678 + B 10578 11577 TRUE
3 Chr2 22431 22532 + C 20432 21431 TRUE
4 Chr2 32202 32303 + D 30203 31202 TRUE
5 Chr2 42024 42125 + E 40025 41024 TRUE
6 Chr2 51830 51931 + F 49831 50830 TRUE
7 Chr2 82061 84742 + G 80062 81061 TRUE
8 Chr2 84811 86692 + H 82812 83811 TRUE
9 Chr2 86782 88106 - I 88107 89106 TRUE
10 Chr2 139454 139555 + J 137455 138454 TRUE
Что неправильно. Это могут быть косвенные совпадения, но прямого совпадения нет.
На самом деле перекрывается только одна строка. Но остальные нет. Это отличный улов, Маэль. Так что в идеале у меня должно быть 9 строк с ЛОЖЬЮ и одна с ИСТИНА
Верно. Попробуйте мой код без каких-либо тогда.
@LDT, если вы удалите внешний any()
ответов @Maël или моих ответов, вы можете получить 9 строк с ЛОЖЬЮ и одну с ИСТИНА с новыми данными, вы этого хотите? Но с этим правилом ваш первый набор данных получит (F, T, F, F). Очевидно, что два правила в старом и новом наборах данных несовместимы.
Ты прав, Даррен, но тут надо быть последовательным. Теоретически, это что-то такое простое. Я хочу проверить, пересекается ли какой-либо диапазон2 с любым диапазоном1. С any
я получаю наложения, которых не существует. Это может дать прямой результат для небольшого набора данных, но это не означает, что это правильно. Правило одинаково для обоих наборов данных. Новый набор данных не вводит новый вопрос. Он только проверяет код
Основная проблема заключалась в том, что разные интерпретации вашего вопроса могли привести к одним и тем же результатам, поэтому, когда вы попробовали другой сценарий, он больше не работал. Но теперь я думаю, что мы поняли
Вы хотели знать, перекрывается ли какой-либо диапазон2 с любым диапазоном1 в столбце chr
, поэтому ваш второй пример не должен быть просто Chr2
-> TRUE
?
во втором примере должны быть все ЛОЖЬ, кроме одного, который ИСТИНА. хорошая точка зрения
Сценарий 1: Поэлементное обнаружение перекрытия
library(dplyr)
df1 %>%
group_by(chr) %>%
mutate(OVERLAP = any(start1 <= end2 & end1 >= start2)) %>%
ungroup()
# # A tibble: 4 × 7
# chr start1 end1 species start2 end2 OVERLAP
# <dbl> <dbl> <dbl> <chr> <dbl> <dbl> <lgl>
# 1 1 100 150 Penguin 200 250 TRUE
# 2 1 200 400 Penguin 200 240 TRUE
# 3 2 100 150 Penguin 500 1000 FALSE
# 4 2 200 400 Penguin 1000 2000 FALSE
Сценарий 2: Поэлементное обнаружение совпадения с сортировкой
Если интервалы направлены, т.е. end
может быть меньше start
, то перед определением перекрытий нужно сделать сортировку.
df1 %>%
group_by(chr) %>%
mutate(OVERLAP = any(pmin(start1, end1) <= pmax(start2, end2) &
pmax(start1, end1) >= pmin(start2, end2)))
Сценарий 3: перекрестное обнаружение совпадения с сортировкой
Кроме того, если вы хотите проверить, не перекрывает ли интервал (start1, end1)
какой-либо из интервалов (start2, end2)
, в которых работает ivs::iv_overlaps()
, вы можете реализовать это с помощью purrr::map2
.
df1 %>%
group_by(chr) %>%
mutate(OVERLAP = any(
purrr::map2_lgl(start1, end1,
~ any(min(.x, .y) <= pmax(start2, end2) &
max(.x, .y) >= pmin(start2, end2)))
))
Будет ли это работать, даже если перекрытие находится в другом столбце?
Я проверил, и это не работает на конкретном случае. Это зависит от того, что ОП подразумевает под any
@ Маэль Спасибо. Да, это зависит от запроса ОП. Если он хочет эффекта ivs::iv_overlaps()
, я предлагаю альтернативу для его достижения.
Большое спасибо, Даррен, за то, что посмотрели. Я тестировал код на реальных данных и у меня не работал. Я разместил некоторые реальные данные в вопросе. Не могли бы вы также взглянуть
Если вы хотите проверить, происходит ли перекрытие в любом направлении, вам нужно:
df1 %>%
group_by(chr) %>%
mutate(overlap = (max(end1) > min(start2) & min(start2) > min(start1))|
(max(end2) > min(start1) & min(start1) > min(start2)))
#> # A tibble: 4 x 7
#> # Groups: chr [2]
#> chr start1 end1 species start2 end2 overlap
#> <dbl> <dbl> <dbl> <chr> <dbl> <dbl> <lgl>
#> 1 1 100 150 Penguin 200 250 TRUE
#> 2 1 200 400 Penguin 200 240 TRUE
#> 3 2 100 150 Penguin 500 1000 FALSE
#> 4 2 200 400 Penguin 1000 2000 FALSE
Created on 2023-01-05 with reprex v2.0.2
@DarrenTsai да, вы были правы - сейчас обновлено.
Большое спасибо, Аллан. Я ценю, что вы нашли время. Однако, когда я проверяю код на реальных данных, я не получаю желаемых результатов, и я так озадачен. Не могли бы вы тоже посмотреть? Часть реальных данных находится в вопросе
Есть несколько интерпретаций ваших вопросов, поэтому вот три возможных случая:
[start1, end1]
, пересекаются ли они с любым из [start2, end2]
.[start1, end1]
с любым из [start2, end2]
.[start1, end1]
с соответствующим [start2, end2]
(тот, что находится в той же строке).В трех случаях вы можете использовать ivs::iv_overlaps
.
Дело 1
iv_overlaps
обнаружит в каждой группе, пересекаются ли интервалы, определенные в [start1, end1]
, каким-либо образом с любым из интервалов [start2, end2]
. Он вернет логический вектор длины [start1, end1]
.
library(ivs)
library(dplyr)
df1 %>%
group_by(chr) %>%
mutate(overlap = iv_overlaps(iv(start1, end1), iv(start2, end2)))
# A tibble: 4 × 7
# Groups: chr [2]
chr start1 end1 species start2 end2 overlap
<dbl> <dbl> <dbl> <chr> <dbl> <dbl> <lgl>
1 1 100 150 Penguin 200 250 FALSE
2 1 200 400 Penguin 160 170 TRUE
3 2 100 150 Penguin 500 1000 FALSE
4 2 200 400 Penguin 1000 2000 FALSE
Случай 2
Если вы хотите знать, перекрывается ли какой-либо (не каждый) интервал 1 с любым из интервалов 2 (то есть одно уникальное значение на группу), вы должны добавить any
:
df1 %>%
group_by(chr) %>%
mutate(overlap = any(iv_overlaps(iv(start1, end1), iv(start2, end2))))
# A tibble: 4 × 7
# Groups: chr [2]
chr start1 end1 species start2 end2 overlap
<dbl> <dbl> <dbl> <chr> <dbl> <dbl> <lgl>
1 1 100 150 Penguin 200 250 TRUE
2 1 200 400 Penguin 160 170 TRUE
3 2 100 150 Penguin 500 1000 FALSE
4 2 200 400 Penguin 1000 2000 FALSE
Случай 3
Если вы хотите обнаружить перекрытие по строкам, вам следует использовать map2
с iv_overlaps
:
df1 %>%
group_by(chr) %>%
mutate(overlap = map2_lgl(iv(start1, end1), iv(start2, end2), iv_overlaps))
# A tibble: 4 × 7
# Groups: chr [2]
chr start1 end1 species start2 end2 overlap
<dbl> <dbl> <dbl> <chr> <dbl> <dbl> <lgl>
1 1 100 150 Penguin 200 250 FALSE
2 1 200 400 Penguin 160 170 FALSE
3 2 100 150 Penguin 500 1000 FALSE
4 2 200 400 Penguin 1000 2000 FALSE
Порядок сравнения
Действительно, если кто-то хочет сравнить вторые интервалы с первыми, следует использовать iv_overlaps(interval2, interval1)
:
# A tibble: 4 × 7
# Groups: chr [2]
chr start1 end1 species start2 end2 overlap
<dbl> <dbl> <dbl> <chr> <dbl> <dbl> <lgl>
1 1 100 150 Penguin 200 250 TRUE
2 1 200 400 Penguin 160 170 FALSE
3 2 100 150 Penguin 500 1000 FALSE
4 2 200 400 Penguin 1000 2000 FALSE
Данные
df1 <- tibble(chr=c(1,1,2,2), start1=c(100,200,100,200), end1=c(150,400,150,400), species=c("Penguin"), start2=c(200,160,500,1000), end2=c(250,170,1000,2000) )
Спасибо, Маэль. Я поставил кусок реальных данных. Похоже, на моем компьютере код у меня не работает. Я не знаю почему. Ясно, что нет никаких перекрытий и дают перекрытие. Большое спасибо, что нашли время
Спасибо, Маэль. Я думаю, что это все еще не работает универсально с этим кодом. Если у вас есть такой набор данных df1 <- tibble(chr=c(1,1,2,2), start1=c(100,200,100,200), end1=c(150,400,150,400), species=c("Penguin"), start2=c(200,160,500,1000), end2=c(250,170,1000,2000) )
, он дает вам перекрытие, когда его нет.
Вы имеете в виду во 2 ряду? есть перекрытие между интервалом 1 строки 2 и интервалом 2 строки 1. Вы не хотите обнаруживать перекрытие даже в этом случае? так только по ряду? Проверьте мое последнее редактирование
Я сожалею, что я не был ясен. Он не должен быть рядным. У нас есть диапазон2, и затем мы хотим сравнить каждый диапазон2 с каждым диапазоном1. Если есть перекрытие, то это ИСТИНА. Мы хотим сравнить каждую строку диапазона2 со всеми строками диапазона1, а затем получить результат.
Можете ли вы объяснить мне, почему вы сказали: «Это дает вам наложение, когда наложения нет»? каков будет ожидаемый результат здесь?
Если я сейчас понимаю, вам просто нужно инвертировать интервалы в iv_overlaps
: df1 %>% group_by(chr) %>% mutate(overlap = iv_overlaps(iv(start2, end2), iv(start1, end1)))
ты прав. Например, в Chr1 вы ожидаете, что интервал 200–250 (диапазон 2) будет перекрываться с интервалом (диапазон 1) 200–400. Это должно быть ИСТИНА, ЛОЖЬ, ЛОЖЬ, ЛОЖЬ
Отлично, тогда обратный интервал - это решение.
и тогда в то же время это нужно работать и для данных. Я действительно восхищаюсь вами, Маэль, за то, что вы не отстаете от этого. Ты замечательный
вау, это настоящее расследование здесь
Если ваше определение перекрытия не является перекрытием, как в ответе Даррена https://stackoverflow.com/a/75021631/11732165, а сдерживанием ((start1 >= start2 & end1 <= end2) | (start2 >= start1 & end2 <= end1))
, тогда возьмите ответ и используйте нужную логику.
Я использую перекрестное соединение, чтобы убедиться, что вы сравниваете все строки под одним и тем же chr
.
К сожалению, в ваших тестовых данных, несомненно, есть полное сдерживание -
chr start1 end1 strand gene start2 end2 overlap
7 Chr2 82061 84742 + G 80062 81061 TRUE
8 Chr2 84811 86692 + H 82812 83811 TRUE
[start2, end2] для H содержится в [start1, end1] для G.
Код (обратите внимание, что производительность быстро ухудшится, если под одним chr
будет много записей — более 200, вероятно, будет невыносимым, и вам понадобится реализация, которая не включает самопересечение.
check_overlap = function(df){
df %>% mutate(temp_id = 1:nrow(df)) %>%
inner_join(., ., by='chr') %>%
filter(temp_id.x != temp_id.y) %>%
mutate(overlaps = start1.x <= end2.y & end1.x >= start2.y) %>%
group_by(chr) %>%
summarise(OVERLAP = any(overlaps)) %>%
inner_join(df, by = 'chr')
}
check_containment = function(df){
df %>% mutate(temp_id = 1:nrow(df)) %>%
inner_join(., ., by='chr') %>%
filter(temp_id.x != temp_id.y) %>%
mutate(overlaps = (start1.x >= start2.y & end1.x <= end2.y) | (start2.y >= start1.x & end2.y <= end1.x)) %>%
group_by(chr) %>%
summarise(OVERLAP = any(overlaps)) %>%
inner_join(df, by = 'chr')
}
Я думаю, это зависит от того, что вы подразумеваете под перекрытием. Проверьте аргумент типа iv_overlaps. Не могли бы вы пояснить, что вы имеете в виду под перекрытием? Например, в ваших новых данных строка 7 частично перекрывается строкой 8, поэтому iv_overlaps возвращает значение true. Соответственно обновлю свой ответ.