我发现首先考虑算法,然后考虑 data.table(或基本 R 或 dplyr)应用程序很有帮助。似乎有几种可能的算法来创建所需的计数器。我有
f0 = function(x) match(x, unique(x))
或者如果要对 x 的值进行排序
f1 = function(x) match(x, sort(unique(x)))
这些不同于基于 x 中运行的索引
f2 = function(x) { r = rle(x); r$values = seq_along(r$values); inverse.rle(r) }
我们有其他答案
f3 = function(x) { o <- order(x); rleid(x[o])[order(o)] }
和data.table::rleid()。
这里是不同功能的快速比较
> set.seed(123); x = sample(5, 20, TRUE)
> f0(x); f1(x); f2(x); f3(x); rleid(x)
[1] 1 2 3 4 4 5 3 4 3 3 4 3 2 3 5 4 1 5 1 4
[1] 2 4 3 5 5 1 3 5 3 3 5 3 4 3 1 5 2 1 2 5
[1] 1 2 3 4 4 5 6 7 8 8 9 10 11 12 13 14 15 16 17 18
[1] 2 4 3 5 5 1 3 5 3 3 5 3 4 3 1 5 2 1 2 5
[1] 1 2 3 4 4 5 6 7 8 8 9 10 11 12 13 14 15 16 17 18
澄清实现 f0-f2 各不相同,f2() 和 rleid() 似乎至少对于 f 的域是相同的,f1() 似乎是@Ryan 的解决方案f3()。
有趣的是,问题中提供的数据并没有区分这些实现(我执行 data.table 步骤对吗?)
> dt = tab[, .(x, y, i)]
> (dt[, .(y = y, f0 = f0(y), f1 = f1(y), f2 = f2(y), rleid = rleid(y)), by = .(x)])
x y f0 f1 f2 rleid
1: A B 1 1 1 1
2: A B 1 1 1 1
3: A C 2 2 2 2
4: A D 3 3 3 3
5: B A 1 1 1 1
6: B A 1 1 1 1
7: C A 1 1 1 1
8: C A 1 1 1 1
9: C B 2 2 2 2
10: C C 3 3 3 3
11: C C 3 3 3 3
12: C D 4 4 4 4
建立不同的算法后,可能比较性能以区分替代实现。
> x = sample(100, 10000, TRUE)
> microbenchmark(f0(x), f1(x), f2(x), f3(x), rleid(x))
Unit: microseconds
expr min lq mean median uq max neval
f0(x) 818.773 856.5275 926.5475 880.014 906.6040 5273.431 100
f1(x) 1026.094 1084.1425 1112.1629 1101.626 1133.4100 1384.260 100
f2(x) 1362.461 1428.8665 1595.0777 1622.881 1672.9835 4253.685 100
f3(x) 823.653 862.5090 893.1710 894.268 914.1290 1050.157 100
rleid(x) 236.590 245.0090 252.4963 251.158 257.7365 309.326 100