сравнить несколько столбцов в одном или двух кадрах данных - PullRequest
0 голосов
/ 31 января 2020

У меня есть фрейм данных:

name<-c('a','b','c','d','e')
type<-c('x','x','y','x','y')
chr<- c('ch1','ch1','ch1','ch2','ch2')
pos<- c(5000, 5100, 4999,5500,5100)
df<-data.frame(name,type, chr,pos)

df
Я хотел бы go через каждую строку, и если тип НЕ равен, И chr IS равно, AND pos находится в пределах abs (100), затем создайте новый df с совпадениями (с новым столбцом имени совпадения). Поскольку вышеупомянутые df строки 1 и 3 будут соответствовать, и результат будет

enter image description here

В идеале я не хочу взаимного соответствия и поэтому я хотел бы

enter image description here

Если проще, я могу разделить на две dfs в соответствии с типом.

Я пробовал вариант слияния и фильтрации (dplyr) но никуда не денусь.

Ответы [ 3 ]

4 голосов
/ 31 января 2020

Мы можем разделить данные на основе столбца type, сделать столбец full_join by 'chr' и filter строк, где абсолютные значения между столбцами pos меньше 100.

library(dplyr)

df %>%
  group_split(type) %>%
  purrr::reduce(full_join, by = 'chr') %>%
  filter(abs(pos.x - pos.y) < 100)

# A tibble: 1 x 7
#  name.x type.x chr   pos.x name.y type.y pos.y
#  <fct>  <fct>  <fct> <dbl> <fct>  <fct>  <dbl>
#1  a      x      ch1    5000 c      y       4999

Затем вы можете удалить любые ненужные столбцы и переименовать их согласно вашему требованию.

1 голос
/ 31 января 2020

Я уверен, что другие здесь придумают что-то более элегантное, чем нарезка строк, но, похоже, это сработает, если у вас полный кадр данных всех совпадений:

library(tidyverse)

find_matches <- function(i) {
  row_of_interest <- df[i, ]
  df_rest <- df[-i, ]
  names(df_rest) <- str_c(names(df_rest), ".x")

  df_rest %>% 
    cbind(row_of_interest) %>% 
    filter(type != type.x, abs(pos - pos.x) < 100) %>% 
    transmute(name, type, chr, pos, match = name.x)
}

map_dfr(1:5, find_matches)

  name type chr  pos match
1    a    x ch1 5000     c
2    b    x ch1 5100     e
3    c    y ch1 4999     a
4    e    y ch2 5100     b
0 голосов
/ 31 января 2020

Опция data.table, использующая неэквивалентное объединение, которое должно быть быстрее для большого набора данных:

library(data.table)
setDT(df)[, c("s", "e") := .(pos - 100, pos + 100)]

#perform non-equi join based on desired conditions
pair <- df[df, on=.(chr, s<=pos, e>=pos), nomatch=0L,
    .(name=i.name[x.type!=i.type], match=x.name[x.type!=i.type])]

#extract rows with matches while removing reciprocals
df[unique(pair[, .(name=pmin(name, match), match=pmax(name, match))]), on=.(name)]

вывод:

   name type chr  pos    s    e match
1:    a    x ch1 5000 4900 5100     c
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...