raf*_*ira 5 r combinatorics dataframe data.table pairwise
我有一个data.table给我在不同的公交路线()的位置(origin和destination)之间的连接route_id.
library(data.table)
library(magrittr)
# data for reproducible example
dt <- data.table( origin = c('A','B','C', 'F', 'G', 'H'),
destination = c('B','C','D', 'G', 'H', 'I'),
freq = c(2,2,2,10,10,10),
route_id = c(1,1,1,2,2,2), stringsAsFactors=FALSE )
# > dt
# origin destination freq route_id
# 1: A B 2 1
# 2: B C 2 1
# 3: C D 2 1
# 4: F G 10 2
# 5: G H 10 2
# 6: H I 10 2
Run Code Online (Sandbox Code Playgroud)
对于什么我想要做的目的,如果有route_id,给出了一个连接A-B和连接B-C,然后我要添加到数据的连接A-C为相同route_id等.
问题:到目前为止,我已经创建了一个简单的代码来完成这项工作,但是:
# loop
# a) get a data subset corresponding to each route_id
# b) get all combinations of origin-destination pairs
# c) row bind the new pairs to original data
for (i in unique(dt$route_id)) {
temp <- dt[ route_id== i,]
subset_of_pairs <- expand.grid(temp$origin, temp$destination) %>% setDT()
setnames(subset_of_pairs, c("origin", "destination"))
dt <- rbind(dt, subset_of_pairs, fill=T)
}
# assign route_id and freq to new pairs
dt[, route_id := route_id[1L], by=origin]
dt[, freq := freq[1L], by=route_id]
# Keepe only different pairs that are unique
dt[, origin := as.character(origin) ][, destination := as.character(destination) ]
dt <- dt[ origin != destination, ][order(route_id, origin, destination)]
dt <- unique(dt)
Run Code Online (Sandbox Code Playgroud)
origin destination freq route_id
1: A B 2 1
2: A C 2 1
3: A D 2 1
4: B C 2 1
5: B D 2 1
6: C D 2 1
7: F G 10 2
8: F H 10 2
9: F I 10 2
10: G H 10 2
11: G I 10 2
12: H I 10 2
Run Code Online (Sandbox Code Playgroud)
单程:
res = dt[, {
stops = c(origin, last(destination))
pairs = combn(.N + 1L, 2L)
.(o = stops[pairs[1,]], d = stops[pairs[2,]])
}, by=route_id]
route_id o d
1: 1 A B
2: 1 A C
3: 1 A D
4: 1 B C
5: 1 B D
6: 1 C D
7: 2 F G
8: 2 F H
9: 2 F I
10: 2 G H
11: 2 G I
12: 2 H I
Run Code Online (Sandbox Code Playgroud)
这是假设这c(origin, last(destination))是按顺序排列的完整停靠点列表。如果dt不包含足够的信息来构建完整的订单,任务就会变得更加困难。
如果dt需要 vars from ,则res[dt, on=.(route_id), freq := i.freq]可以使用更新连接。
像这样的任务总是有内存不足的风险。在这种情况下,OP 最多有 100 万行,其中包含最多 341 个停靠点的组,因此最终结果可能高达1e6/341*choose(341,2)= 1.7 亿行。这是可以管理的,但一般来说,这种分析无法扩展。
怎么运行的
一般来说,data.table 语法可以被视为组上的循环:
DT[, {
...
}, by=g]
Run Code Online (Sandbox Code Playgroud)
与循环相比,这有一些优点:
...不会污染工作空间。.N、.SD、.GRP和.BY以及.()。list()在上面的代码中,pairs查找取自 1 .. #stops 的索引对(=.N+1,其中 .N 是与给定 Route_id 关联的数据子集中的行数)。它是一个矩阵,第一行对应于一对中的第一个元素;和第二行与第二行。应该...评估为列列表;这里list()缩写为.().
进一步改进
我猜时间大部分都花在了combn多次计算上。如果多条路线具有相同的 #stops,则可以通过预先计算来解决此问题:
Ns = dt[,.N, by=route_id][, unique(N)]
cb = lapply(setNames(,Ns), combn, 2)
Run Code Online (Sandbox Code Playgroud)
然后抓取pairs = cb[[as.character(.N)]]主要代码。或者,定义一个pairs使用记忆以避免重新计算的函数。
| 归档时间: |
|
| 查看次数: |
559 次 |
| 最近记录: |