Data.table: добавить параметр «имеющий» в `[.data.table`

Созданный на 29 авг. 2014  ·  28Комментарии  ·  Источник: Rdatatable/data.table

В настоящее время, чтобы иметь эквивалент (или нечто подобное) предложению SQL having , вам нужно сначала написать [.data.table , используя by , а затем передать результат в i Параметр [.data.table , например:

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

Другой вариант - использовать условный оператор внутри j , очень мощный, я делаю все время, и пока нет ничего, что текущий синтаксис не позволял бы мне сделать. Однако я считаю, что наличие параметра having позволит писать гораздо более понятные и читаемые коды. Например, приведенное выше можно записать так:

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

Я предлагаю что-то вроде:

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

Идея состоит в том, чтобы иметь выражение, которое всегда возвращает логическое значение длины 1 , которое укажет, нужно ли вычислять j для текущей группы.

Спасибо,
Мишель

feature request

Самый полезный комментарий

Другой пример из SO . Его можно использовать для выбора строго уникальных строк (относится к #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}]

Обратите внимание, что Bigdt[, if (.N == 1L) .SD, by=names(Bigdt)] здесь не работает, так как .SD пусто. Возможно, этому может помочь #1269.


И еще один из SO: http://stackoverflow.com/q/38272608/ Они хотят выбирать группы на основе материала в последней строке, поэтому having = состояние здоровья [.N] == "not healthy" должно это делать.


И еще один простой случай (фильтрация по размеру): http://stackoverflow.com/q/39085450/


И еще один , с антиприсоединением:

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) ]

Впрочем, не такой уж и отличный пример.


И еще один с ответом вроде dt[, if(uniqueN(time)==1L) .SD, by=name, .SDcols="time"]


И еще: http://stackoverflow.com/q/43354165/

И еще: http://stackoverflow.com/q/43613087/

Другой (хотя он может быть удален): http://stackoverflow.com/q/43635968/

Другой http://stackoverflow.com/a/43765352/

Другой http://chat.stackoverflow.com/transcript/message/37148860#37148860

Другой https://stackoverflow.com/questions/45464333/assign-a-binary-vector-based-on-blocks-of-data-within-another-vector/

Другой

Другой https://stackoverflow.com/q/45557011/

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

Гм май https://stackoverflow.com/a/45721286/

лингвай иге https://stackoverflow.com/a/45820567/

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

уно мас https://stackoverflow.com/questions/46307315/show-sequences-that-include-a-variable-in-r

тамбем https://stackoverflow.com/q/46638058/


И другой. Я хочу подмножить мою таблицу данных (myDT) для записей, которых нет в справочной таблице (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]

Однако это было бы неэффективно, поскольку моя желаемая нотация влечет за собой каждое значение by=, создающее отдельное соединение с idDT. В этом смысле, возможно, это не лучший пример.


mais um https://stackoverflow.com/questions/47765283/r-data-table-group-by-where/47765308?noredirect=1#comment82524998_47765308 может сделать DT[, if (any(status == "A") && !any(status == "B")) .SD, by=id] или с параметром DT[, .SD, by=id, having = any(status == "A") && !any(status == "B")]

а затем https://stackoverflow.com/a/48669032/ m[, if(isTRUE(any(passed))) .SD, by=id] должно быть m[by = id, having = isTRUE(any(passed))]

лучший пример https://stackoverflow.com/q/49072250/

Эйн Андерер https://stackoverflow.com/a/49211292/ stock_profile[, sum(Value), by=Pcode, having=any(Location=="A" & NoSales == "Y")][, sum(V1)]

больше мм https://stackoverflow.com/a/49366998/

другой https://stackoverflow.com/a/49919015/

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

Моар https://stackoverflow.com/q/54582048

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

сохранить группы, если .N ==k (также много в цели обмана)

сохранить группы, если они есть (diff (sorted_col)) <= порог https://stackoverflow.com/q/57512417

сохранить, если max (x) < порог https://stackoverflow.com/a/57698641

Все 28 Комментарий

Отличный ФР. Я тоже долго размышлял над этим вариантом использования. Мы можем сделать это без дополнительного аргумента, например:

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

(Но для скорости потребуется внутренняя оптимизация .SD[.] — #735.)

Скорее всего, в этом случае мы прибегнем к .I вместо этого:

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

И было бы здорово получить это напрямую (даже лучше, если бы мы могли добиться этого без having ) - может быть, если выражение j оценивается как логический вектор с 1 столбцом? Просто мысли вслух.

Привет Арун. Спасибо за ответ. Как только будет доступна оптимизация .SD , это будет просто вопрос «вкуса» с точки зрения того, что понятнее читать между:

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

и

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

Несмотря на то, что второй может также быть более привлекательным для людей, пришедших с других языков (в частности, SQL). Но опять же, это может быть только мое мнение. Может быть, я просто слишком много использовал SQL в последнее время (смеется).

Что касается вкусовой части - мне очень не нравится добавлять дополнительный параметр, когда это можно сделать с помощью простого и стандартного синтаксиса (т.е. первый вариант выше).

Любопытный. Я был уверен, что именно вы, скорее всего, это оцените :-) (учитывая, как сильно вы хотели исключить by-without-by, главным образом для улучшения читаемости, особенно для людей, пришедших с других языков, если я правильно помню). Во всяком случае, я знаю, что это два совершенно разных сценария. Я просто хотел поделиться своей точкой зрения:

  • Я почти уверен, что это будет более читабельно для тех, кто не очень хорошо знаком с R (или просто data.table)
  • 15 против 14 (текущих) параметров [.data.table особо не вредят
  • Вас не заставят использовать его, и он не сломает код. Это будет выражение, которое, если оно предоставлено, возможно, пропустит выполнение j для конкретной группы.

Причины, по которым мне не нравились молчание by-without-by и «иметь», на самом деле одни и те же — я не люблю запоминать лишнее, будь то дополнительные параметры или дополнительное странное поведение.

Я бы сказал, что первое выражение, которое вы написали, намного легче читать, потому что вам не нужно продолжать читать строку, а затем обнаруживать, что указан какой-то новый параметр, и вам нужно вернуться к началу предложения и переоценить ваш ментальная модель происходящего.

Что вы думаете о том, чтобы не добавлять аргумент having к [ , а превратить его в функцию having() и заставить его работать с аргументом i , так же, как order() работает, например:

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

having будет функцией для оценки аргумента в кадре dt и обеспечения фильтрации для i .

Я думаю, что этот FR тесно связан с https://github.com/Rdatatable/data.table/issues/1269 «Возврат только групп». Я часто хочу получить группы с некоторым атрибутом и сохранить их в векторе, например my_teams в этом посте SO . Вот соответствующая строка:

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

С FR having и «Возврат только групп» это может быть что-то вроде

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

Код такой же длинный, но я предпочитаю его, поэтому мне не нужно внимательно читать j , чтобы понять цель.

Другой пример из SO . Цель состоит в том, чтобы перезаписать столбец Value столбцом 3L , если выполняется какое-либо условие на уровне группы:

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 ) }]

