Найдите, какие диапазоны столбцов перекрываются после группировки в R

У меня есть огромный фрейм данных, который выглядит так.

Хочу group_by(chr), а потом для каждого chr найти

  • Перекрывается ли диапазон1 (начало1, конец1) в группе chr с диапазоном2 (начало2, конец2)?
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

Что неправильно. Это могут быть косвенные совпадения, но прямого совпадения нет.

Я думаю, это зависит от того, что вы подразумеваете под перекрытием. Проверьте аргумент типа iv_overlaps. Не могли бы вы пояснить, что вы имеете в виду под перекрытием? Например, в ваших новых данных строка 7 частично перекрывается строкой 8, поэтому iv_overlaps возвращает значение true. Соответственно обновлю свой ответ.

Maël 05.01.2023 23:18

На самом деле перекрывается только одна строка. Но остальные нет. Это отличный улов, Маэль. Так что в идеале у меня должно быть 9 строк с ЛОЖЬЮ и одна с ИСТИНА

LDT 05.01.2023 23:21

Верно. Попробуйте мой код без каких-либо тогда.

Maël 05.01.2023 23:27

@LDT, если вы удалите внешний any() ответов @Maël или моих ответов, вы можете получить 9 строк с ЛОЖЬЮ и одну с ИСТИНА с новыми данными, вы этого хотите? Но с этим правилом ваш первый набор данных получит (F, T, F, F). Очевидно, что два правила в старом и новом наборах данных несовместимы.

Darren Tsai 06.01.2023 03:26

Ты прав, Даррен, но тут надо быть последовательным. Теоретически, это что-то такое простое. Я хочу проверить, пересекается ли какой-либо диапазон2 с любым диапазоном1. С any я получаю наложения, которых не существует. Это может дать прямой результат для небольшого набора данных, но это не означает, что это правильно. Правило одинаково для обоих наборов данных. Новый набор данных не вводит новый вопрос. Он только проверяет код

LDT 06.01.2023 10:22

Основная проблема заключалась в том, что разные интерпретации вашего вопроса могли привести к одним и тем же результатам, поэтому, когда вы попробовали другой сценарий, он больше не работал. Но теперь я думаю, что мы поняли

Maël 06.01.2023 10:51

Вы хотели знать, перекрывается ли какой-либо диапазон2 с любым диапазоном1 в столбце chr, поэтому ваш второй пример не должен быть просто Chr2 -> TRUE?

Cong Chen 06.01.2023 11:35

во втором примере должны быть все ЛОЖЬ, кроме одного, который ИСТИНА. хорошая точка зрения

LDT 06.01.2023 11:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
8
188
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Сценарий 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)))
  ))

Будет ли это работать, даже если перекрытие находится в другом столбце?

Maël 05.01.2023 17:37

Я проверил, и это не работает на конкретном случае. Это зависит от того, что ОП подразумевает под any

Maël 05.01.2023 17:54

@ Маэль Спасибо. Да, это зависит от запроса ОП. Если он хочет эффекта ivs::iv_overlaps(), я предлагаю альтернативу для его достижения.

Darren Tsai 05.01.2023 20:25

Большое спасибо, Даррен, за то, что посмотрели. Я тестировал код на реальных данных и у меня не работал. Я разместил некоторые реальные данные в вопросе. Не могли бы вы также взглянуть

LDT 05.01.2023 21:59

Если вы хотите проверить, происходит ли перекрытие в любом направлении, вам нужно:

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 да, вы были правы - сейчас обновлено.

Allan Cameron 05.01.2023 18:09

Большое спасибо, Аллан. Я ценю, что вы нашли время. Однако, когда я проверяю код на реальных данных, я не получаю желаемых результатов, и я так озадачен. Не могли бы вы тоже посмотреть? Часть реальных данных находится в вопросе

LDT 05.01.2023 22:00
Ответ принят как подходящий

Есть несколько интерпретаций ваших вопросов, поэтому вот три возможных случая:

  1. Внутри группы определите для каждого [start1, end1], пересекаются ли они с любым из [start2, end2].
  2. В группе определите, пересекаются ли какие-либо из [start1, end1] с любым из [start2, end2].
  3. В группе определите, пересекаются ли каждый из [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) )

Спасибо, Маэль. Я поставил кусок реальных данных. Похоже, на моем компьютере код у меня не работает. Я не знаю почему. Ясно, что нет никаких перекрытий и дают перекрытие. Большое спасибо, что нашли время

LDT 05.01.2023 21:58

Спасибо, Маэль. Я думаю, что это все еще не работает универсально с этим кодом. Если у вас есть такой набор данных 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) ), он дает вам перекрытие, когда его нет.

LDT 06.01.2023 10:51

Вы имеете в виду во 2 ряду? есть перекрытие между интервалом 1 строки 2 и интервалом 2 строки 1. Вы не хотите обнаруживать перекрытие даже в этом случае? так только по ряду? Проверьте мое последнее редактирование

Maël 06.01.2023 10:53

Я сожалею, что я не был ясен. Он не должен быть рядным. У нас есть диапазон2, и затем мы хотим сравнить каждый диапазон2 с каждым диапазоном1. Если есть перекрытие, то это ИСТИНА. Мы хотим сравнить каждую строку диапазона2 со всеми строками диапазона1, а затем получить результат.

LDT 06.01.2023 11:04

Можете ли вы объяснить мне, почему вы сказали: «Это дает вам наложение, когда наложения нет»? каков будет ожидаемый результат здесь?

Maël 06.01.2023 11:07

Если я сейчас понимаю, вам просто нужно инвертировать интервалы в iv_overlaps: df1 %>% group_by(chr) %>% mutate(overlap = iv_overlaps(iv(start2, end2), iv(start1, end1)))

Maël 06.01.2023 11:07

ты прав. Например, в Chr1 вы ожидаете, что интервал 200–250 (диапазон 2) будет перекрываться с интервалом (диапазон 1) 200–400. Это должно быть ИСТИНА, ЛОЖЬ, ЛОЖЬ, ЛОЖЬ

LDT 06.01.2023 11:11

Отлично, тогда обратный интервал - это решение.

Maël 06.01.2023 11:12

и тогда в то же время это нужно работать и для данных. Я действительно восхищаюсь вами, Маэль, за то, что вы не отстаете от этого. Ты замечательный

LDT 06.01.2023 11:12

вау, это настоящее расследование здесь

Corrector 06.01.2023 11:18

Если ваше определение перекрытия не является перекрытием, как в ответе Даррена 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')
}

Другие вопросы по теме