Перенос операций набора из фреймов данных R в таблицы данных: как идентифицировать повторяющиеся строки?

[Обновление 1: как заметил Мэтью Доул, я использую data.table версию 1.6.7 на R-Forge, а не на CRAN. Вы не увидите такого же поведения с более ранней версией data.table.]

В качестве фона: я переношу некоторые небольшие служебные функции для выполнения операций над строками фрейма данных или парами фреймов данных (т.е. каждая строка является элементом набора), например. уникальный - для создания набора из списка, объединения, пересечения, разности наборов и т. д. Они имитируют intersect(...,'rows'), setdiff(...,'rows') и т. д. Matlab, которые, похоже, не имеют аналогов в R (операции набора R ограничены векторами и списками, но не строки матриц или фреймов данных). Примеры этих маленьких функций приведены ниже. Если эта функциональность для фреймов данных уже существует в каком-то пакете или базе R, я открыт для предложений.

Я переносил их в таблицы данных, и одним из необходимых шагов в текущем подходе является поиск повторяющихся строк. При выполнении duplicated() возвращается ошибка о том, что таблицы данных должны иметь ключи. Это досадный барьер — помимо установки ключей, что не является универсальным решением и увеличивает вычислительные затраты, есть ли какой-либо другой способ найти дубликаты объектов?

Вот воспроизводимый пример:

library(data.table)
set.seed(0)
x   <- as.data.table(matrix(sample(2, 100, replace = TRUE), ncol = 4))
y   <- as.data.table(matrix(sample(2, 100, replace = TRUE), ncol = 4))

res3    <- dt_intersect(x,y)

Вывод этого сообщения об ошибке:

Error in duplicated.data.table(z_rbind) : data table must have keys

Код работает как есть для фреймов данных, хотя я назвал каждую функцию шаблоном dt_operation.

Есть ли способ обойти эту проблему? Установка ключей работает только для целых чисел, что является ограничением, которое я не могу принять для входных данных. Итак, возможно, я упускаю умный способ использования таблиц данных?


Примеры функций работы с наборами, где элементами наборов являются строки данных:

dt_unique       <- function(x){
    return(unique(x))
}

dt_union        <- function(x,y){
    z_rbind     <- rbind(x,y)
    z_unique    <- dt_unique(z_rbind)
    return(z_unique)
}

dt_intersect    <- function(x,y){
    zx          <- dt_unique(x)
    zy          <- dt_unique(y)

    z_rbind     <- rbind(zy,zx)
    ixDupe      <- which(duplicated(z_rbind))
    z           <- z_rbind[ixDupe,]
    return(z)
}

dt_setdiff      <- function(x,y){
    zx          <- dt_unique(x)
    zy          <- dt_unique(y)

    z_rbind     <- rbind(zy,zx)
    ixRangeX    <- (nrow(zy) + 1):nrow(z_rbind)
    ixNotDupe   <- which(!duplicated(z_rbind))
    ixDiff      <- intersect(ixNotDupe, ixRangeX)
    diffX       <- z_rbind[ixDiff,]
    return(diffX)
}

Примечание 1. Одним из предполагаемых применений этих вспомогательных функций является поиск строк, в которых значения ключа в x не входят в число значений ключа в y. Таким образом, я могу найти, где могут появиться NA при расчете x[y] или y[x]. Хотя это использование позволяет устанавливать ключи для объекта z_rbind, я бы предпочел не ограничивать себя только этим вариантом использования.

Примечание 2. Для связанных сообщений вот пост о запуске unique на фреймах данных с отличными результатами при запуске с обновленным пакетом data.table. И это более ранняя запись о запуске unique на таблицы данных.


person Iterator    schedule 19.10.2011    source источник


Ответы (1)


duplicated.data.table требуется то же исправление, что и unique.data.table [EDIT: теперь сделано в версии 1.7.2]. Пожалуйста, создайте еще один отчет об ошибке: bug.report(package="data.table"). Чтобы другие смотрели, вы уже используете v1.6.7 от R-Forge, а не 1.6.6 от CRAN.

Но в Note 1 есть идиома «не присоединяться»:

x[-x[y,which=TRUE]]

См. также FR#1384. (Новые аргументы «не» и «какая-то»?), чтобы облегчить пользователям задачу, и ссылки на ключи, которые не соответствуют потоку, который более подробно описан.


Обновить. Теперь в версии 1.8.3 реализовано не-присоединение.

DT[-DT["a",which=TRUE,nomatch=0],...]   # old idiom
DT[!"a",...]                            # same result, now preferred.
person Matt Dowle    schedule 19.10.2011
comment
Спасибо! Хороший вопрос - я забыл упомянуть, что обновил data.table. Кроме того, bug.report() для меня новинка. - person Iterator; 19.10.2011
comment
Мэтью, ваш код должен быть x[-x[y,which=TRUE, nomatch=0]]? Без аргумента nomatch=0 я получаю эту ошибку: Error in [.default(x[[s]], irows) : only 0's may be mixed with negative subscripts. - person Ryogi; 27.10.2011
comment
@RYogi. Точно сказать не могу. Нужен пример, пожалуйста, возможно, в новом вопросе. - person Matt Dowle; 27.10.2011