Data.table: 向 `[.data.table` 添加一个“有”参数

创建于 2014-08-29  ·  28评论  ·  资料来源: Rdatatable/data.table

目前,要获得 SQL having子句的等效(或类似内容),您需要先使用by编写[.data.table #$,然后将结果输入i第二个[.data.tablei参数,例如:

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/questions/32259620/how-to-remove-unique-entry-and-keep-duplicates-in-r/32259758#32259758

独立https://stackoverflow.com/q/45557011/

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

嗯 mais https://stackoverflow.com/a/45721286/

凌外一哥https://stackoverflow.com/a/45820567/

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

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

坦贝姆https://stackoverflow.com/q/46638058/


还有一个。 我想将我的 data.table (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))]

mais um 示例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)]

mais um 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

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

如果 .N==k 保留组(也有很多在欺骗目标) https://stackoverflow.com/questions/56794306/only-get-data-table-groups-with-a-given-number-of-rows

如果有的话保留组(diff(sorted_col))<=阈值https://stackoverflow.com/q/57512417

如果 max(x) < 阈值则保持https://stackoverflow.com/a/57698641

所有28条评论

伟大的FR。 我也一直在思考这个用例。 我们可以在没有额外参数的情况下这样做:

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)的人来说,它会更具可读性
  • [.data.table的 15 对 14 (当前)参数并没有真正的伤害
  • 您不会被迫使用它,也不会破坏任何代码。 这将是一个表达式,如果提供,可能会跳过特定组的j执行

我不喜欢沉默的 by-without-by 和“have”的原因实际上是相同的——我不喜欢记住额外的东西,无论是额外的参数还是额外的奇怪行为。

我认为您写的第一个表达式更容易阅读,因为您不必继续阅读该行,然后发现指定了一些新参数,并且必须回到句子的开头并重新评估您的正在发生的事情的心理模型。

您如何看待不将having arg 添加到[ ,而是将其转换为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 “仅返回组”密切相关。 我经常想获取具有某些属性的组并将它们存储在一个向量中,例如这个 SO post中的my_teams 。 这是相关的行:

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

使用having和“仅返回组”FR,这可能类似于

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

代码一样长,但我更喜欢它,所以我不必仔细阅读j来理解目标。

SO的另一个例子。 如果某些按组级别的条件成立,目标是用3L覆盖Value列:

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=方式也可能更有效,因为只需要修改 by-groups 的一个子集。 没有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/questions/32259620/how-to-remove-unique-entry-and-keep-duplicates-in-r/32259758#32259758

独立https://stackoverflow.com/q/45557011/

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

嗯 mais https://stackoverflow.com/a/45721286/

凌外一哥https://stackoverflow.com/a/45820567/

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

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

坦贝姆https://stackoverflow.com/q/46638058/


还有一个。 我想将我的 data.table (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))]

mais um 示例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)]

mais um 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

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

如果 .N==k 保留组(也有很多在欺骗目标) https://stackoverflow.com/questions/56794306/only-get-data-table-groups-with-a-given-number-of-rows

