Объединение аномальных интервалов из разных групп с использованием расстояния по интервалам, а не расстояния по ячейкам - PullRequest
1 голос
/ 20 апреля 2020

У меня есть большой фрейм данных, в котором есть зоны, к которым я пытаюсь присоединиться, внутри групп, где расстояние между интервалами (а не расстояние между ячейками) меньше заданного значения. Ниже приведен базовый пример.

Этот фрейм данных имеет две группы (GRP1 и GRP2) в столбце «Группа» и зоны, заданные двоичным значением в столбце «Зоны», для интервалов, определяемых значениями от и до (в поле «От» столбцы 'и' To '). Мне нужно объединить 'Zones' со значением 1 в пределах 'Groups', заменив 0 на 1, где разница в интервале между зонами равна или меньше 1 единицы (т.е. расстояние между столбцами 'To' и 'From' со значениями 1 равен или меньше 1 единицы).

Например, в приведенном ниже фрейме данных значения 13 и 14 для Sample.ID должны иметь значения 0 для зоны, замененные на 1. Причина в том, что они попадают между Sample.ID 12 и Sample.ID 15, которые оба имеют значения Zone 1, оба относятся к одной и той же группе (например, GRP2) с расстоянием, равным 1 (т.е. Sample.ID 12 'To' значение = 14 и Sample.ID 15 из значения = 15).

Sample.ID 6 и 7 будут иметь значения 'Zone', которые будут оставаться 0, поскольку расстояние между Sample.ID 5 и 8 будет больше 1, а Sample.ID 3 также будет оставаться как 0 Sample.ID 4 из другой группы

   Sample.ID Groups From   To Zones
1          1   GRP1  2.0  3.0     1
2          2   GRP1  3.0  4.0     1
3          3   GRP2  4.0  5.0     0
4          4   GRP2  5.0  6.0     1
5          5   GRP2  6.0  7.0     1
6          6   GRP2  7.0  8.0     0
7          7   GRP2  8.0  9.0     0
8          8   GRP2  9.0 10.0     1
9          9   GRP2 10.0 11.0     1
10        10   GRP2 11.0 12.0     1
11        11   GRP2 12.0 13.0     1
12        12   GRP2 13.0 14.0     1
13        13   GRP2 14.0 14.3     0
14        14   GRP2 14.3 15.0     0
15        15   GRP2 15.0 16.0     1

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Возможность скользящего соединения с использованием data.table:

DT[, newZones := Zones]
DT[Zones==0L, lastTo := DT[Zones==1L][.SD, on=.(Groups, To=From), roll=Inf, x.To]]
DT[Zones==0L, firstFrom := DT[Zones==1L][.SD, on=.(Groups, From=To), roll=-Inf, x.From]]
DT[Zones==0L & firstFrom - lastTo <= 1, newZones := 1L]

выход:

    SampleID Groups From   To Zones newZones lastTo firstFrom
 1:        1   GRP1  2.0  3.0     1        1     NA        NA
 2:        2   GRP1  3.0  4.0     1        1     NA        NA
 3:        3   GRP2  4.0  5.0     0        0     NA         5
 4:        4   GRP2  5.0  6.0     1        1     NA        NA
 5:        5   GRP2  6.0  7.0     1        1     NA        NA
 6:        6   GRP2  7.0  8.0     0        0      7         9
 7:        7   GRP2  8.0  9.0     0        0      7         9
 8:        8   GRP2  9.0 10.0     1        1     NA        NA
 9:        9   GRP2 10.0 11.0     1        1     NA        NA
10:       10   GRP2 11.0 12.0     1        1     NA        NA
11:       11   GRP2 12.0 13.0     1        1     NA        NA
12:       12   GRP2 13.0 14.0     1        1     NA        NA
13:       13   GRP2 14.0 14.3     0        1     14        15
14:       14   GRP2 14.3 15.0     0        1     14        15
15:       15   GRP2 15.0 16.0     1        1     NA        NA

данные:

library(data.table)
DT <- fread("SampleID Groups From   To Zones
1   GRP1  2.0  3.0     1
2   GRP1  3.0  4.0     1
3   GRP2  4.0  5.0     0
4   GRP2  5.0  6.0     1
5   GRP2  6.0  7.0     1
6   GRP2  7.0  8.0     0
7   GRP2  8.0  9.0     0
8   GRP2  9.0 10.0     1
9   GRP2 10.0 11.0     1
10   GRP2 11.0 12.0     1
11   GRP2 12.0 13.0     1
12   GRP2 13.0 14.0     1
13   GRP2 14.0 14.3     0
14   GRP2 14.3 15.0     0
15   GRP2 15.0 16.0     1")
1 голос
/ 20 апреля 2020

Вот один из способов сделать это с помощью пользовательской функции.

library(dplyr)

change_to_1 <- function(From, To, Zones) {
  #Get index where zone = 0
  inds <- which(Zones == 0)
  #Differentiate separate instances of 0's
  all_0_pairs <- split(inds, cumsum(c(TRUE, diff(inds) > 1)))
  #Change the Zone values to 1 where the difference is less than 1
  #and 0-index is not present in first or last row. 
  Zones[unlist(Filter(function(i) {
      if(all(between(i, 2, length(Zones) - 1)))
         (From[i[length(i)] + 1] - To[i[1] - 1]) <= 1
      else
         FALSE
  }, all_0_pairs))] <- 1
  return(Zones)
}

Затем примените эту функцию к каждой группе.

df %>% group_by(Groups) %>% mutate(New_zone = change_to_1(From, To, Zones))


#   Sample.ID Groups  From    To Zones New_zone
#       <int> <fct>  <dbl> <dbl> <int>    <dbl>
# 1         1 GRP1     2     3       1        1
# 2         2 GRP1     3     4       1        1
# 3         3 GRP2     4     5       0        0
# 4         4 GRP2     5     6       1        1
# 5         5 GRP2     6     7       1        1
# 6         6 GRP2     7     8       0        0
# 7         7 GRP2     8     9       0        0
# 8         8 GRP2     9    10       1        1
# 9         9 GRP2    10    11       1        1
#10        10 GRP2    11    12       1        1
#11        11 GRP2    12    13       1        1
#12        12 GRP2    13    14       1        1
#13        13 GRP2    14    14.3     0        1
#14        14 GRP2    14.3  15       0        1
#15        15 GRP2    15    16       1        1

данные

df <- structure(list(Sample.ID = 1:15, Groups = structure(c(1L, 1L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("GRP1", 
"GRP2"), class = "factor"), From = c(2, 3, 4, 5, 6, 7, 8, 9, 
10, 11, 12, 13, 14, 14.3, 15), To = c(3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13, 14, 14.3, 15, 16), Zones = c(1L, 1L, 0L, 1L, 1L, 
0L, 0L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 1L)), class = "data.frame",
row.names = c(NA, -15L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...