Определите, когда столбцы значения data.frame меняют значение и возвращают индексы изменения
Я пытаюсь найти способ определить, когда набор столбцов меняет значение в data.frame. Позвольте мне прямо сказать, рассмотрим следующий пример:
x<-data.frame(cnt=1:10, code=rep('ELEMENT 1',10), val0=rep(5,10), val1=rep(6,10),val2=rep(3,10))
x[4,]$val0=6
- Столбец cnt - это уникальный идентификатор (может быть дата или столбец времени, для простоты здесь int)
- Кодовый столбец похож на код для набора строк (представьте несколько таких групп, но с разными кодами). Код и cnt являются ключами в моей таблице данных.
- Столбцы val0, val1, val2 являются чем-то вроде результатов.
Приведенный выше формат данных должен быть прочитан как: Оценки для "ELEMENT 1" начались как 5,6,3, оставались как есть до 4-й итерации, когда они изменились на 6,6,3, а затем изменились на 5,6,3.
Мой вопрос: есть ли способ получить строку 1-го, 4-го и 5-го данных .frame? Есть ли способ обнаружить, когда столбцы меняются? (Есть 12 столбцов кстати)
Я попытался использовать дублированный data.table(который отлично работал в большинстве случаев), но в этом случае он удалит все дубликаты и оставит только строки 1 и 4 (удаление 5-го).
Есть ли у вас предложения? Я бы предпочел не использовать цикл for, поскольку прибл. 2M.
Ответы
Ответ 1
В data.table
версии 1.8.10 (стабильная версия в CRAN) существует (n) (неэкспортированная) функция, называемая duplist
, которая выполняет именно это. И он также написан на C и поэтому ужасно быстр.
require(data.table) # 1.8.10
data.table:::duplist(x[, 3:5])
# [1] 1 4 5
Если вы используете версию разработки data.table
(1.8.11), тогда существует более эффективная версия (с точки зрения памяти), переименованная в uniqlist
, которая выполняет точно такую же работу. Вероятно, это должно быть экспортировано для следующего выпуска. Кажется, что он поднялся на SO более одного раза. Посмотрим.
require(data.table) # 1.8.11
data.table:::uniqlist(x[, 3:5])
# [1] 1 4 5
Ответ 2
Полностью нечитаемый, но:
c(1,which(rowSums(sapply(x[,grep('val',names(x))],diff))!=0)+1)
# [1] 1 4 5
В принципе, запустите diff
в каждой строке, чтобы найти все изменения. Если изменение происходит в любом столбце, то в строке произошла смена.
Кроме того, без sapply
:
c(1,which(rowSums(diff(as.matrix(x[,grep('val',names(x))])))!=0)+1)