Помимо, возможно, более приятного синтаксиса, я предполагаю, что способ having= также может быть более эффективным, поскольку необходимо изменить только подмножество групп по группам. Самый эффективный способ без having= наверное выглядит так...

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)]

которые довольно запутаны.

Изменить : И еще один пример для обновления, если/когда эта функция доступна: http://stackoverflow.com/q/36292702
(2016/4/26:) http://stackoverflow.com/q/36869784
(2016/06/16:) http://stackoverflow.com/q/37855013/

Другой пример из SO . Его можно использовать для выбора строго уникальных строк (относится к #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}]

Обратите внимание, что Bigdt[, if (.N == 1L) .SD, by=names(Bigdt)] здесь не работает, так как .SD пусто. Возможно, этому может помочь #1269.


И еще один из SO: http://stackoverflow.com/q/38272608/ Они хотят выбирать группы на основе материала в последней строке, поэтому having = состояние здоровья [.N] == "not healthy" должно это делать.


И еще один простой случай (фильтрация по размеру): http://stackoverflow.com/q/39085450/


И еще один , с антиприсоединением:

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) ]

Впрочем, не такой уж и отличный пример.


И еще один с ответом вроде dt[, if(uniqueN(time)==1L) .SD, by=name, .SDcols="time"]


И еще: http://stackoverflow.com/q/43354165/

И еще: http://stackoverflow.com/q/43613087/

Другой (хотя он может быть удален): http://stackoverflow.com/q/43635968/

Другой http://stackoverflow.com/a/43765352/

Другой http://chat.stackoverflow.com/transcript/message/37148860#37148860

Другой https://stackoverflow.com/questions/45464333/assign-a-binary-vector-based-on-blocks-of-data-within-another-vector/

Другой

Другой https://stackoverflow.com/q/45557011/

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

Гм май https://stackoverflow.com/a/45721286/

