A continuación se muestra un ejemplo simple en el que keyby (también por) no devuelve grupos únicos con subconjuntos.
Sin embargo, una vez que se elimina el subconjunto, keyby funciona correctamente.
library(data.table)
# data.table 1.10.5 IN DEVELOPMENT built 2018-03-21 23:49:00 UTC; travis
# The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way
# Documentation: ?data.table, example(data.table) and browseVignettes("data.table")
# Release notes, videos and slides: http://r-datatable.com
# small dataset
dat <- data.table(Group = rep(c("All", "Not All"), times = 4), count = 1:8, ID = rep(1:2, each = 4))
# keyby returning non unique IDs with subset
dat[Group == "All" ,lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= c("count"), keyby = ID, verbose = TRUE]
# Creating new index 'Group'
# Creating index Group done in ... 0.001sec
# Optimized subsetting with index 'Group'
# on= matches existing index, using index
# Starting bmerge ...done in 0.000sec
# i clause present and columns used in by detected, only these subset: ID
# Finding groups using forderv ... 0.000sec
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ...
# collecting discontiguous groups took 0.000s for 2 groups
# eval(j) took 0.000s for 2 calls
# 0.000sec
# ID count
# 1: 1 4
# 2: 1 12
# keyby working fine without subset
dat[,lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= c("count"), keyby = ID]
# Finding groups using forderv ... 0.000sec
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ...
# memcpy contiguous groups took 0.000s for 2 groups
# eval(j) took 0.000s for 2 calls
# 0.000sec
# ID count
# 1: 1 10
# 2: 2 26
sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)
Matrix products: default
BLAS: /usr/lib/openblas-base/libblas.so.3
LAPACK: /usr/lib/libopenblasp-r0.2.19.so
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=C
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] data.table_1.10.5
loaded via a namespace (and not attached):
[1] compiler_3.4.4
De acuerdo, es un error.
Para el registro, el código recomendado en este caso es:
dat[Group == "All", lapply(.SD, sum, na.rm = TRUE), .SDcols= c("count"), keyby = ID]
Lo que da la respuesta correcta ya que esta versión activará GForce
y el error no está presente en ese caso.
Por supuesto, esto no ayuda si su código real no se puede manipular de esta manera.
Curiosamente, si pasamos las filas del subconjunto directamente, el código funciona:
dat[c(1, 3, 5, 7),
lapply(.SD, function(x) sum(x, na.rm = TRUE)),
.SDcols= "count", keyby = ID, verbose = TRUE]
# i clause present and columns used in by detected, only these subset: ID
# Finding groups using forderv ... 0.000sec
# Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec
# lapply optimization changed j from 'lapply(.SD, function(x) sum(x, na.rm = TRUE))' to 'list(..FUN1(count))'
# GForce is on, left j unchanged
# Old mean optimization is on, left j unchanged.
# Making each group and running j (GForce FALSE) ...
# collecting discontiguous groups took 0.000s for 2 groups
# eval(j) took 0.000s for 2 calls
# 0.000sec
# ID count
# 1: 1 4
# 2: 2 12
Veo la siguiente diferencia en la salida verbose
:
Subconjunto optimizado con índice 'Grupo'
Esto me llevó a instalar desde CRAN; el código se ejecuta sin error en 1.10.4-3
.
Entonces, ¿supongo que esto es algo del trabajo de
También veo el mismo error si hacemos la unión explícita:
dat[.('All'), on = 'Group',
lapply(.SD, function(x) sum(x, na.rm = TRUE)),
.SDcols= "count", keyby = ID]
# ID count
# 1: 1 4
# 2: 1 12
Pero la versión con clave está bien:
setkey(dat, Group)
dat[.('All'),
lapply(.SD, function(x) sum(x, na.rm = TRUE)),
.SDcols= "count", keyby = ID]# ID count
# 1: 1 4
# 2: 2 12
Gracias @cathine por informar y a @MichaelChirico por investigar.
La causa raíz es el comportamiento defectuoso de la versión de unión, como lo señaló Michael:
dat[.('All'), on = 'Group', lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= "count", keyby = ID]
Probablemente se resolverá cuando se resuelva este problema # 2591.
En la nueva optimización de subconjuntos, los subconjuntos se redirigen a la parte de unión de data.table
, por lo que este error ahora afecta a los subconjuntos ahora y también a las uniones. Intentaré investigar lo antes posible si puedo resolver el problema.
Hasta entonces, puedes recurrir a
dat[Group == "All"][ ,lapply(.SD, function(x) sum(x, na.rm = TRUE)), .SDcols= c("count"), keyby = ID, verbose = TRUE]
por ejemplo.
Lo siento por los inconvenientes ocasionados.
¡Gracias @cathine! Confirmado que esto es solo para desarrolladores y se puede solucionar con options(datatable.optimize=2)
ya que el problema parece estar en la optimización de nivel 3. ¡Me pregunto cómo se las arregló para pasar las pruebas!
Ejemplos aún más simples de otro contacto que también informó:
> DT = data.table(
id = c("a","a","a","b","b","c","c","d","d"),
group = c(1,1,1,1,1,2,2,2,2),
num = 1)
> DT[, uniqueN(id), by=group] # ok
group V1
<num> <int>
1: 1 2
2: 2 2
> DT[num==1, uniqueN(id), by=group] # group column wrong
group V1
<num> <int>
1: 1 2
2: 1 2
> options(datatable.optimize=2)
> DT[num==1, uniqueN(id), by=group] # ok
group V1
<num> <int>
1: 1 2
2: 2 2
> options(datatable.optimize=3) # not ok
> DT[num==1, uniqueN(id), by=group]
group V1
<num> <int>
1: 1 2
2: 1 2
> DT[num==1, sum(num), by=group] # ok
group V1
<num> <num>
1: 1 7
2: 2 4
> DT[num==1, length(num), by=group] # not ok
group V1
<num> <int>
1: 1 7
2: 1 4
> options(datatable.optimize=2) # ok
> DT[num==1, length(num), by=group]
group V1
<num> <int>
1: 1 7
2: 2 4
>
¿Por qué pasó las pruebas? ¡Porque solo ocurre si la columna de agrupación está ordenada (consulte el código a continuación)! No verifiqué la agrupación en columnas ordenadas específicamente.
library(data.table)
DT = data.table(
id = c("a","a","a","b","b","c","c","d","d"),
group = c(1,1,1,1,1,2,2,2,2),
group2 = c(1,1,1,1,1,2,2,2,1),
num = 1)
DT[, uniqueN(id), by=group] # ok
# group V1
# <num> <int>
# 1: 1 2
# 2: 2 2
DT[num==1, uniqueN(id), by=group] # group column wrong
# group V1
# <num> <int>
# 1: 1 2
# 2: 1 2
DT[num==1, uniqueN(id), by=group2] # ok with other group column that is not sorted
# group2 V1
# 1: 1 3
# 2: 2 2
setkey(DT, group2)
DT[num==1, uniqueN(id), by=group2] # not ok anymore since the group column is sorted now
# group2 V1
# 1: 1 3
# 2: 1 2
Comentario más útil
De acuerdo, es un error.
Para el registro, el código recomendado en este caso es:
Lo que da la respuesta correcta ya que esta versión activará
GForce
y el error no está presente en ese caso.Por supuesto, esto no ayuda si su código real no se puede manipular de esta manera.
Curiosamente, si pasamos las filas del subconjunto directamente, el código funciona:
Veo la siguiente diferencia en la salida
verbose
:Esto me llevó a instalar desde CRAN; el código se ejecuta sin error en
1.10.4-3
.Entonces, ¿supongo que esto es algo del trabajo de
También veo el mismo error si hacemos la unión explícita:
Pero la versión con clave está bien: