Определить последовательности между одинаковыми значениями - PullRequest
0 голосов
/ 28 ноября 2018

У меня большая матрица:

id    v1   v2   v3   v4   v5   v6   v7   v8
1001   37   15   30   37    4   11   35   37
2111   44   31   44   30   24   39   44   18
3121   43   49   39   34   44   43   26   24
4532   45   31   26   33   12   47   37   15
5234   23   27   34   23   30   34   23    4
6345   9    46   39   34    8   43   26   24

Для каждой строки (id) я хотел бы определить интервалы чисел в столбце от v1 до v8.Интервал здесь определяется как последовательность чисел, которая начинается и заканчивается одним и тем же номером.

Например, в первой строке есть две последовательности, которые начинаются и заканчиваются на 37: от столбца 1 до 4( 37 , 15, 30, 37 ) и от столбца 4 до столбца 8 ( 37 , 4, 11, 35, 37 ).

Фокусное значение должно появляться только в начальных и конечных положениях.Например, в первой строке последовательность от 37 в V1 до 37 в V8 не включена, потому что 37 также происходит в V4.

Для каждого интервала я хочу индексначального и конечного столбцов, начальное и конечное значения фокуса и последовательность чисел между ними.

Желаемый вывод:

1001 [v1] to [v4] 37 to 37: 15,30
1001 [v4] to [v8] 37 to 37: 4, 11, 35
2111 [v1] to [v3] 44 to 44: 31 
2111 [v3] to [v7] 44 to 44: 30, 24, 39

Есть предложения?Алгоритм?

Мне удалось закодировать индексы для вектора, а не матрицы,

a <- which(x == 37)
from <- a[!(a-1) %in% a]
to <- a[!(a+1) %in% a]
rbind(from, to)

Ответы [ 2 ]

0 голосов
/ 01 декабря 2018

Вот альтернатива data.table.

Преобразование матрицы в data.table и melt в длинный формат.Создайте индекс столбца 'ci', чтобы отслеживать исходные столбцы (rowid(id)).Порядок по 'id'.

Для каждого 'id' и 'value' (by = .(id, value)) проверьте, не превышает ли число строк одно (if(.N > 1)), т. Е. Существует ли хотя бы одна последовательность,Если это так, возьмите индекс строки (.I) последовательностей и индексов их столбцов (в исходных данных).Для каждой последовательности возьмите соответствующие значения между начальным и конечным индексом.Оберните list дважды (.(.(), чтобы создать столбец списка.

library(data.table)
d <- melt(as.data.table(m), id.vars = "id")
d[ , `:=`(
  ci = rowid(id),
  variable = NULL)]  
setorder(d, id)

d2 <- d[ , if(.N > 1){
  .(from = .I[-.N], to = .I[-1],
    from_ci = ci[-.N], to_ci = ci[ -1])
}, by = .(id, value)]

d2[ , val := .(.(d$value[seq(from + 1, to - 1)])), by = 1:nrow(d2)]
d2[ , `:=`(from = NULL, to = NULL)]

#      id value from_ci to_ci         val
# 1: 1001    37       1     4       15,30
# 2: 1001    37       4     8     4,11,35
# 3: 2111    44       1     3          31
# 4: 2111    44       3     7    30,24,39
# 5: 3121    43       1     6 49,39,34,44
# 6: 5234    23       1     4       27,34
# 7: 5234    23       4     7       30,34
# 8: 5234    34       3     6       23,30
0 голосов
/ 28 ноября 2018

Метод очень грубой силы.Получить уникальные элементы для данной строки, проверить, присутствуют ли они более одного раза, но не рядом, затем lapply через каждый, получая элементы строки x между ними.

apply(m, 1, function(x) {
  u <- unique(x)
  u <- u[sapply(u, function(u) any(diff(which(x == u)) > 1))]
  lapply(setNames(u, u), function(u){ 
      ind <- which(x == u)
      lapply(seq(length(ind) - 1), 
             function(i) x[seq(ind[i] + 1, ind[i + 1] - 1)])
  })
})

Вывод:

# [[1]]
# [[1]]$`37`
# [[1]]$`37`[[1]]
# [1] 15 30
# 
# [[1]]$`37`[[2]]
# [1]  4 11 35
# 
# 
# 
# [[2]]
# [[2]]$`44`
# [[2]]$`44`[[1]]
# [1] 31
# 
# [[2]]$`44`[[2]]
# [1] 30 24 39
# 
# 
# 
# [[3]]
# [[3]]$`43`
# [[3]]$`43`[[1]]
# [1] 49 39 34 44
# 
# 
# 
# [[4]]
# named list()
# 
# [[5]]
# [[5]]$`23`
# [[5]]$`23`[[1]]
# [1] 27 34
# 
# [[5]]$`23`[[2]]
# [1] 30 34
# 
# 
# [[5]]$`34`
# [[5]]$`34`[[1]]
# [1] 23 30
# 
# 
# 
# [[6]]
# named list()

Редактировать: ответ Хенрика вдохновил меня на создание версии для соединения

library(data.table)
library(magrittr)

d <- melt(as.data.table(m), "id", variable.name = 'ci')[, ci := rowid(id)]

setorder(d, id) 
options(datatable.nomatch = 0)

d[d, on = .(id, value, ci > ci)
  , .(id, value, i.ci, x.ci)
  , mult = 'first'] %>% 
  .[d, on = .(id, i.ci < ci, x.ci > ci)
    , .(id, value, from_ci = x.i.ci, to_ci = x.x.ci, i.value)] %>% 
  .[, .(val = .(i.value))
    , by = setdiff(names(.), 'i.value')]


#      id value from_ci to_ci         val
# 1: 1001    37       1     4       15,30
# 2: 1001    37       4     8     4,11,35
# 3: 2111    44       1     3          31
# 4: 2111    44       3     7    30,24,39
# 5: 3121    43       1     6 49,39,34,44
# 6: 5234    23       1     4       27,34
# 7: 5234    34       3     6       23,30
# 8: 5234    23       4     7       30,34
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...