лингвай иге https://stackoverflow.com/a/45820567/

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

уно мас https://stackoverflow.com/questions/46307315/show-sequences-that-include-a-variable-in-r

тамбем https://stackoverflow.com/q/46638058/


И другой. Я хочу подмножить мою таблицу данных (myDT) для записей, которых нет в справочной таблице (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]

Однако это было бы неэффективно, поскольку моя желаемая нотация влечет за собой каждое значение by=, создающее отдельное соединение с idDT. В этом смысле, возможно, это не лучший пример.


mais um https://stackoverflow.com/questions/47765283/r-data-table-group-by-where/47765308?noredirect=1#comment82524998_47765308 может сделать DT[, if (any(status == "A") && !any(status == "B")) .SD, by=id] или с параметром DT[, .SD, by=id, having = any(status == "A") && !any(status == "B")]

а затем https://stackoverflow.com/a/48669032/ m[, if(isTRUE(any(passed))) .SD, by=id] должно быть m[by = id, having = isTRUE(any(passed))]

лучший пример https://stackoverflow.com/q/49072250/

Эйн Андерер https://stackoverflow.com/a/49211292/ stock_profile[, sum(Value), by=Pcode, having=any(Location=="A" & NoSales == "Y")][, sum(V1)]

больше мм https://stackoverflow.com/a/49366998/

другой https://stackoverflow.com/a/49919015/

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

Моар https://stackoverflow.com/q/54582048

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

сохранить группы, если .N ==k (также много в цели обмана)

сохранить группы, если они есть (diff (sorted_col)) <= порог https://stackoverflow.com/q/57512417

сохранить, если max (x) < порог https://stackoverflow.com/a/57698641

@eantonya ИМХО, добавление параметра having действительно облегчит запоминание. Чрезмерная краткость может быть трудной для запоминания. Более того, сделать data.table более похожим на SQL — неплохая идея.

В разделе часто задаваемых вопросов data.table :

2.16 Я слышал, что синтаксис data.table аналогичен SQL.
Да : ...

@ywhuofu data.table уже принимает функцию $# order i в качестве аргумента i, чего и ожидает пользователь базы R. Точно так же, как мы переводим sql _ORDER_ в i = order(...) , мы можем сделать с _HAVING_. Это хорошо подходит, так как i в data.frame используется для подмножества (_having_ — это просто отложенное подмножество после агрегации) или переупорядочивания.

Может это 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

Я реализовал эту версию, хотя она устанавливает ограничение на использование только оптимизированных функций gforce , а также некоторых функций, которые не зависят от группировок (например, + , | , & и т. д.). В SQL используются сводные функции, хотя я бы понял, если бы Cdogroups захотелось поддерживать.

Одно дополнительное замечание. Кажется, что dt[having(var > 3), .(var = mean(x)), by = .(grp)] будет трудно вписать в текущий код '[.data.table' . Потребуются некоторые проверки, чтобы убедиться, что синтаксис правильный.
```
п = 1e6
гпс = 1e5
голова_n = 2L
dt = data.table::data.table (x = образец (группы, n, ИСТИНА), y = runif (n))

Тиббл: 2 х 13

выражение мин медиана

1 lw[имея.i(.N < 2L | сумма (y) > 11 | медиана (y) < 0,7, by = x)] 114,13 мс 124,98 мс
2 dt[dt[, .I[.N < 2L | сумма(у) > 11 | медиана(y) < 0,7], by = x]$V1] 4000 мс 4000 мс

Тиббл: 2 х 13

выражение минимальная медиана itr/sec mem_alloc gc/sec n_itr

1 lw[имея.i(.N < 2L, by = x)] 30,2 мс 35,3 мс 27,9 8,02 МБ 3,99 14
2 dt[dt[, .I[.N < 2L], by = x]$V1] 106,1 мс 110,4 мс 8,81 6,13 МБ 10,6 5

Я бы предпочел, чтобы это был добавленный параметр с именем having= или group_filter= (или что-то еще, что не зависит от знания SQL, чтобы знать, что он делает).

например, я думаю, что было бы запутанно объединять фильтры строк в i с фильтрами на уровне группы также в i

Будет ли having = работать с подмножеством данных или вы сможете использовать только аргумент i или аргумент having ? Я также предполагаю, что having произойдет до оценки j . Как .BY и .GRP , а вскоре и .NGRP будут работать с ```having = ````?

Синтаксических вариантов не так много:

  • Добавление нового аргумента, такого как having
  • Использование существующих аргументов: i , j , by .

