Data.table: agregue un parámetro 'tener' a `[.data.table`

Creado en 29 ago. 2014  ·  28Comentarios  ·  Fuente: Rdatatable/data.table

Actualmente, para tener el equivalente (o algo similar) de la cláusula having SQL, debe escribir [.data.table primero usando by y luego introducir el resultado en i parámetro de un segundo [.data.table , como en:

dt <- data.table(id   = rep(1:2, each = 2),
                 var  = c(0.2, 0.5, 1.5, 1.3))

dt[dt[, mean(var) > 1, by = id]$id]
   id var
1:  2 1.5
2:  2 1.3

Otra opción es usar una declaración condicional dentro j , muy potente, lo hago todo el tiempo, y hasta ahora no hay nada que la sintaxis actual no me permita hacer. Sin embargo, tener un parámetro having creo que permitirá escribir códigos mucho más claros y legibles. Por ejemplo lo anterior se puede escribir como:

dt[, if(mean(var) > 1) .SD, by = id]

Lo que propongo es algo como:

dt[, .SD, by = id, having = mean(var) > 1]

La idea es tener una expresión que siempre se evalúe como una lógica de longitud 1 que diga si j debe evaluarse o no para el grupo actual.

Gracias,
michele

feature request

Comentario más útil

Otro ejemplo de SO . Podría usarse para seleccionar filas estrictamente únicas (relacionadas con #1163):

DT = setDT(structure(list(id = c(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 
2, 3, 4), dsp = c(5, 6, 7, 8, 6, 6, 7, 8, 5, 6, 9, 8, 5, 6, 7, 
NA), status = c(FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, 
TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE)), .Names = c("id", 
"dsp", "status"), row.names = c(NA, -16L), class = "data.frame"))

# my current way to select "strictly unique" rows
Bigdt[, .N, by=names(Bigdt)][N == 1][, N := NULL][]

# could be...
Bigdt[, .SD, by=names(Bigdt), having ={.N == 1L}]

Tenga en cuenta que Bigdt[, if (.N == 1L) .SD, by=names(Bigdt)] no funciona aquí, ya que .SD está vacío. Sin embargo, tal vez eso podría ser ayudado por # 1269 .


Y otro de SO: http://stackoverflow.com/q/38272608/ Quieren seleccionar grupos en función de las cosas en la última fila, por lo que having = condición de salud [.N] == "not healthy" debería hacerlo.


Y otro caso sencillo (filtrando por tamaño): http://stackoverflow.com/q/39085450/


Y otro , con un anti join:

ID <- c("A","A","A","B","B","C","D")
Value <- c(0,1,2,0,2,0,0)
df <- data.frame(ID,Value)

library(data.table)
setDT(df)

# use j = max() to get GForce speedup
df[ !df[, max(Value), by=ID][V1 > 0, .(ID, Value = 0)], on=.(ID, Value)]

# do the more standard thing, if j = if (...) x
df[ !df[, if (max(Value) > 0) .(Value = 0), by=ID], on=.(Value, ID) ]

# desired syntax
df[ !df[, .(Value = 0), by=ID, having = max(Value) > 0], on=.(Value, ID) ]

Sin embargo, no es un gran ejemplo.


Y otro con una respuesta como dt[, if(uniqueN(time)==1L) .SD, by=name, .SDcols="time"]


Y otro: http://stackoverflow.com/q/43354165/

Y otro: http://stackoverflow.com/q/43613087/

Otro (aunque podría eliminarse): http://stackoverflow.com/q/43635968/

Otro http://stackoverflow.com/a/43765352/

Otro http://chat.stackoverflow.com/transcript/message/37148860#37148860

Otro https://stackoverflow.com/questions/45464333/assign-a-binary-vector-based-on-blocks-of-data-within-another-vector/

Otro https://stackoverflow.com/questions/32259620/how-to-remove-unique-entry-and-keep-duplicates-in-r/32259758#32259758

Un autre https://stackoverflow.com/q/45557011/

Haiyou https://stackoverflow.com/questions/45598397/filter-data-frame-matching-all-values-of-a-vector

Um más https://stackoverflow.com/a/45721286/

lingwai yige https://stackoverflow.com/a/45820567/

y https://stackoverflow.com/q/46251221/

uno mas https://stackoverflow.com/questions/46307315/show-sequences-that-include-a-variable-in-r

también https://stackoverflow.com/q/46638058/


Y otro. Quiero dividir mi tabla de datos (myDT) en entradas que no se encuentran en una tabla de referencia (idDT):

library(data.table)
idDT = data.table(id = 1:3, v = c("A","B","C"))
myDT = data.table(id = 3:4, z = c("gah","egad"))

# my attempt
idDT[myDT, on=.(id), .SD[.N == 0L], by=.EACHI]
# Empty data.table (0 rows) of 2 cols: id,v

# workaround
myDT[, .SD[idDT[.SD, on=.(id), .N == 0, by=.EACHI]$V1]]

# desired notation (with having=)
myDT[, .SD, by = id, having = idDT[.BY, on=.(id), .N]==0L]

Sin embargo, esto sería ineficiente, ya que mi notación deseada implica que cada valor por = haga una unión separada a idDT. En ese sentido, quizás no sea el mejor ejemplo.


mais um https://stackoverflow.com/questions/47765283/r-data-table-group-by-where/47765308?noredirect=1#comment82524998_47765308 podría hacer DT[, if (any(status == "A") && !any(status == "B")) .SD, by=id] o con un parámetro que tiene DT[, .SD, by=id, having = any(status == "A") && !any(status == "B")]

y luego https://stackoverflow.com/a/48669032/ m[, if(isTRUE(any(passed))) .SD, by=id] debería ser m[by = id, having = isTRUE(any(passed))]

más un ejemplo https://stackoverflow.com/q/49072250/

ein anderer https://stackoverflow.com/a/49211292/ stock_profile[, sum(Value), by=Pcode, having=any(Location=="A" & NoSales == "Y")][, sum(V1)]

más um https://stackoverflow.com/a/49366998/

autre https://stackoverflow.com/a/49919015/

y https://stackoverflow.com/questions/50257643/deleting-rows-in-r-with-value-less-than-x

moar https://stackoverflow.com/q/54582048

y https://stackoverflow.com/q/56283005

mantenga los grupos si .N==k (también muchos en el objetivo duplicado )

mantener grupos si los hay (diff (sorted_col)) <= umbral https://stackoverflow.com/q/57512417

mantener si max(x) <umbral https://stackoverflow.com/a/57698641

Todos 28 comentarios

Gran FR. También he estado reflexionando sobre este caso de uso durante bastante tiempo. Podemos hacer esto sin el argumento adicional como este:

dt[, .SD[mean(var)>1], by=id]

(Pero para la velocidad, necesitará una optimización de .SD[.] internamente - #735).

Es muy probable que en este caso recurramos a .I en su lugar:

dt[dt[, .I[mean(var) > 1], by=id]$V1]

Y sería genial obtener esto directamente (incluso mejor si podemos lograrlo sin having ) - ¿quizás si la expresión j se evalúa como un vector lógico de 1 columna? Solo pensando en voz alta.

Hola Arun. Gracias por la respuesta. Una vez que la optimización de .SD esté disponible, esto sería solo una cuestión de "gusto" en términos de lo que es más claro para leer entre:

dt[, .SD[mean(var)>1], by=id]

y

dt[, .SD, by = id, having = mean(var) > 1]

Aunque el segundo también puede tener un mayor atractivo para las personas que vienen de otros idiomas (SQL en particular). Pero, de nuevo, esto podría ser sólo mi opinión. Tal vez solo usé SQL demasiado en el último período (lol).

En lo que respecta a la parte del sabor, realmente no me gusta agregar un parámetro adicional, cuando se puede lograr con una sintaxis simple y estándar (es decir, la primera opción anterior).

Curioso. Estaba seguro de que tú eras el que más apreciaría esto :-) (considerando lo mucho que querías eliminar by-without-by, principalmente para mejorar la legibilidad, especialmente para las personas que vienen de otros idiomas, si no recuerdo mal). De todos modos, sé que los dos son escenarios bastante diferentes. Solo quería compartir mi punto de vista,:

  • Estoy bastante seguro de que será más legible para cualquiera que no esté muy familiarizado con R (o solo data.table)
  • 15 vs 14 parámetros (actuales) de [.data.table realmente no dañan
  • No se verá obligado a usarlo y no romperá ningún código. Será una expresión que, si se proporciona, posiblemente omitirá la ejecución de j para un grupo en particular

Las razones por las que no me gustó el silencio por-sin-por y "tener" son en realidad las mismas: no me gusta recordar cosas adicionales, ya sean parámetros adicionales o comportamientos extra extraños.

Yo diría que la primera expresión que escribió es mucho más fácil de leer, porque no tiene que seguir leyendo la línea, luego descubrir que se especifica algún parámetro nuevo y tener que volver al principio de la oración y reevaluar su modelo mental de lo que está pasando.

¿Qué piensas de no agregar having arg a [ , sino convertirlo en la función having() y hacer que funcione en el argumento i , lo mismo que order() funciona, por ejemplo:

dt[ having(var > 1), .(var = mean(var)), by = id ]
# would perform below without additional copy:
dt[, .(var = mean(var)), by = id ][ var > 1 ]

having sería una función para evaluar su argumento en el marco de dt y proporcionar filtrado a i .

Creo que este FR está estrechamente relacionado con https://github.com/Rdatatable/data.table/issues/1269 "Returning only groups". A menudo quiero obtener grupos con algún atributo y almacenarlos en un vector, como my_teams en esta publicación SO . Aquí está la línea relevante:

my_teams <- FantasyTeams[, max(table(Team)) <= 3, by=team_no][(V1)]$team_no
# or 
my_teams <- FantasyTeams[, if ( max(table(Team)) <= 3 ) 1, by=team_no]$team_no

Con los FR having y "Solo grupos que regresan", esto podría ser algo como

my_teams <- FantasyTeams[, .(), by = team_no, having = { max(table(Team)) <= 3 }]$team_no

El código es igual de largo, pero lo prefiero, así que no tengo que leer j detenidamente para entender el objetivo.

Otro ejemplo de SO . El objetivo es sobrescribir la columna Value con 3L si se cumple alguna condición a nivel de grupo:

DT = setDT(structure(list(Ind = c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L), ID = c("A", 
"A", "A", "A", "B", "B", "B", "B"), RegionStart = c(1L, 101L, 
1L, 101L, 1L, 101L, 1L, 101L), RegionEnd = c(100L, 200L, 100L, 
200L, 100L, 200L, 100L, 200L), Value = c(3L, 2L, 3L, 2L, 3L, 
2L, 5L, 5L), TN = c("N", "N", "T", "T", "N", "N", "T", "T")), .Names = c("Ind", 
"ID", "RegionStart", "RegionEnd", "Value", "TN"), row.names = c(NA, 
-8L), class = "data.frame"))

# current syntax 
DT[, Value := { 
  fixit = ( Value[TN=="N"] != 3L ) & ( uniqueN(Value) == 1L )
  if (fixit) 3L else Value
}, by=.(ID, RegionStart)]

# with "having"
DT[,
  Value := 3L
, by=.(ID, RegionStart)
, having={ ( Value[TN=="N"] != 3L ) & ( n_distinct(Value) == 1L ) }]

Además de una sintaxis posiblemente más agradable, supongo que la forma having= también podría ser más eficiente, ya que solo es necesario modificar un subconjunto de subgrupos. La forma más eficiente sin having= probablemente parezca...

myeyes = DT[, .I[ ( Value[TN=="N"] != 3L ) & ( uniqueN(Value) == 1L )], by=.(ID, RegionStart)]$V1
DT[ myeyes, Value := 3L]

# or 

mygs = DT[, ( Value[TN=="N"] != 3L ) & ( uniqueN(Value) == 1L ), by=.(ID, RegionStart)][(V1)][, V1 := NULL]
DT[ mygs, Value := 3L, on=names(mygs)]

que son bastante enrevesados.

Editar : Y otro ejemplo para actualizar si/cuando esta función esté disponible: http://stackoverflow.com/q/36292702
(2016/4/26:) http://stackoverflow.com/q/36869784
(2016/06/16:) http://stackoverflow.com/q/37855013/

Otro ejemplo de SO . Podría usarse para seleccionar filas estrictamente únicas (relacionadas con #1163):

DT = setDT(structure(list(id = c(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 
2, 3, 4), dsp = c(5, 6, 7, 8, 6, 6, 7, 8, 5, 6, 9, 8, 5, 6, 7, 
NA), status = c(FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, 
TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE)), .Names = c("id", 
"dsp", "status"), row.names = c(NA, -16L), class = "data.frame"))

# my current way to select "strictly unique" rows
Bigdt[, .N, by=names(Bigdt)][N == 1][, N := NULL][]

# could be...
Bigdt[, .SD, by=names(Bigdt), having ={.N == 1L}]

Tenga en cuenta que Bigdt[, if (.N == 1L) .SD, by=names(Bigdt)] no funciona aquí, ya que .SD está vacío. Sin embargo, tal vez eso podría ser ayudado por # 1269 .


Y otro de SO: http://stackoverflow.com/q/38272608/ Quieren seleccionar grupos en función de las cosas en la última fila, por lo que having = condición de salud [.N] == "not healthy" debería hacerlo.


Y otro caso sencillo (filtrando por tamaño): http://stackoverflow.com/q/39085450/


Y otro , con un anti join:

ID <- c("A","A","A","B","B","C","D")
Value <- c(0,1,2,0,2,0,0)
df <- data.frame(ID,Value)

library(data.table)
setDT(df)

# use j = max() to get GForce speedup
df[ !df[, max(Value), by=ID][V1 > 0, .(ID, Value = 0)], on=.(ID, Value)]

# do the more standard thing, if j = if (...) x
df[ !df[, if (max(Value) > 0) .(Value = 0), by=ID], on=.(Value, ID) ]

# desired syntax
df[ !df[, .(Value = 0), by=ID, having = max(Value) > 0], on=.(Value, ID) ]

Sin embargo, no es un gran ejemplo.


Y otro con una respuesta como dt[, if(uniqueN(time)==1L) .SD, by=name, .SDcols="time"]


Y otro: http://stackoverflow.com/q/43354165/

Y otro: http://stackoverflow.com/q/43613087/

Otro (aunque podría eliminarse): http://stackoverflow.com/q/43635968/

Otro http://stackoverflow.com/a/43765352/

Otro http://chat.stackoverflow.com/transcript/message/37148860#37148860

Otro https://stackoverflow.com/questions/45464333/assign-a-binary-vector-based-on-blocks-of-data-within-another-vector/

Otro https://stackoverflow.com/questions/32259620/how-to-remove-unique-entry-and-keep-duplicates-in-r/32259758#32259758

Un autre https://stackoverflow.com/q/45557011/

Haiyou https://stackoverflow.com/questions/45598397/filter-data-frame-matching-all-values-of-a-vector

Um más https://stackoverflow.com/a/45721286/

lingwai yige https://stackoverflow.com/a/45820567/

y https://stackoverflow.com/q/46251221/

uno mas https://stackoverflow.com/questions/46307315/show-sequences-that-include-a-variable-in-r

también https://stackoverflow.com/q/46638058/


Y otro. Quiero dividir mi tabla de datos (myDT) en entradas que no se encuentran en una tabla de referencia (idDT):

library(data.table)
idDT = data.table(id = 1:3, v = c("A","B","C"))
myDT = data.table(id = 3:4, z = c("gah","egad"))

# my attempt
idDT[myDT, on=.(id), .SD[.N == 0L], by=.EACHI]
# Empty data.table (0 rows) of 2 cols: id,v

# workaround
myDT[, .SD[idDT[.SD, on=.(id), .N == 0, by=.EACHI]$V1]]

# desired notation (with having=)
myDT[, .SD, by = id, having = idDT[.BY, on=.(id), .N]==0L]

Sin embargo, esto sería ineficiente, ya que mi notación deseada implica que cada valor por = haga una unión separada a idDT. En ese sentido, quizás no sea el mejor ejemplo.


mais um https://stackoverflow.com/questions/47765283/r-data-table-group-by-where/47765308?noredirect=1#comment82524998_47765308 podría hacer DT[, if (any(status == "A") && !any(status == "B")) .SD, by=id] o con un parámetro que tiene DT[, .SD, by=id, having = any(status == "A") && !any(status == "B")]

y luego https://stackoverflow.com/a/48669032/ m[, if(isTRUE(any(passed))) .SD, by=id] debería ser m[by = id, having = isTRUE(any(passed))]

más un ejemplo https://stackoverflow.com/q/49072250/

ein anderer https://stackoverflow.com/a/49211292/ stock_profile[, sum(Value), by=Pcode, having=any(Location=="A" & NoSales == "Y")][, sum(V1)]

más um https://stackoverflow.com/a/49366998/

autre https://stackoverflow.com/a/49919015/

y https://stackoverflow.com/questions/50257643/deleting-rows-in-r-with-value-less-than-x

moar https://stackoverflow.com/q/54582048

y https://stackoverflow.com/q/56283005

mantenga los grupos si .N==k (también muchos en el objetivo duplicado )

mantener grupos si los hay (diff (sorted_col)) <= umbral https://stackoverflow.com/q/57512417

mantener si max(x) <umbral https://stackoverflow.com/a/57698641

@eantonya En mi humilde opinión, agregar el parámetro having hará que sea más fácil de recordar. La concisión excesiva puede ser difícil de memorizar. Además, hacer data.table más como SQL no es una mala idea.

En data.table Preguntas frecuentes:

2.16 He oído que la sintaxis de data.table es análoga a SQL.
Sí : ...

@ywhuofu data.table ya acepta la función order para el argumento i , que es lo que esperaría el usuario base de R. De la misma manera que traducimos _ORDER_ de sql a i = order(...) podemos hacerlo con _HAVING_. Encaja bien, ya que i en data.frame se usa para crear subconjuntos (_tener_ es solo un subconjunto retrasado después de la agregación) o reordenación.

¿Podría ser esta la API?

dt <- data.table(id   = rep(1:2, each = 2),
                 var  = c(0.2, 0.5, 1.5, 1.3))

dt[having.i(mean(var) > 1, by = id)]
  id var
1  2 1.5
2  2 1.3

He implementado esta versión aunque establece una restricción de usar solo funciones optimizadas gforce así como algunas funciones que no dependen de agrupaciones (por ejemplo, + , | , & , etc.). En SQL, las funciones de resumen son las que se usan, aunque lo entendería si Cdogroups quisiera ser compatible.

Una nota adicional. Parece que sería difícil encajar dt[having(var > 3), .(var = mean(x)), by = .(grp)] dentro del código actual '[.data.table' . Tendría que haber algunas comprobaciones para asegurarse de que la sintaxis sea correcta.
```
n = 1e6
grps = 1e5
cabeza_n = 2L
dt = data.table::data.table(x = muestra(grps, n, TRUE), y = runif(n))

Un tibble: 2 x 13

expresión min mediana

1 lw[tener.i(.N < 2L | sum(y) > 11 | mediana(y) < 0.7, by = x)] 114.13ms 124.98ms
2 dt[dt[, .I[.N < 2L | suma(y) > 11 | mediana(y) < 0.7], por = x]$V1] 4000ms 4000ms

Un tibble: 2 x 13

expresión min mediana itr/sec mem_alloc gc/sec n_itr

1 lw[tener.i(.N < 2L, por = x)] 30.2ms 35.3ms 27.9 8.02MB 3.99 14
2 dt[dt[, .I[.N < 2L], por = x]$V1] 106,1 ms 110,4 ms 8,81 6,13 MB 10,6 5

Preferiría esto como un parámetro agregado, denominado como having= o group_filter= (o algo más que no dependa de la conciencia de SQL para saber lo que hace a la vista).

por ejemplo, creo que sería confuso combinar filtros de fila en i con filtros de nivel de grupo también en i

¿Funcionaría having = en un subconjunto de los datos o solo podría usar el i o el argumento having ? También asumo que having ocurriría antes de que se evalúe j . ¿Cómo funcionarían .BY y .GRP y pronto .NGRP con ```have = ````?

No hay muchas opciones sintácticas:

  • Agregar un nuevo argumento como having
  • Aprovechando los argumentos existentes: i , j , by .

Si se necesitan tanto el filtro de fila como el filtro de grupo, dt[row_selector & group_selector, ...] no se ve bien, por lo tanto, parece que para tal caso de uso, el filtro de fila y el filtro de grupo no deberían aparecer en el mismo argumento. Entonces se descarta i .

Entonces no habrá muchas opciones sintácticas.

Aprovechar by podría hacer que parezca confuso. Por ejemplo,

dt[, .SD, by = having(.(id), mean(var > 1))]
dt[, .SD, by = id ~ mean(var) > 1]

Agregar una función especial a j no se ve bien.

dt[, having(mean(var) > 1, .SD), by = id]

Ahora, el código que me parece mejor es la versión más original

dt[, if (mean(var) > 1) .SD, by = id]
dt[, if (mean(var) > 1) .(x = sum(x), y = sum(y)), by = id]

Lo que realmente quiero es mantener la optimización realizada después del filtrado grupal. ¿Podemos detectar la expresión if en j y optimizarla, como hacer que GForce funcione dentro de la instrucción if?

@ renkun-ken ¿O sobrecargar otro operador infijo?

dt[, mean(var) > 1 ? .SD, by=id]

Una ventaja de un símbolo especial sobre if es que no hay posibilidad de que el usuario coloque un else correspondiente más adelante.

@franknarf1 Parece que mientras intentamos detectar if en j , también podríamos comprobar que if tiene else if y else . Podríamos optimizar if -solo caso y dejar if-else sin optimizar. Tal vez más tarde podamos manejar el caso if-else también. Personalmente, sigo prefiriendo optimizar el código a anular o aprovechar demasiado los operadores existentes.

@ franknarf1 esta es una sintaxis de C genial, aunque no estoy seguro de si no se complicaría demasiado aquí.
var > 1 ? d : e también podría funcionar, ¿no?

var > 1 ? d : e parece conciso, pero solo funciona para el caso simple en línea, ya que d y e podrían ser algo así como {...} y la precedencia del operador puede ser confusa. ¿Solo estamos tratando de permitir que .SD realice un filtrado de grupo puro, o cualquier expresión en j aquí?

Agregar sintaxis tiene el problema de que el usuario debe tener en cuenta que la sintaxis se maneja especialmente y no debería funcionar dentro j . Por ejemplo, el usuario puede esperar

dt[, mean(var) > 1 ? 0 : (sd(var) < 1 ? 1 : 0), by = id]

para trabajar, e incluso

dt[, mean(var) > 1 ? 0 : 1]
dt[, mean(var) > 1 ? 0 : (sd(var) < 1 ? 1 : 0)]

para trabajar en general.

Estoy un poco confundido aquí.

Lo hace

dt[, .SD, by = id, having = mean(var) > 1]

tener alguna ventaja sobre

dt[, if(mean(var) > 1) .SD, by = id]

ya que mean(var) > 1 siempre se evaluará para cada grupo. ¿Solo sirve como un azúcar sintáctico o estamos tratando de optimizar esto de alguna manera para tener un mayor rendimiento?

@jangorecki

@ franknarf1 esta es una sintaxis de C genial, aunque no estoy seguro de si no se complicaría demasiado aquí.
var > 1 ? d : e también podría funcionar, ¿no?

Sí, eso estaría genial. La precedencia del operador podría interponerse sin {} s como señaló @renkun-ken ( ex = quote(x & y ? a+b : v+w); str(rapply(as.list(ex), as.list, how="replace")) )

Estoy un poco confundido aquí.

Lo hace

dt[, .SD, by = id, having = mean(var) > 1]

tener alguna ventaja sobre

dt[, if(mean(var) > 1) .SD, by = id]

ya que siempre se evaluará mean(var) > 1 para cada grupo. ¿Solo sirve como un azúcar sintáctico o estamos tratando de optimizar esto de alguna manera para tener un mayor rendimiento?

Supongo que hasta ahora había preferido having= porque lo encuentro un poco más claro de leer e imagino que es más fácil de mantener en comparación con agregar más magia sintáctica a j . Por otro lado, creo que preferiría la sintaxis mágica j , ya que

  • Ya estoy acostumbrado a if () ... ; y me gusta la forma ? también si es factible.
  • Si está integrado en j , entonces no es necesario responder preguntas adicionales sobre su comportamiento (por ejemplo, DT[, x := if (cond) y, by=id] crea NA si la condición se cumple en algunos grupos pero no en otros y este comportamiento no debería t necesita ser explicado nuevamente por having= ).

Con respecto a la optimización, parece que hay muchos ejemplos en los que la condición de tener en sí misma podría beneficiarse de alguna versión de GForce, ya que generalmente es una expresión como max(x) > 0 , max(x) == 0 .

Para mi propio uso, además de la optimización, supongo que sería más útil para el caso de grupos de devolución solo mencionado anteriormente https://github.com/Rdatatable/data.table/issues/1269

> dt[, if (mean(var) > 1) .(), by=id] 
> # instead of ...
> dt[, mean(var) > 1, by=id][V1 == TRUE, !"V1"]
   id
1:  2

Buenos puntos Frank. además del enorme compendio de casos de uso que has
construido (¡gracias de nuevo por cierto!).

de hecho, puede ser más fácil hacer GForce en la versión being= ya que podemos
simplemente aplique la lógica gforce para tener similar a j en lugar de intentar hacer
NSE para lograr lo mismo.

aunque eso puede interactuar con el WIP de Jan para mover una gran cantidad de código j a C, cualquier
pensamientos hay Jan?

El sábado 15 de febrero de 2020 a la 1:40 p. m., Frank [email protected] escribió:

@jangorecki https://github.com/jangorecki

@franknarf1 https://github.com/franknarf1 esta es una sintaxis C genial,
aunque no estoy seguro si no se complicaría mucho aquí.
var > 1 ? d : Podría funcionar también, ¿no?

Sí, eso estaría genial. La precedencia del operador puede interferir sin
{}s como señaló @renkun-ken https://github.com/renkun-ken (ex =
cita(x & y ? a+b : v+w); str(rapply(como.lista(ex), como.lista, como="reemplazar"))
)

Estoy un poco confundido aquí.

Lo hace

dt[, .SD, por = id, teniendo = media(var) > 1]

tener alguna ventaja sobre

dt[, si(media(var) > 1) .SD, por = id]

ya que mean(var) > 1 siempre se evaluará para cada grupo. ¿Es solo
servir como un azúcar sintáctico o estamos tratando de optimizar esto de alguna manera
para tener un mayor rendimiento?

Supongo que hasta ahora hubiera preferido tener= porque lo encuentro un poco
más claro de leer e imaginar que es más fácil de mantener en comparación con agregar
más magia sintáctica a j. Por otro lado, creo que podría
en su lugar prefiero la magia de la sintaxis j, ya que

  • Estoy acostumbrado a si () ... ya; y como el? demasiado si es
    factible.
  • Si está integrado en j, entonces no es necesario hacer preguntas adicionales.
    respondió sobre su comportamiento (por ejemplo, DT[, x := if (cond) y, by=id] crea
    NA si la condición se cumple en algunos grupos pero no en otros y este comportamiento
    no debería ser necesario volver a explicar por tener =).

Con respecto a la optimización, parece que hay muchos ejemplos en los que
la condición de tener en sí podría beneficiarse de alguna versión de GForce,
ya que normalmente es una expresión como max(x) > 0, max(x) == 0.

Para mi propio uso, además de la optimización, supongo que sería principalmente
útil para el caso de grupos de retorno solo mencionado anteriormente # 1269
https://github.com/Rdatatable/data.table/issues/1269

dt[, si (media(var) > 1) .(), por=id]

en lugar de ...

dt[, media(var) > 1, por=id][V1 == VERDADERO, !"V1"]
identificación
1: 2


Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Rdatatable/data.table/issues/788?email_source=notifications&email_token=AB2BA5OCN4IW3N6QQJU6RJ3RC555BA5CNFSM4ATSQPMKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEL3CK7A#issue665comment-598
o darse de baja
https://github.com/notifications/unsubscribe-auth/AB2BA5MD7ZXWSRRHVEJM6C3RC555BANCNFSM4ATSQPMA
.

El código j que se moverá a C es el código responsable solo de la selección de columnas, por lo que debe adivinar el argumento with . No interferirá aquí.

Dado que FR es para agregar un parámetro 'tener'... , la palabra having debería estar en algún lugar de la solución. La optimización para operadores ternarios parece un tema aparte.

Mi preferencia por having.i() se debe al mantra de data.table: subconjunto/ordenar en i, seleccionar en j, agrupar en por. having es solo un caso especial de creación de subconjuntos.

Independientemente, si hay un nuevo argumento having , ¿la API admitiría un argumento $# i ? La mayoría de los casos de uso no parecen necesitar ese requisito.

¿Cuál debe ser el comportamiento de ordenar? Es decir, la mayoría de los enfoques actuales reordenan automáticamente:

library(data.table)

dt = data.table(grp = c(1L, 2L, 1L, 2L), x = letters[sample(4L)])
dt
#>      grp      x
#>    <int> <char>
#> 1:     1      a
#> 2:     2      b
#> 3:     1      c
#> 4:     2      d
dt[dt[, .I[.N > 0L], by = grp]$V1]
#>      grp      x
#>    <int> <char>
#> 1:     1      a
#> 2:     1      c
#> 3:     2      b
#> 4:     2      d

¿Debe having arg devolver un resultado que se reordena de acuerdo con by ?

¿Cuál debe ser el comportamiento de ordenar?
¿Debe having arg devolver un resultado que se reordena de acuerdo con by ?

@ColeMiller1 Fwiw, esperaría que having= solo apareciera cuando también aparece by= , por lo que los resultados se agruparían como en su ejemplo con ...$V1 .

Sí, esperaría que el orden fuera consistente:

DT[i, j, by, having]
# < == >
DT[i, if (having) j, by]

Creo que no hubo acuerdo sobre la API, particularmente sobre tener un nuevo argumento having en [ . @mattdowle ¿qué pasa?
El enfoque actual de usar DT[, if (.N > 1L) .SD, col1] es bueno, no es realmente complicado, fácil de extender, pero un poco más difícil de optimizar.
Mi idea era usar having como llamada de función en i : DT[having(N > 1L), .N, col1] , pero entonces no es posible proporcionar un subconjunto normal a i .
Alternativamente, el nuevo argumento podría ser un subargumento de by , no lo he pensado mucho, pero algo así como DT[, .N, by=.(col1, .having = N > 1L)] , por lo que el argumento adicional relacionado con la agrupación se encapsula en by argumento. Esta es la forma correcta de escalar el número de argumentos.

¿Fue útil esta página
0 / 5 - 0 calificaciones