检查两个指标是否相同

Check whether two indicators are the same

我得到一个大数据 table,其中有两个指标 ind1ind2,可能有重复。例如

 set.seed(1)
 ind1 <- sample(1:3,1000, replace=TRUE )
 ind2 <- c("a","b","c")[ind1]

 dt <- data.table(ind1=ind1, ind2=ind2)

我现在想检查一下,这两个指标是否以相同的方式对数据进行分组,即

两行具有相同的指标 ind1 当且仅当它们也具有相同的指标 ind2。在上面的示例中,构造就是这种情况。

您可以简单地按 ind2 分组并计算不同的 ind1 或 vice-versa。如果任何计数 > 1,则它们不会以相同的方式对数据进行分组。这是一种使用 base R -

的方法
any(with(dt, ave(ind1, ind2, FUN = function(x) length(unique(x)))) > 1)

[1] FALSE # means ind1 and ind2 group the data in same way

或者,如果更容易解释,您可以使用 all 检查是否所有计数 == 1 -

all(with(dt, ave(ind1, ind2, FUN = function(x) length(unique(x)))) == 1)

[1] TRUE # means ind1 and ind2 group the data in same way

您可以使用两个变量创建一个数字组索引,并检查它们对所有行是否相等。

这会将两个组索引添加到 table 并检查是否相等,但如果需要,您可以在之后删除这些列

dt[,  g1 := .GRP, ind1][, g2 := .GRP, ind2][, all(g1 == g2)]
#[1] TRUE

编辑:Shree unique-counting 的想法更好。 data.table 实施见下文

Edit2:另请参阅其他解决方案的评论

dt[, uniqueN(ind2), ind1][, all(V1 == 1)]
#[1] TRUE

具有 1e7 行和 10 组的 table 基准,用两个等效列表示

set.seed(1)
ind1 <- sample(1:10,1e7, replace=TRUE )
ind2 <- c("a","b","c")[ind1]

dt <- data.table(ind1=ind1, ind2=ind2)

microbenchmark::microbenchmark(
grp = dt[,  g1 := .GRP, ind1][, g2 := .GRP, ind2][, all(g1 == g2)], 
uniques = dt[, uniqueN(ind2), ind1][, all(V1 == 1)]
)

# Unit: milliseconds
#     expr      min       lq    mean   median       uq       max neval cld
#      grp 727.9489 838.2190 918.280 879.1036 971.3982 1542.9655   100   b
#  uniques 472.1311 502.1327 529.581 526.5357 540.5406  723.5078   100  a 

我的直觉是像@IceCreamToucan 的回答那样使用 .GRP,但另一种方法是联合删除两列的重复项,然后分别检查每列中的重复项:

# data.table
unique(dt[, c("ind1", "ind2")])[, !(anyDuplicated(ind1) || anyDuplicated(ind2))]

# base, with df = data.frame(dt)
with(unique(df[, c("ind1", "ind2")]), !(anyDuplicated(ind1) || anyDuplicated(ind2)))

我尝试了各种基准测试,但没有看到任何明确的结果,令人惊讶的是,上述两个选项之间的时间几乎总是非常有利于 data.table。

带有#rows 和#groups 参数的示例:

library(data.table)
library(magrittr)

ng = 150
n = 1e6
set.seed(1)
ind1 <- sample(1:ng, n, replace=TRUE )
ind2 <- -ind1

dt <- data.table(ind1=ind1, ind2=ind2)
df = data.frame(dt)

microbenchmark::microbenchmark(times = 3L,
grp = dt[,  g1 := .GRP, ind1][, g2 := .GRP, ind2][, all(g1 == g2)], 
uniques = dt[, uniqueN(ind2), ind1][, all(V1 == 1)],
shreet = with(dt, max(tapply(ind1, ind2, function(x) length(unique(x))))) == 1L,
shreep = with(dt, tapply(ind1, ind2, . %>% unique %>% length)) %>% max %>% equals(1L),
another = unique(dt[, c("ind1", "ind2")])[, !(anyDuplicated(ind1) || anyDuplicated(ind2))],
banother = with(unique(df[, c("ind1", "ind2")]), !(anyDuplicated(ind1) || anyDuplicated(ind2)))
)

结果:

Unit: milliseconds
     expr        min         lq       mean     median         uq        max neval
      grp   31.89250   34.92348   46.06510   37.95446   53.15140   68.34833     3
  uniques   32.82520   34.36808   36.32377   35.91097   38.07306   40.23515     3
   shreet   38.26046   38.35256   44.37116   38.44467   47.42650   56.40834     3
   shreep   43.37336   98.56367  145.38600  153.75399  196.39231  239.03064     3
  another   14.47064   31.42879   88.20134   48.38694  125.06669  201.74643     3
 banother 1338.14070 1427.35481 1658.08404 1516.56893 1818.05572 2119.54251     3