Если необходимы и фильтр строк, и групповой фильтр, dt[row_selector & group_selector, ...] выглядит неправильно, поэтому кажется, что в таком случае фильтр строк и групповой фильтр не должны появляться в одном и том же аргументе. Тогда i исключается.

Тогда не будет много вариантов синтаксиса.

Использование by может привести к путанице. Например,

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

Добавление специальной функции к j выглядит не очень хорошо.

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

Теперь код, который мне кажется лучше всего, является самой оригинальной версией.

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

Чего я действительно хочу, так это сохранить оптимизацию после групповой фильтрации. Можем ли мы обнаружить выражение if в j и оптимизировать его, например, сохранить работу GForce внутри оператора if?

@renkun-ken Или перегрузить другой инфиксный оператор?

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

Одним из преимуществ специального символа перед if является то, что пользователь не может поставить соответствующий символ else позже.

@franknarf1 Кажется, что пока мы пытаемся обнаружить if в j , мы также можем проверить, что if имеет else if и else . Мы могли бы оптимизировать только случай if и оставить if-else неоптимизированным. Возможно, позже мы сможем справиться и с делом if-else . Лично я по-прежнему предпочитаю оптимизировать код переопределению или чрезмерному использованию существующих операторов.

@ franknarf1 , это классный синтаксис C, хотя не уверен, что здесь это не сильно усложнит.
var > 1 ? d : e тоже может работать, не так ли?

var > 1 ? d : e выглядит лаконично, но работает только для встроенного простого случая, поскольку d и e могут быть чем-то вроде {...} , а приоритет операций может сбивать с толку. Мы только пытаемся разрешить .SD выполнять чистую групповую фильтрацию или любое выражение в j здесь?

Добавление синтаксиса имеет проблему, которую пользователь должен знать, что синтаксис обрабатывается особым образом и не должен работать внутри j . Например, пользователь может ожидать

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

работать и даже

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

вообще работать.

Я немного смущен здесь.

Делает

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

иметь какое-либо преимущество перед

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

поскольку mean(var) > 1 всегда будет оцениваться для каждой группы. Служит ли он только синтаксическим сахаром, или мы пытаемся как-то его оптимизировать, чтобы повысить производительность?

@jangorecki

@ franknarf1 , это классный синтаксис C, хотя не уверен, что здесь это не сильно усложнит.
var > 1 ? d : e тоже может работать, не так ли?

Да, это было бы круто. Приоритет оператора может мешать без {} , как указал @renkun-ken ( ex = quote(x & y ? a+b : v+w); str(rapply(as.list(ex), as.list, how="replace")) )

Я немного смущен здесь.

Делает

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

иметь какое-либо преимущество перед

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

поскольку mean(var) > 1 всегда будет оцениваться для каждой группы. Служит ли он только синтаксическим сахаром, или мы пытаемся как-то его оптимизировать, чтобы повысить производительность?

Я думаю, до сих пор я предпочитал having= , потому что я нахожу его немного более понятным для чтения и представляю, что его легче поддерживать по сравнению с добавлением дополнительной синтаксической магии в j . С другой стороны, я думаю, что мог бы вместо этого предпочесть синтаксическую магию j , поскольку

  • Я уже привык к if () ... ; и как способ ? также, если это осуществимо.
  • Если он интегрирован в j , то не нужно отвечать на дополнительные вопросы о его поведении (например, DT[, x := if (cond) y, by=id] создает NA, если условие выполняется в одних группах, но не в других, и такое поведение не должно t нужно заново объяснять для having= ).

Что касается оптимизации, похоже, есть много примеров, когда само условие наличия могло бы выиграть от какой-либо версии GForce, поскольку обычно это выражение вроде max(x) > 0 , max(x) == 0 .

Для моего собственного использования, помимо оптимизации, я думаю, это было бы в основном полезно для случая групп только для возврата, упомянутого выше 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

Хорошие моменты Фрэнк. в дополнение к огромному сборнику вариантов использования, которые вы
построен (еще раз спасибо!).

на самом деле может быть проще использовать GForce в версии have=, так как мы можем
просто примените логику gforce к тому, чтобы иметь аналог j, а не пытаться сделать
NSE, чтобы сделать то же самое.

хотя это может взаимодействовать с WIP Яна по перемещению большого количества j-кода на C - любой
мысли есть Ян?

В субботу, 15 февраля 2020 г., 13:40. Фрэнк уведомления@github.com написал:

