Создание подмножеств повторяющихся данных из большого набора данных - PullRequest
2 голосов
/ 15 апреля 2019

Я пытаюсь извлечь определенные данные из большого набора данных, используя R. Данные взяты из процесса, который проходит несколько этапов, скажем, фазы 0-5. У меня есть набор данных, который содержит несколько запусков процесса.

Я пытаюсь извлечь данные для каждого из прогонов. Я хочу создать подмножества с первым появлением фазы от 0 до 5, а затем с другим подмножеством снова с фазами от 0 до 5 (второго запуска). Набор данных содержит только данные процесса и номер фазы в хронологическом порядке, он не указывает, в каком цикле он находится. Однако фазы расположены по порядку, поэтому столбец фазы переходит от 0 до 5, а затем снова начинается с 0.

Я уже пытался организовать данные, используя некоторые циклы while и for, однако это очень медленно для такого большого набора данных (700 000 записей). Даже использование небольшого раздела из 10000 записей занимает довольно много времени.

набор данных может выглядеть примерно так (второй столбец - фаза):

01, 0, 2, 4, 5, 3, 4,
02, 0, 3, 4, 5, 2, 2,
03, 0, 4, 5, 4, 9, 8,
04, 1, 8, 9, 2, 7, 3,
05, 1, 8, 7, 0, 7, 8,
06, 2, 8, 4, 9, 7, 8,
07, 2, 9, 7, 5, 0, 8,
08, 2, 8, 6, 5, 7, 9,
07, 2, 8, 7, 6, 7, 9,
08, 3, 7, 8, 6, 7, 9,
09, 3, 7, 9, 8, 7, 8, 
10, 4, 5, 6, 7, 4, 3,
11, 4, 6, 7, 5, 6, 4,
12, 5, 6, 4, 3, 2, 2,
13, 0, 6, 3, 3, 2, 5,
14, 0, 5, 6, 3, 2, 2,
15, 1, 5, 2, 1, 4, 4,

обратите внимание, что число линий на фазу не является постоянным.

Подмножества, которые я ожидал бы из приведенного выше примера, будут:

01, 0, 2, 4, 5, 3, 4,
02, 0, 3, 4, 5, 2, 2,
03, 0, 4, 5, 4, 9, 8,
04, 1, 8, 9, 2, 7, 3,
05, 1, 8, 7, 0, 7, 8,
06, 2, 8, 4, 9, 7, 8,
07, 2, 9, 7, 5, 0, 8,
08, 2, 8, 6, 5, 7, 9,
07, 2, 8, 7, 6, 7, 9,
08, 3, 7, 8, 6, 7, 9,
09, 3, 7, 9, 8, 7, 8, 
10, 4, 5, 6, 7, 4, 3,
11, 4, 6, 7, 5, 6, 4,
12, 5, 6, 4, 3, 2, 2,

и

13, 0, 6, 3, 3, 2, 5,
14, 0, 5, 6, 3, 2, 2,
15, 1, 5, 2, 1, 4, 4,

(примечание: в исходном наборе данных фаза всегда заканчивается на 5)

Ответы [ 2 ]

2 голосов
/ 15 апреля 2019

В вашей задаче новое подмножество запускается только в том случае, если фазовый индекс (приведенный во втором столбце) уменьшается. Таким образом, мы можем объединить which с diff, чтобы получить индексы строк, в которых заканчивается фаза.

Сначала мы можем получить индексы строк, с которых начинается / заканчивается подмножество, следующим образом:

end   <- which(diff(data[,2]) < 0)
start <- c(1, end + 1)
end   <- c(end, nrow(data))

Затем мы можем использовать это для составления списка с подмножествами следующим образом:

subsets <- vector("list", length(start))

for (idx in 1:length(start))
  subsets[[idx]] <- data[start[idx]:end[idx],]

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

РЕДАКТИРОВАТЬ: Конечно, R имеет решение, которое позволяет избежать утверждения for. Мы должны создать новый вектор, который указывает для каждой строки, к какому подмножеству он принадлежит. Учитывая два вышеупомянутых вектора end и start, этого легко достичь (см. Фрагмент кода ниже). Затем мы можем использовать встроенную функцию split и преобразовать ее вывод в список матриц (вдохновленный на этот ответ ).

# How many rows does each subset has?
n <- end - start + 1

# Create vector that indicates for each row to which subset it belongs 
idx_subset <- rep(1:length(start), n)

# Create the subsets
subsets <- lapply( split(data, idx_subset), matrix, ncol=7)
1 голос
/ 15 апреля 2019

Вот векторизованное решение

# sample df
df = read.table(text = "
v1  phase   v3  v4  v5  v6  v7
01  0   2   4   5   3   4
02  0   3   4   5   2   2
03  0   4   5   4   9   8
04  1   8   9   2   7   3
05  1   8   7   0   7   8
06  2   8   4   9   7   8
07  2   9   7   5   0   8
08  2   8   6   5   7   9
07  2   8   7   6   7   9
08  3   7   8   6   7   9
09  3   7   9   8   7   8   
10  4   5   6   7   4   3
11  4   6   7   5   6   4
12  5   6   4   3   2   2
13  0   6   3   3   2   5
14  0   5   6   3   2   2
15  1   5   2   1   4   4
                ", stringsAsFactors = F, header = T)

# create groups for splitting df
grp <- cumsum( c( 0, diff( df$phase ) ) < 0 ) + 1

# split the df
split(df, grp)
#> $`1`
#>    v1 phase v3 v4 v5 v6 v7
#> 1   1     0  2  4  5  3  4
#> 2   2     0  3  4  5  2  2
#> 3   3     0  4  5  4  9  8
#> 4   4     1  8  9  2  7  3
#> 5   5     1  8  7  0  7  8
#> 6   6     2  8  4  9  7  8
#> 7   7     2  9  7  5  0  8
#> 8   8     2  8  6  5  7  9
#> 9   7     2  8  7  6  7  9
#> 10  8     3  7  8  6  7  9
#> 11  9     3  7  9  8  7  8
#> 12 10     4  5  6  7  4  3
#> 13 11     4  6  7  5  6  4
#> 14 12     5  6  4  3  2  2
#> 
#> $`2`
#>    v1 phase v3 v4 v5 v6 v7
#> 15 13     0  6  3  3  2  5
#> 16 14     0  5  6  3  2  2
#> 17 15     1  5  2  1  4  4

Создано в 2019-04-15 пакетом Представитель (v0.2.1)

Объяснение: diff вычисляет разницу определенного значения от предыдущего, тогда оператор < оценивает, если результат меньше 0.Результирующий логический вектор T, F добавляется с другим 0 спереди, чтобы длина вектора была такой же, как количество строк в df.cumsum затем находит накопленную текущую сумму значений, которая будет изменяться только при меньшем значении фазы сразу после фазы 5, следовательно, по существу, создавая группы.Затем эти группы (grp) используются для разделения df.

...