Найдите дубликат во фрейме данных и измените указанное значение - PullRequest
3 голосов
/ 16 июня 2020

Я застрял с, вероятно, глупой и легко решаемой проблемой.

У меня есть триггер, который кодирует 1 при нажатии клавиши компьютера (и) и 0 при отпускании клавиши. Мне нужно идентифицировать начало и конец каждого триггера (т.е. первый и последний 1) и заменить 1 между ними на 0. Запись данных - это время (непрерывно, t ниже) и значение (электродермальная активность, значение). Чтобы обработать данные быстрее, мне нужно их предварительно обработать, то есть определить 1, соответствующую началу и концу интересующего окна.

Пожалуйста, найдите пример кода:

t <- seq(0.1,10,0.1)

value <- rnorm(length(t), mean=1, sd=2) 

trig <- c(rep(0,20),rep(c(rep(1,10), rep(0,10)),4))

id <- 1:length(t)

ожидаемый результат:

trig_result <- c(rep(0,20), rep(c(1, rep(0,8),1,rep(0,10)),4)); length(trig_result)

Использование дубликата идентифицирует только первую 1 и последнюю, но не промежуточное значение. Я видел похожий пост, но ни один из них не решает проблему идентификации.

Я смотрю на функцию dplyr, но не могу понять, как заменить 1 на 0, чтобы завершить фазу предварительной обработки. Мы будем благодарны за вашу помощь.

С уважением,

Ответы [ 4 ]

4 голосов
/ 17 июня 2020

Вот базовое решение R с rle и cumsum:

result <- rep(0,length(trig))
result[head(cumsum(rle(trig)$lengths)+c(1,0),-1)] <- 1
all.equal(result,trig_result)
#[1] TRUE

Обратите внимание, что это решение предполагает, что данные начинаются и заканчиваются на 0.

3 голосов
/ 17 июня 2020

Вот еще одно базовое решение R, использующее логические векторы.

borders <- function(x, b = 1){
  n <- length(x)
  d1 <- c(x[1] == b, diff(x) != 0 & x[-1] == b)
  d2 <- c(rev(diff(rev(x)) != 0 & rev(x[-n]) == b), x[n] == b)
  d1 + d2
}

trig <- c(rep(0,20),rep(c(rep(1,10), rep(0,10)),4))
tr <- borders(trig)

Результат не соответствует identical() ожидаемому результату, потому что его класс отличается, но значения равны all.equal().

trig_result <- c(rep(0,20), rep(c(1, rep(0,8),1,rep(0,10)),4))
identical(trig_result, tr)  # FALSE
all.equal(trig_result, tr)  # TRUE

class(trig_result)
#[1] "numeric"
class(tr)
#[1] "integer"
2 голосов
/ 17 июня 2020

Один из вариантов - создать индекс группировки с rle или rleid (из data.table)

library(data.table)
out <- ave(trig, rleid(trig), FUN = function(x)
      x == 1 & (!duplicated(x) | !duplicated(x, fromLast = TRUE)))
identical(trig_result, out)
#[1] TRUE
1 голос
/ 17 июня 2020

Вы хотите найти начало и конец прогона единиц и удалить все единицы, которые не являются началом или концом цикла.

Начало серии единиц - это то место, где значение текущей строки равно 1, а значение предыдущей строки равно 0. Вы можете получить доступ к значению предыдущей строки с помощью функции lag.

Конец серия 1 с - это когда текущая строка равна 1, а следующая строка - нулю. Вы можете получить доступ к значению следующей строки с помощью функции lead.

library(tidyverse)
result = tibble(Trig = trig) %>%
    mutate(StartOfRun = Trig == 1 & lag(Trig == 0),
           EndOfRun = Trig == 1 & lead(Trig == 0),
           Result = ifelse(StartOfRun | EndOfRun, 1, 0)) %>%
    pull(Result)
...