@jangorecki https://github.com/jangorecki

@franknarf1 https://github.com/franknarf1 это классный синтаксис C,
хотя не уверен, что это не сильно усложнит здесь.
переменная > 1? d : e тоже может работать, не так ли?

Да, это было бы круто. Приоритет оператора может мешать без
{}, как указал @renkun-ken https://github.com/renkun-ken (ex =
цитата (x & y ? a+b : v+w); str(rapply(as.list(ex), as.list, как="заменить"))
)

Я немного смущен здесь.

Делает

dt[, .SD, by = id, имея = mean(var) > 1]

иметь какое-либо преимущество перед

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

поскольку среднее (var) > 1 всегда будет оцениваться для каждой группы. Это только
служить синтаксическим сахаром, или мы пытаемся как-то оптимизировать это
иметь более высокую производительность?

Я думаю, до сих пор я предпочитал иметь =, потому что я нахожу это немного
яснее читать и представлять, что его легче поддерживать по сравнению с добавлением
дальнейшая синтаксическая магия к j. С другой стороны, я думаю, что мог бы
вместо этого предпочитайте магию синтаксиса j, так как

  • Я привык, если () ... уже; и нравится? тоже, если это
    достижимый.
  • Если он интегрирован в j, то никаких дополнительных вопросов задавать не нужно.
    ответили о его поведении (например, DT[, x := if (cond) y, by=id] создает
    NAs, если условие выполняется в одних группах, но не в других, и такое поведение
    не нужно повторно объяснять наличие =).

Что касается оптимизации, похоже, есть много примеров, когда
само условие наличия может выиграть от какой-либо версии GForce,
поскольку обычно это выражение типа max(x) > 0, max(x) == 0.

Для моего собственного использования, помимо оптимизации, я думаю, это было бы в основном
полезно для случая групп только для возврата, упомянутого выше # 1269
https://github.com/Rdatatable/data.table/issues/1269

dt[, если (среднее(var) > 1).(), by=id]

вместо ...

dt[, mean(var) > 1, by=id][V1 == TRUE, !"V1"]
я бы
1:2


Вы получаете это, потому что вы прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/Rdatatable/data.table/issues/788?email_source=notifications&email_token=AB2BA5OCN4IW3N6QQJU6RJ3RC555BA5CNFSM4ATSQPMKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEL3CK7A#issuecomment
или отписаться
https://github.com/notifications/unsubscribe-auth/AB2BA5MD7ZXWSRRHVEJM6C3RC555BANCNFSM4ATSQPMA
.

j-код, который нужно переместить в C, — это код, который отвечает только за выбор столбца, поэтому угадывание аргумента with . Не буду здесь мешать.

Поскольку FR предназначен для добавления параметра "имеющий"... , слово having должно быть где-то в решении. Оптимизация для тернарных операторов кажется отдельной проблемой.

Я предпочитаю having.i() из-за мантры data.table: подмножество/порядок в i, выбор в j, группировка по. having — это всего лишь частный случай подмножества.

В любом случае, если есть новый аргумент having , будет ли API поддерживать аргумент $# i ? Большинство вариантов использования, похоже, не нуждаются в этом требовании.

Каким должно быть поведение при заказе? То есть большинство текущих подходов автоматически меняют порядок:

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

Должен ли аргумент having возвращать результат, переупорядоченный в соответствии с by ?

Каким должно быть поведение при заказе?
Должен ли аргумент having возвращать результат, переупорядоченный в соответствии с by ?

@ColeMiller1 Между прочим, я ожидаю, что having= появится только тогда, когда также появится by= , поэтому результаты будут сгруппированы, как в вашем примере с ...$V1 .

Да, я ожидаю, что порядок будет последовательным:

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

Я думаю, что не было соглашения об API, особенно о новом аргументе having в [ . @mattdowle wdyt?
Текущий подход к использованию DT[, if (.N > 1L) .SD, col1] хорош, не очень сложен, легко расширяется, но его немного сложнее оптимизировать.
Моя идея состояла в том, чтобы использовать having как вызов функции в i : DT[having(N > 1L), .N, col1] , но тогда невозможно обеспечить нормальное подмножество для i .
В качестве альтернативы новый аргумент может быть подаргументом by , не особо задумывался об этом, но что-то вроде DT[, .N, by=.(col1, .having = N > 1L)] , поэтому дополнительный аргумент, связанный с группировкой, инкапсулирован в by аргумент. Это правильный способ увеличить количество аргументов.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги