这与Create sequential counter that restarts on a condition within panel data groups和data.table "key indices" or "group counter"有些相关,但不完全相同。
# data table:
x y i d
1: A B 1 1
2: A B 1 1
3: A C 2 2
4: A D 3 3
5: B A 1 4
6: B A 1 4
7: C A 1 4
8: C A 1 4
9: C B 2 5
10: C C 3 6
11: C C 3 6
12: C D 4 7
使用dt[, d:= .GRP, by = .(x,y)]
可以生成最后一列。然而,我正在寻找一个在每个x
组内重启的计数器。请参阅列i
以获取所需结果。
答案 0 :(得分:3)
您可以使用rleid
列y
列上的x
功能来实现这一目标。 rleid
是一种计数器,每次发生变化时都会增加,否则保持不变
library(data.table)
tab <- fread("
x y i d
A B 1 1
A B 1 1
A C 2 2
A D 3 3
B A 1 4
B A 1 4
C A 1 4
C A 1 4
C B 2 5
C C 3 6
C C 3 6
C D 4 7")
dt <- tab[, .(x, y, i)]
dt[, d:= rleid(y), by = .(x)]
dt
#> x y i d
#> 1: A B 1 1
#> 2: A B 1 1
#> 3: A C 2 2
#> 4: A D 3 3
#> 5: B A 1 1
#> 6: B A 1 1
#> 7: C A 1 1
#> 8: C A 1 1
#> 9: C B 2 2
#> 10: C C 3 3
#> 11: C C 3 3
#> 12: C D 4 4
由reprex package(v0.2.0)创建于2018-06-03。
答案 1 :(得分:2)
如果您的数据未在y
x
内排序,则可以
df[, i := .SD[, rep(.GRP, .N), y]$V1, x]
或
df[, i := {ord <- order(y); rleid(y[ord])[order(ord)]}, x]
但是,如果订单不重要,那么在计算y
之前按i
排序会更快
setorder(df, y)
df[, i := rleid(y), x]
比较
df <- df[sample(nrow(df), 1e7, T)]
grp <- function(df) df[, i := .SD[, rep(.GRP, .N), y]$V1, x]
rleid.alone <- function(df)
df[, i := rleid(y), x]
setord.rleid <- function(df) {
setorder(df, y); df[, i := rleid(y), x]}
ord.rleid <- function(df){
df[, i := {ord <- order(y); rleid(y[ord])[order(ord)]}, x]}
microbenchmark(
rleid.alone(df),
setord.rleid(df),
ord.rleid(df),
grp(df),
times = 10
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# rleid.alone(df) 196.5973 201.1499 237.3837 234.6709 262.0397 292.0986 10
# setord.rleid(df) 215.6894 248.7814 285.1045 273.7231 316.5271 382.6173 10
# ord.rleid(df) 7610.9995 7767.9028 8137.2361 7820.5919 8055.2610 10034.9907 10
# grp(df) 336.3208 357.3206 439.5327 394.6960 517.3482 719.8893 10
答案 2 :(得分:1)
我发现先考虑算法,然后再考虑data.table(或base 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()
似乎是@瑞恩的解决方案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