- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
概述
我对 data.table
比较熟悉,对 dplyr
不太熟悉。我已经阅读了一些 dplyr
vignettes 和出现在 SO 上的例子,到目前为止我的结论是:
data.table
和 dplyr
在速度上是相当的,除非有很多(即 >10-100K)组,以及在其他一些情况下(参见下面的基准测试)1314239dplyr
有更易访问的语法 dplyr
抽象(或将)潜在的数据库交互 data.table
相当熟悉,但我知道对于这两个新用户来说,这将是一个重要因素。我想避免争论哪个更直观,因为这与我从已经熟悉
data.table
的人的角度提出的具体问题无关。我也想避免讨论“更直观”如何导致更快的分析(当然是真的,但同样,这不是我在这里最感兴趣的)。
dplyr
会提供超出我在
data.table
中已经可以做的更多。这是
dplyr
解决方案(Q 末尾的数据):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
data.table
解决方案的 hack 尝试要好得多。也就是说,好的
data.table
解决方案也非常好(感谢 Jean-Robert、Arun,并在此注意我更喜欢单一语句而不是严格的最佳解决方案):
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
data.table
(即不使用一些更深奥的技巧),它实际上非常简单。
dplyr
或
data.table
方式更简洁或性能更好。
dplyr
不允许分组返回行(任意数量从 eddi's question ,注意操作:这看起来将在 dplyr 0.5 ,也@beginneR显示在回答用do
潜在的变通@实现eddi 的问题)。 data.table
支撑 rolling joins (感谢@dholstius)以及 overlap joins data.table
内部优化了 DT[col == value]
或 DT[col %in% values]
形式的表达式,以通过使用二进制搜索的自动索引来提高速度,同时使用相同的基本 R 语法。 See here 了解更多细节和一个小基准。 dplyr
提供的功能标准评估版本(例如regroup
,summarize_each_
),可以简化程序中使用的dplyr
(注意程序中使用的data.table
是绝对有可能,只是需要一些认真思考,置换/报价,等等,至少据我所知) data.table
变得基本上快除外。 data.table
鳞比dplyr
更好,因为群体数量的增加(更新在两个包的最新增强和R最近的版本)。此外,尝试获得 unique values 时的基准测试速度快 data.table
~6x。 data.table
75%/应用/排序而dplyr
是在较小的( another SO question from comments ,由于达纳斯)快40%。 data.table
的主要作者,有 benchmarked grouping operations on data.table
, dplyr
and python pandas
on up to 2 billion rows (~100GB in RAM) 。 data.table
~823 快 823 10 4 0dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
最佳答案
我们至少需要涵盖这些方面以提供全面的答案/比较(没有特别的重要性顺序): Speed
、 Memory usage
、 Syntax
和 0x251812221313
我的目的是从 data.table 的角度尽可能清楚地涵盖每一个。
Note: unless explicitly mentioned otherwise, by referring to dplyr, we refer to dplyr's data.frame interface whose internals are in C++ using Rcpp.
Features
。将
DT[i, j, by]
、
i
和
j
保持在一起是设计使然。通过将相关操作放在一起,它可以轻松优化操作的速度,更重要的是内存使用,还提供一些强大的功能,同时保持语法的一致性。
by
。另见
updated benchmarks ,其中包括
pandas
和
Spark
。
pydatatable
类型操作。DT[x > val, sum(y), by = z]
或 filter()
的操作可能是内存效率低下的(在 data.frames 和 data.tables 上)。 See this post。Note that Hadley's comment talks about speed (that dplyr is plentiful fast for him), whereas the major concern here is memory.
# sub-assign by reference, updates 'y' in-place
DT[x >= 1L, y := NA]
但是 dplyr 永远不会通过引用更新。 dplyr 等价物将是(请注意,结果需要重新分配): # copies the entire 'y' column
ans <- DF %>% mutate(y = replace(y, which(x >= 1L), NA))
对此的一个关注是 referential transparency 。通过引用更新 data.table 对象,尤其是在函数内可能并不总是可取的。但这是一个非常有用的功能:有关有趣的案例,请参见 this 和 this 帖子。我们想保留它。slice()
函数,这将为用户提供两种可能性。例如,如果不想修改函数内的输入 data.table,则可以执行以下操作: foo <- function(DT) {
DT = shallow(DT) ## shallow copy DT
DT[, newcol := 1L] ## does not affect the original DT
DT[x > 2L, newcol := 2L] ## no need to copy (internally), as this column exists only in shallow copied DT
DT[x > 2L, x := 3L] ## have to copy (like base R / dplyr does always); otherwise original DT will
## also get modified.
}
通过不使用 shallow()
,旧功能被保留: bar <- function(DT) {
DT[, newcol := 1L] ## old behaviour, original DT gets updated by reference
DT[x > 2L, x := 3L] ## old behaviour, update column x in original DT.
}
通过使用 shallow()
创建浅拷贝,我们了解到您不想修改原始对象。我们在内部处理所有事情,以确保同时确保仅在绝对必要时复制您修改的列。实现后,这应该完全解决引用透明度问题,同时为用户提供两种可能性。Also, once
shallow()
is exported dplyr's data.table interface should avoid almost all copies. So those who prefer dplyr's syntax can use it with data.tables.
But it will still lack many features that data.table provides, including (sub)-assignment by reference.
DT1 = data.table(x=c(1,1,1,1,2,2,2,2), y=c("a", "a", "b", "b"), z=1:8, key=c("x", "y"))
# x y z
# 1: 1 a 1
# 2: 1 a 2
# 3: 1 b 3
# 4: 1 b 4
# 5: 2 a 5
# 6: 2 a 6
# 7: 2 b 7
# 8: 2 b 8
DT2 = data.table(x=1:2, y=c("a", "b"), mul=4:3, key=c("x", "y"))
# x y mul
# 1: 1 a 4
# 2: 2 b 3
并且您想在 shallow()
中的每一行中获得 sum(z) * mul
,同时按列 DT2
加入。我们可以:x,y
得到 DT1
,2)执行连接和 3)乘(或)sum(z)
功能):by = .EACHI
,我们想要执行的操作就很清楚了。j
的详细说明。没有中间结果被具体化,join+aggregate 是一次性执行的。
by = .EACHI
中,您必须使用
join and aggregate or aggregate first and then join ,就内存而言(这反过来又转化为速度),这两种方法都没有效率。
DT1[DT2, col := i.mul]
添加/更新 dplyr
的列 DT1
与 col
来自 mul
的那些行,其中 0x251813121313141313131313131313131413143 列匹配。我认为 DT2
中没有与此操作完全等效的操作,即,在不避免 DT2
操作的情况下,它必须复制整个 DT1
只是为了向其中添加一个新列,这是不必要的。To summarise, it is important to realise that every bit of optimisation matters. As Grace Hopper would say, Mind your nanoseconds!
Data tables are extremely fast but I think their concision makes it harder to learn and code that uses it is harder to read after you have written it ...
DT = data.table(x=1:10, y=11:20, z=rep(1:2, each=5))
DF = as.data.frame(DT)
# case (a)
DT[, sum(y), by = z] ## data.table syntax
DF %>% group_by(z) %>% summarise(sum(y)) ## dplyr syntax
DT[, y := cumsum(y), by = z]
ans <- DF %>% group_by(z) %>% mutate(y = cumsum(y))
# case (b)
DT[x > 2, sum(y), by = z]
DF %>% filter(x>2) %>% group_by(z) %>% summarise(sum(y))
DT[x > 2, y := cumsum(y), by = z]
ans <- DF %>% group_by(z) %>% mutate(y = replace(y, which(x > 2), cumsum(y)))
# case (c)
DT[, if(any(x > 5L)) y[1L]-y[2L] else y[2L], by = z]
DF %>% group_by(z) %>% summarise(if (any(x > 5L)) y[1L] - y[2L] else y[2L])
DT[, if(any(x > 5L)) y[1L] - y[2L], by = z]
DF %>% group_by(z) %>% filter(any(x > 5L)) %>% summarise(y[1L] - y[2L])
dplyr
。但是在更新时,我们不得不将逻辑移到 *_join
中。然而,在 data.table 中,我们用相同的逻辑表达两个操作 - 对 DT1
的行进行操作,但在第一种情况下,得到 filter()
,而在第二种情况下,用其累积和更新这些行的 mutate()
。x > 2
形式一致时的意思。sum(y)
条件时,我们能够在 data.table 和 dplyr 中“按原样”表达逻辑。但是,如果我们只想返回满足 y
条件的那些行,否则就跳过,我们不能直接使用 DT[i, j, by]
(AFAICT)。我们必须先 if-else
然后总结,因为 if
总是期望一个值。summarise()
会使实际操作不那么明显。filter()
(对我来说似乎并不明显),但我的观点是我们不应该这样做。 # case (a)
DT[, lapply(.SD, sum), by = z] ## data.table syntax
DF %>% group_by(z) %>% summarise_each(funs(sum)) ## dplyr syntax
DT[, (cols) := lapply(.SD, sum), by = z]
ans <- DF %>% group_by(z) %>% mutate_each(funs(sum))
# case (b)
DT[, c(lapply(.SD, sum), lapply(.SD, mean)), by = z]
DF %>% group_by(z) %>% summarise_each(funs(sum, mean))
# case (c)
DT[, c(.N, lapply(.SD, sum)), by = z]
DF %>% group_by(z) %>% summarise_each(funs(n(), mean))
summarise()
,而 filter()
引入了 filter()
和一堆函数到 lapply()
。dplyr
需要提供列名,而 dplyr 会自动生成它。*_each()
的列数,而不是一次。在 data.table 中,我们需要做的就是返回 funs()
中的列表。列表的每个元素都将成为结果中的一列。因此,我们可以再次使用熟悉的基函数 :=
将 n()
连接到 j
,后者返回 c()
。Note: Once again, in data.table, all we need to do is return a list in
j
. Each element of the list will become a column in result. You can usec()
,as.list()
,lapply()
,list()
etc... base functions to accomplish this, without having to learn any new functions.
You will need to learn just the special variables -
.N
and.SD
at least. The equivalent in dplyr aren()
and.
.N
(并有理由)进行连接。它还提供等效的 list
函数作为替代。 setkey(DT1, x, y)
# 1. normal join
DT1[DT2] ## data.table syntax
left_join(DT2, DT1) ## dplyr syntax
# 2. select columns while join
DT1[DT2, .(z, i.mul)]
left_join(select(DT2, x, y, mul), select(DT1, x, y, z))
# 3. aggregate while join
DT1[DT2, .(sum(z) * i.mul), by = .EACHI]
DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>%
inner_join(DF2) %>% mutate(z = z*mul) %>% select(-mul)
# 4. update while join
DT1[DT2, z := cumsum(z) * i.mul, by = .EACHI]
??
# 5. rolling join
DT1[DT2, roll = -Inf]
??
# 6. other arguments to control output
DT1[DT2, mult = "first"]
??
list
或 DT[i, j, by]
类似于 base R.merge.data.table()
才能加入,如上所示。否则,您会使用不必要的列来实现连接,只是为了稍后删除它们,这是低效的。DT[i, j, by]
特性 (3) 并在加入时更新 (4)。为什么将整个连接结果物化为仅添加/更新几列?merge()
参数,它选择第一个、最后一个或所有匹配项 (6)。select()
参数来防止意外的无效连接。Once again, the syntax is consistent with
DT[i, j, by]
with additional arguments allowing for controlling the output further.
by = .EACHI
...mult =
。您必须事先了解所有函数的返回值。 DT[, list(x[1], y[1]), by = z] ## data.table syntax
DF %>% group_by(z) %>% summarise(x[1], y[1]) ## dplyr syntax
DT[, list(x[1:2], y[1]), by = z]
DF %>% group_by(z) %>% do(data.frame(.$x[1:2], .$y[1]))
DT[, quantile(x, 0.25), by = z]
DF %>% group_by(z) %>% summarise(quantile(x, 0.25))
DT[, quantile(x, c(0.25, 0.75)), by = z]
DF %>% group_by(z) %>% do(data.frame(quantile(.$x, c(0.25, 0.75))))
DT[, as.list(summary(x)), by = z]
DF %>% group_by(z) %>% do(data.frame(as.list(summary(.$x))))
allow.cartesian = TRUE
的等价物是 do()
do()
中抛出任何内容 - 唯一要记住的是它返回一个列表,以便列表中的每个元素都转换为一列。.SD
,具体取决于您对函数是否始终返回单个值的确定程度。而且速度很慢。Once again, data.table's syntax is consistent with
DT[i, j, by]
. We can just keep throwing expressions inj
without having to worry about these things.
To summarise, I have particularly highlighted several instances where dplyr's syntax is either inefficient, limited or fails to make operations straightforward. This is particularly because data.table gets quite a bit of backlash about "harder to read/learn" syntax (like the one pasted/linked above). Most posts that cover dplyr talk about most straightforward operations. And that is great. But it is important to realise its syntax and feature limitations as well, and I am yet to see a post on it.
data.table has its quirks as well (some of which I have pointed out that we are attempting to fix). We are also attempting to improve data.table's joins as I have highlighted here.
But one should also consider the number of features that dplyr lacks in comparison to data.table.
.
通过对 0x231341 期间的变量进行分组来自动对结果进行排序,这可能并不总是可取的j
以及 data.table 连接的所有其他优点进行连接。do()
在 data.table 中的函数允许通过引用真正快速地重新排序 data.tables。dplyr
提供的一组操作更快当量(由Jan Gorecki写入) - summarise()
,<=, <, >, >=
,setorder()
和data.table
用额外fsetdiff
参数(如SQL)。fintersect
兼容性。 dplyr 更改基本函数 funion
、 fsetequal
和 all
,这可能会导致问题;例如here 和 here 。[.data.frame
并行化已知的耗时部分以提高性能。 关于r - 数据表与 dplyr : can one do something well the other can't or does poorly?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21435339/
我有一个带有嵌套数据的 angular 数据表,我正在尝试在行点击函数上创建另一个数据表。父数据表的 rowCallBack 函数。 这是我的外部数据表 html; 这是我生成数据表的方
我有一个字母数字列,其中包含诸如“1、2、2”之类的字符串。 当我在搜索中输入“1, 2, 2”时,它似乎返回带有“1,”和“2,”的所有单元格。 我该怎么做才能使搜索仅返回“1、2、2”? 使用数据
我有一个获取其数据服务器端的表,使用自定义服务器端初始化参数,这些参数因生成的报告而异。表格生成后,用户可以打开一个弹出窗口,他们可以在其中添加多个附加过滤器以进行搜索。我需要能够使用与原始表相同的初
在 datatables我希望能够隐藏所有列,但似乎无法正确使用语法。 这来自下面的代码和上面的链接,创建了一个显示所有列的按钮。有没有办法写这个以便我可以隐藏所有列? {
我正在使用 DataTable 创建一个交互式表。我有 9 列,其中 5 列是值。我想根据它们的具体情况更改每个单元格的背景颜色。 我已经开始尝试首先更改整行颜色,因为这似乎是一项更容易的任务。但是我
我有一个简单的例子来说明我的问题。我正在使用数据表 1.9。当数据表位于另一个 html 表内时,水平滚动时列标题不会移动。当它不在 html 表中时它工作正常。我的示例实际上取自他们的水平滚动示例,
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
这是添加按钮以将数据导出到 csv、pdf、excel 的数据表示例...... fiddle here https://datatables.net/extensions/buttons/examp
是否有任何方法可以更改 angularjs 数据表中的按钮样式(colvis、copy、print、excel)。 vm.dtOptions = DTOptionsBuilder.newOptions
我试图弄清楚如何加入 2 个数据表并更新第一个但应用了过滤器。 DT DT2 b c 1: 1 10 2: 2 10 3: 3 10 4: 4 10 5: 5 10 6: 6 10 7: 7 10
我有一个数据表,其中包含许多包含值的列。我还有另一列,它定义了我需要选择哪些列的值。我很难找到一种方法来做到这一点。 这是一个简单的例子。 > d d value.1 value.2 name
我正在使用 data.table 包。我有一个数据表,表示用户在网站上的操作。假设每个用户都可以访问一个网站,并对其执行多项操作。我的原始数据表是 Action (每一行都是一个 Action ),我
我想知道每个变量在每个组中变化了多少次,然后将结果添加到所有组中。 我是这样找到的: mi[,lapply(.SD, function(x) sum(x != shift(x), na.rm=T)
有人可以向我解释一下如何向页眉或页脚添加按钮吗?Datatables 的开发者 Alan 说你必须离开网络服务器才能使用 Table Tools 来使用按钮。但我在独立计算机上离线运行 Datatab
我希望按 id 和按顺序(时间)计算不同的东西。 例如,与: dt = data.table( id=c(1,1,1,2,2,2,3,3,3), hour=c(1,5,5,6,7,8,23,23,23
我正在尝试在 JIRA 小工具中使用数据表,但在我的表准备就绪后,没有可用的分页按钮。我有一个表,我正在以最简单的方式使用数据表:$("#mytableid").dataTable(); 浏览页面元素
我有 responsive 表单中的数据表。 数据表生成 child rows在小型设备上。在这一行中,我有一些输入控件。这会导致两个问题。 第一个问题:**隐藏子行中的值不会进入表单数据。** 第二
我在使用 JQuery DataTable 捕获 keydown 事件时遇到问题。我的目标是允许用户使用箭头键导航表的行。因此,当用户按下箭头键时,我想捕获 keydown 事件并移动表的选定行(这是
是否有任何方法可以以编程方式更改显示的行数,而无需从下拉列表中手动选择? 我已经知道如何更改默认行数。当表首次加载时,我希望它加载所有行,然后“刷新”表以可能仅显示前 10 行。但我想以编程方式刷新表
我有一个数据表,我应该对其进行更改,例如我想更改内容的状态,但该内容位于表的第三页。当我更改它时,数据表会自行刷新到第一页。我想做的是保留选定的页码并在刷新后回调它。这可能吗? 顺便说一句,我正在使用
我是一名优秀的程序员,十分优秀!