将集合操作从 R 的数据帧移植到数据表:如何识别重复行?

发布于 2024-12-10 21:51:35 字数 2461 浏览 4 评论 0 原文

[更新 1:正如 Matthew Dowle 指出的那样,我在 R-Forge 上使用 data.table 版本 1.6.7,而不是 CRAN。您不会在早期版本的 data.table 中看到相同的行为。]

作为背景:我正在移植一些小实用函数来对数据帧的行或数据帧对执行设置操作(即每一行都是集合中的一个元素),例如唯一 - 从列表、并集、交集、集合差值等创建集合。这些模仿 Matlab 的 intersect(...,'rows'), setdiff(...,'rows') 等,这些在 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 中的键值中的行。这样,我就可以在计算 x[y]y[x] 时找到 NA 可能出现的位置。尽管这种用法允许为 z_rbind 对象设置键,但我不希望将自己限制在这个用例上。

注 2:对于相关帖子,这里有一篇关于在数据帧上运行 unique 的文章,使用更新的 data.table 包运行它取得了出色的结果。 这是一篇关于运行 >数据表上唯一

[Update 1: As Matthew Dowle noted, I'm using data.table version 1.6.7 on R-Forge, not CRAN. You won't see the same behavior with an earlier version of data.table.]

As background: I am porting some little utility functions to do set operations on rows of a data frame or pairs of data frames (i.e. each row is an element in a set), e.g. unique - to create a set from a list, union, intersection, set difference, etc. These mimic Matlab's intersect(...,'rows'), setdiff(...,'rows'), etc., which don't appear to have counterparts in R (R's set operations are limited to vectors and lists, but not rows of matrices or data frames). Examples of these little functions are below. If this functionality for data frames already exists in some package or base R, I'm open to suggestions.

I have been migrating these to data tables and one necessary step in the current approach is to find duplicated rows. When duplicated() is executed an error is returned stating that data tables must have keys. This is an unfortunate roadblock - other than setting keys, which isn't a universal solution and adds to computational costs, is there some other way to find duplicated objects?

Here is a reproducible example:

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)

Yielding this error message:

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

The code works as-is for data frames, though I've named each function with the pattern dt_operation.

Is there some way to get around this issue? Setting keys only works for integers, which is a constraint I can't assume for the input data. So, perhaps I'm missing a clever way to use data tables?


Example set operation functions, where the elements of the sets are rows of data:

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)
}

Note 1: One intended use for these helper functions is to find rows where key values in x are not among the key values in y. This way, I can find where NAs may appear when calculating x[y] or y[x]. Although this usage allows for setting of keys for the z_rbind object, I'd prefer not to constrain myself to just this use case.

Note 2: For related posts, here is a post on running unique on data frames, with excellent results for running it with the updated data.table package.
And this is an earlier post on running unique on data tables.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冧九 2024-12-17 21:51:35

duplicated.data.table 需要相同的修复 unique.data.table 得到[编辑:现已在 v1.7.2 中完成]。请提出另一个错误报告:bug.report(package="data.table")。为了其他人观看的利益,您已经在使用 R-Forge 的 v1.6.7,而不是 CRAN 上的 1.6.6。

但是,在注释 1 上,有一个“不加入”惯用语:

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

另请参阅 FR#1384 (新的“not”和“whichna”参数?)对用户来说更容易,并且链接到 不匹配线程,其中有更多细节。


更新。现在在 v1.8.3 中,已经实现了 not-join。

DT[-DT["a",which=TRUE,nomatch=0],...]   # old idiom
DT[!"a",...]                            # same result, now preferred.

duplicated.data.table needs the same fix unique.data.table got [EDIT: Now done in v1.7.2]. Please raise another bug report: bug.report(package="data.table"). For the benefit of others watching, you're already using v1.6.7 from R-Forge, not 1.6.6 on CRAN.

But, on Note 1, there's a 'not join' idiom :

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

See also FR#1384 (New 'not' and 'whichna' arguments?) to make that easier for users, and that links to the keys that don't match thread which goes into more detail.


Update. Now in v1.8.3, not-join has been implemented.

DT[-DT["a",which=TRUE,nomatch=0],...]   # old idiom
DT[!"a",...]                            # same result, now preferred.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文