如果有的话保留组(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参数,这是基本 R 用户所期望的。 我们可以用 _HAVING_ 将 sql _ORDER_ 转换为i = order(...)的相同方式。 它很合适,因为 data.frame 中的i用于子集(_have_ 只是聚合后的延迟子集)或重新排序。

这可能是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

一个附加说明。 似乎很难在当前的'[.data.table'代码中放入dt[having(var > 3), .(var = mean(x)), by = .(grp)] 。 需要进行一些检查以确保语法正确。
```
n = 1e6
grps = 1e5
head_n = 2L
dt = data.table::data.table(x = sample(grps, n, TRUE), y = runif(n))

小标题:2 x 13

表达式最小中位数

1 lw[have.i(.N < 2L | sum(y) > 11 | 中值(y) < 0.7, by = x)] 114.13ms 124.98ms
2 dt[dt[, .I[.N < 2L | 总和(y) > 11 | 中值(y) < 0.7], by = x]$V1] 4000ms 4000ms

小标题:2 x 13

表达式最小中位数itr/sec mem_alloc gc/sec n_itr

1 lw[have.i(.N < 2L, by = x)] 30.2ms 35.3ms 27.9 8.02MB 3.99 14
2 dt[dt[, .I[.N < 2L], by = x]$V1] 106.1ms 110.4ms 8.81 6.13MB 10.6 5

我更喜欢将其作为附加参数,命名为having=group_filter= (或其他不依赖 SQL 意识来知道它在视线中做什么的东西)。

例如,我认为将 i 中的行过滤器与 $#$3 i i中的组级过滤器结合起来会很混乱

having =会在数据子集上工作,还是只能使用i参数或having参数? 我还假设having会在j被评估之前发生。 .BY.GRP以及很快.NGRP将如何与 ```have = ``` 一起使用?

语法选择不多:

  • 添加一个新参数,例如having
  • 利用现有参数: ijby

如果同时需要行过滤器和组过滤器,则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]

我真正想要的是在组过滤之后保持优化。 我们是否可以检测 $#$ j $#$ 中的if表达式并对其进行优化,例如让 GForce 在 if 语句中工作?

@renkun-ken 或者重载另一个中缀运算符?

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

if相比,特殊符号的一个优点是用户不可能在以后输入匹配的else

@franknarf1似乎当我们试图在j中检测if $ 时,我们还可以检查ifelse ifelse 。 我们可以优化仅if的情况,而保留if-else未优化。 也许以后我们也可以处理if-else案子。 就我个人而言,我仍然更喜欢优化代码而不是过多地覆盖或利用现有的运算符。

@franknarf1这是很酷的 C 语法,虽然不确定这里是否不会太复杂。
var > 1 ? d : e也可以,不是吗?

var > 1 ? d : e看起来很简洁,但仅适用于内联简单案例,因为de可能是{...}之类的任何东西,并且运算符优先级可能会令人困惑。 我们只是试图允许.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")) ),如果没有{} s,运算符优先级可能会受到影响

我在这里有点困惑。

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) > 0max(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

尼斯点弗兰克。 除了您使用的大量用例
建成(再次感谢顺便说一句!)。

实际上,在 having= 版本中执行 GForce 可能更容易,因为我们可以
只需将 gforce 逻辑应用于与 j 类似而不是尝试做
NSE 来完成同样的任务。

虽然这可能会与 Jan 的 WIP 交互以将大量 j 代码移动到 C —— 任何
有想法吗?

2020 年 2 月 15 日星期六下午 1:40,Frank [email protected]写道:

@jangorecki https://github.com/jangorecki

@franknarf1 https://github.com/franknarf1这是很酷的 C 语法,
虽然不确定这里是否不会太复杂。
变量 > 1 ? d : e 也可以,不是吗?

是的,那会很酷。 运算符优先级可能会妨碍
{} 正如@renkun-ken https://github.com/renkun-ken指出的那样(例如 =
报价(x & y ? a+b : v+w); str(rapply(as.list(ex), as.list, how="replace"))
)

我在这里有点困惑。

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

有任何优势

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

因为将始终为每个组评估 mean(var) > 1。 难道只有
充当语法糖,或者我们正在尝试以某种方式对其进行优化
有更高的性能?

我想直到现在我更喜欢拥有=,因为我发现它有点
与添加相比,更易于阅读和想象它更容易维护
对 j 进一步的句法魔术。 另一方面,我想我可能
而是更喜欢 j 语法魔术,因为

  • 我已经习惯了 if () ...; 和喜欢? 如果是这样的话
    可行的。
  • 如果它集成在 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[, if (mean(var) > 1) .(), by=id]

代替 ...

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


您收到此消息是因为您发表了评论。
直接回复此邮件,在 GitHub 上查看
https://github.com/Rdatatable/data.table/issues/788?email_source=notifications&email_token=AB2BA5OCN4IW3N6QQJU6RJ3RC555BA5CNFSM4ATSQPMKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEL3CK7A#issuecomment-586556
或退订
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 arg 是否应该返回根据by重新排序的结果?

@ColeMiller1 Fwiw,我希望having=仅在by=也出现时出现,因此结果将与您的示例中的...$V1进行分组。

是的,我希望顺序是一致的:

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

我认为 API 没有达成一致,特别是在[中有新的having参数。 @mattdowle wdyt?
当前使用DT[, if (.N > 1L) .SD, col1]的方法很好,不是很复杂,易于扩展,但更难优化。
我的想法是在i中使用having作为函数调用: DT[having(N > 1L), .N, col1] ,但是不可能为i提供正常的子集。
或者,新的 arg 可以是by的子参数,没有太多考虑,但类似于DT[, .N, by=.(col1, .having = N > 1L)] ,因此额外的与分组相关的参数被封装到by争论。 这是增加参数数量的正确方法。

此页面是否有帮助?
0 / 5 - 0 等级