R 通过多个变量将多个数据帧与data.table联接
所以我看到了一些关于加入不同包的答案。 我需要连接几个数据帧,这对于我的计算机来说是一个非常昂贵的操作,要用基本的“合并”算法来处理 我的数据:R 通过多个变量将多个数据帧与data.table联接,r,data.table,dplyr,R,Data.table,Dplyr,所以我看到了一些关于加入不同包的答案。 我需要连接几个数据帧,这对于我的计算机来说是一个非常昂贵的操作,要用基本的“合并”算法来处理 我的数据: list.of.data.frames = list( data.table("P1" = c(1:3,1:3), "P2" = c(rep(2.5,3),rep(1.5,3)), "D1" = c(3.5,4.5,5.5,2.5,3.5,4.5)), data.table("P1" = c(1:3,1:
list.of.data.frames = list( data.table("P1" = c(1:3,1:3), "P2" = c(rep(2.5,3),rep(1.5,3)), "D1" = c(3.5,4.5,5.5,2.5,3.5,4.5)),
data.table("P1" = c(1:3,1:3), "P3" = c(rep(2,3),rep(3,3)), "D3" =c(3:5,4:6)),
data.table("P1" = c(2:4), "P4" = c(2:4))
)
我试过这两种代码:使用整形 使用基数R 输出:
P1 P2 D1 P3 D3 P4
1: 1 2.5 3.5 2 3 NA
2: 1 2.5 3.5 3 4 NA
3: 2 2.5 4.5 2 4 2
4: 2 2.5 4.5 3 5 2
5: 3 2.5 5.5 2 5 3
6: 3 2.5 5.5 3 6 3
7: 1 1.5 2.5 2 3 NA
8: 1 1.5 2.5 3 4 NA
9: 2 1.5 3.5 2 4 2
10: 2 1.5 3.5 3 5 2
11: 3 1.5 4.5 2 5 3
12: 3 1.5 4.5 3 6 3
13: 4 NA NA NA NA 4
我正在尝试使用最快的方法来执行此操作,它可以很容易地扩展到处理列表。对于data.table
我被键卡住了,因为每个data.frame(或数据表)可以有不同的列,其中一些列可能与其他表相交或不相交
此外,我还看到了data.table::merge.data.table()
函数,但我不知道这是否来自旧版本,因为我在控制台中找不到它
你知道怎么做吗
提前感谢您注意:您包含的两种方法都不适合我,我无法操纵
重塑
方法使其运行
正如@David在一篇评论中提到的,您已经在base
方法中使用了merge.data.table
,因为merge
是一种通用方法,可以“放手”使用更具体的方法(在本例中,对于data.table
)
有一个版本可以使用dplyr
的left\u join
执行多重合并,可以在此处进行修改:
Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2), list.of.data.frames)
我们可以使用microbenchmark
包显式地测试各种方法。我正在添加一个版本,在这个版本中,我告诉left_join
要通过哪一列进行连接,而不是让它来计算(尽管如果每个连接都需要使用不同的列集进行匹配,那么这将不起作用)。我还包括@Axeman的建议,即使用purr
中的reduce
而不是reduce
microbenchmark(
base = Reduce(function(...) merge(..., all=T, by = "P1"), list.of.data.frames)
, dplyr = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2), list.of.data.frames)
, dplyrSet = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2, by = "P1"), list.of.data.frames)
, dplyrPurrr = reduce(list.of.data.frames, full_join, by = "P1")
)
给出:
Unit: microseconds
expr min lq mean median uq max neval cld
base 2911.495 3025.2325 3227.3762 3077.8530 3211.995 5513.166 100 c
dplyr 946.367 1022.0960 1087.8771 1066.3615 1131.675 1429.581 100 b
dplyrSet 443.828 485.3235 543.7130 511.1545 553.040 1918.009 100 a
dplyrPurrr 465.329 494.6615 548.7349 515.6695 551.943 1804.394 100 a
因此,left\u join
的速度大约是merge
的3倍,将变量设置为join将进一步缩短大约一半的时间reduce
并没有缩短时间,尽管它确实使代码更加简洁
我们可以(并且应该,正如@Frank指出的那样)确认返回的值是相同的。对于这种类型的结果,“相同”可能意味着什么存在一些争论,因此我使用compare
包中的compare
来检查差异(每个full\u join
方法完全相同,所以我只展示了有趣的一种):
返回:
TRUE
sorted
renamed rows
dropped row names
dropped attributes
因此,这些值是相同的,但顺序不同(需要排序),行名称不同(需要重命名/删除),属性不同(需要删除)。如果其中任何一个与用例有关,那么用户需要确定哪种方法提供了他们想要的排序/行名/属性
正如@Davidernburg所指出的,不同的尺寸可能导致不同的结果。因此,这里有一些代码检查这些不同的大小
medianTimes_dataTable <- lapply(10^(1:5), function(n){
list_of_longer_ones = list( data.table("P1" = c(1:n), "P2" = rnorm(n), "D1" = rnorm(n)),
data.table("P1" = sample(1:n), "P3" = rnorm(n), "D3" =rnorm(n)),
data.table("P1" = sample(1:n), "P4" = rnorm(n))
)
microbenchmark(
base = Reduce(function(...) merge(..., all=T, by = "P1"), list_of_longer_ones)
, dplyr = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2), list_of_longer_ones)
, dplyrSet = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2, by = "P1"), list_of_longer_ones)
, dplyrPurrr = reduce(list_of_longer_ones, full_join, by = "P1")
) %>%
group_by(expr) %>%
summarise(median = median(time)) %>%
mutate(nRows = n)
}) %>%
bind_rows
medianTimes_dataTable %>%
mutate_at(c("median", "nRows"), format, big.mark = ",", scientific = FALSE) %>%
spread(nRows, median)
给予
expr`10``100``1000``10000``100000`
*
1个底座806009.5 973636.0 2046009.5 19088482.5 519159607.0
2 dplyr 1092747.0 1242550.5 2010648.5 10618735.5 156958793.0
3 DPRhyrSet 526030.0 616996.0 1343766.5 9767689.5 147919013.5
4 dplyrPurrr 541182.0 624208.0 1351910.0 9711435.0 146379176.5
在这里,
full\u join
继续击败merge
——这表明merge.data.table
比merge.data.frame
方法要好(而且很多)。您在那里做的是data.table
合并,而不是基本合并merge
是通用的。请参见methods(merge)
以及data.table:::merge.data.table
。仅供参考,您可以通过使用长格式数据使其无限快:L[[3][,“Dn”:=(NA)];rbindlist(L,use.names=FALSE,idcol=TRUE)
其中L
是您的列表。也就是说,如果速度真的很重要,您应该重新考虑以这种(相当混乱的)方式管理数据。左连接与merge
中的all=TRUE
不同。还有,你把你的第一个版本叫做“base”,你是加入那里的data.frames还是data.tables?谢谢@DavidArenburg——这就是我在喝完咖啡之前回答任何问题的结果。我把它改为full_join
,这应该可以解决问题。捕捉得很好。正在全速进行hadleyverse:减少(list.of.data.frames,full_join,by=“P1”)
。(只是语法上的差异。)谢谢你提醒我关于reduce
@Axeman的事。添加到microbenchmark.Good point@Frank——这是我第一次尝试回答一个明确的基准问题。从结果来看,区别似乎在于排序顺序(merge似乎将所有1放在一起,full\u join
没有)。但是,返回的数据在其他方面似乎是相同的。我添加了一个比较的结果,使测试更加明确。
compare(
Reduce(function(...) merge(..., all=T, by = "P1"), list.of.data.frames)
, reduce(list.of.data.frames, full_join, by = "P1")
, allowAll = TRUE
)
TRUE
sorted
renamed rows
dropped row names
dropped attributes
medianTimes_dataTable <- lapply(10^(1:5), function(n){
list_of_longer_ones = list( data.table("P1" = c(1:n), "P2" = rnorm(n), "D1" = rnorm(n)),
data.table("P1" = sample(1:n), "P3" = rnorm(n), "D3" =rnorm(n)),
data.table("P1" = sample(1:n), "P4" = rnorm(n))
)
microbenchmark(
base = Reduce(function(...) merge(..., all=T, by = "P1"), list_of_longer_ones)
, dplyr = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2), list_of_longer_ones)
, dplyrSet = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2, by = "P1"), list_of_longer_ones)
, dplyrPurrr = reduce(list_of_longer_ones, full_join, by = "P1")
) %>%
group_by(expr) %>%
summarise(median = median(time)) %>%
mutate(nRows = n)
}) %>%
bind_rows
medianTimes_dataTable %>%
mutate_at(c("median", "nRows"), format, big.mark = ",", scientific = FALSE) %>%
spread(nRows, median)
expr ` 10` ` 100` ` 1,000` ` 10,000` `100,000`
* <fctr> <chr> <chr> <chr> <chr> <chr>
1 base 2,032,614.5 2,059,519.0 2,716,534.0 4,475,653.5 29,655,330.0
2 dplyr 1,147,676.5 1,205,818.0 2,369,464.5 11,170,513.5 154,767,265.5
3 dplyrSet 537,434.0 613,785.5 1,602,681.0 10,215,099.5 145,574,663.0
4 dplyrPurrr 540,455.5 626,076.5 1,549,114.0 10,040,808.5 145,086,376.0
medianTimes_dataFrame <- lapply(10^(1:5), function(n){
list_of_longer_ones = list( data.frame("P1" = c(1:n), "P2" = rnorm(n), "D1" = rnorm(n)),
data.frame("P1" = sample(1:n), "P3" = rnorm(n), "D3" =rnorm(n)),
data.frame("P1" = sample(1:n), "P4" = rnorm(n))
)
microbenchmark(
base = Reduce(function(...) merge(..., all=T, by = "P1"), list_of_longer_ones)
, dplyr = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2), list_of_longer_ones)
, dplyrSet = Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2, by = "P1"), list_of_longer_ones)
, dplyrPurrr = reduce(list_of_longer_ones, full_join, by = "P1")
) %>%
group_by(expr) %>%
summarise(median = median(time)) %>%
mutate(nRows = n)
}) %>%
bind_rows
medianTimes_dataFrame %>%
mutate_at(c("median", "nRows"), format, big.mark = ",", scientific = FALSE) %>%
spread(nRows, median)
expr ` 10` ` 100` ` 1,000` ` 10,000` `100,000`
* <fctr> <chr> <chr> <chr> <chr> <chr>
1 base 806,009.5 973,636.0 2,046,009.5 19,088,482.5 519,159,607.0
2 dplyr 1,092,747.0 1,242,550.5 2,010,648.5 10,618,735.5 156,958,793.0
3 dplyrSet 526,030.0 616,996.0 1,343,766.5 9,767,689.5 147,919,013.5
4 dplyrPurrr 541,182.0 624,208.0 1,351,910.0 9,711,435.0 146,379,176.5