使用dplyr将两个数据框中的信息合并

4
我需要一些关于dplyr的帮助。 我有两个数据框 - 一个大的,里面有几个时间序列A,B, ...(LargeDF),还有一个第二个(Categories),包含左右边界的时间间隔。
我想向LargeDF添加另一列,标记为leftBoundary,其中包含适当的边界值,如下所示:
LargeDF
   ts timestamp   signal     # left_boundary
1   A 0.3209338 10.43279     # 0
2   A 1.4791524 10.34295     # 1
3   A 2.6007494 10.71601     # 2

并且

Categories
   ts left right
1   A    0     1
2   A    1     2
3   A    2     3

我想分享的代码是:

LargeDF %>%
  group_by(ts) %>%
  do(myFUN(., Categories))

# calls this ...
myFUN <- function(Large, Categ) {
  CategTS <- Categ %>%
    filter(ts == Large[1, "ts"][[1]])

  Large %>%
    group_by(timestamp) %>%  # this is bothering me...
    mutate(left_boundary = CategTS$left[CategTS$left < timestamp 
                                         & timestamp < CategTS$right])
}

但是对于大型时间序列来说,它非常慢。我真的想去掉 group_by(timestamp),因为它们在每个 ts 中都是唯一的。

有人看到更好的解决方案吗?这将不胜感激。

# Code for making the example data frames ...
library("dplyr")
n <- 10; series <- c("A", "B", "C")
LargeDF <- data.frame(
    ts        = rep(series, each = n)
  , timestamp = runif(n*length(series), max = 4)
  , signal    = runif(n*length(series), min = 10, max = 11)
) %>% group_by(ts) %>% arrange(timestamp)

m <- 7
Categories <- data.frame(
    ts    = rep(series, each = m)
  , left  = rep(seq(1 : m) - 1, length(series))
  , right = rep(seq(1 : m), length(series))
)

更新(data.table和我稍作修改的模拟)

所以,我首先尝试了@DavidArenburg的建议,在一个快速/脏模拟示例上,但遇到了一个问题,即一些时间戳被分成了两个区间。

> foverlaps(d, c, type="any", by.x = c("timestamp", "timestamp2"))
    left right     value timestamp timestamp2
 1:  0.9   1.9 0.1885459         1          1
 2:  0.9   1.9 0.0542375         2          2  # binned here
 3:  1.9   2.9 0.0542375         2          2  # and here as well
13: 19.9  25.9 0.4579986        20         20

我后来了解到 minoverlap = 1L 是默认设置,并且意识到正常时间戳是 >> 1

> as.numeric(Sys.time())
[1] 1429022267

因此,如果我将所有内容转移到更大的值(例如,在下面的示例中 n <- 10),一切都很好。
   left right      value timestamp timestamp2
1:    9    19 0.64971126        10         10
2:   19    29 0.75994751        20         20
3:   29    99 0.98276462        30         30
9:  199   259 0.89816165       200        200

使用我的真实数据,一切顺利进行,再次感谢。

## Code for my data.table example -----
n <- 1
d <- data.table( value     = runif(9),
                 timestamp = c(1, 2, 3, 5, 7, 10, 15, 18, 20)*n,
                timestamp2 = c(1, 2, 3, 5, 7, 10, 15, 18, 20)*n)
c <- data.table(left  = c(0.9, 1.9, 2.9,  9.9, 19.9, 25.9)*n,
                right = c(1.9, 2.9, 9.9, 19.9, 25.9, 33.9)*n)
setkey(c, left, right)
foverlaps(d, c, type="any", by.x = c("timestamp", "timestamp2"))

更新2(使用dplyr中的JOIN,然后FILTER)

我测试了@aosmith建议使用dplyr函数left_join()创建一个(非常)大的数据框,然后再次使用filter()进行过滤。很快,我就遇到了内存问题:

Error: std::bad_alloc

也许对于小型表格来说,这种方法是一个不错的选择 - 因为语法非常简洁易懂(但这再次取决于个人喜好)。在这种情况下,我会选择 data.table 解决方案。再次感谢所有的建议。


1
边界是“刚好”是 floor(timestamp) 吗? - talat
不,这是模拟数据 - 边界在一天中不断变化。 - Wordsmyth
1
一个解决方法是将数据集合并,然后过滤结果以获取所需的行,例如:left_join(LargeDF, Categories) %>% filter(timestamp > left, timestamp < right) - aosmith
嗯...我会将其与data.table进行比较。谢谢。 - Wordsmyth
1个回答

5

dplyr 不适用于这种操作,建议使用 data.tablefoverlaps 函数。

library(data.table)
class(LargeDF) <- "data.frame" ## Removing all the dplyr classes
setDT(LargeDF)[, `:=`(left = timestamp, right = timestamp)] # creating min and max boundaries in the large table
setkey(setDT(Categories)) # keying by all columns (necessary for `foverlaps` to work)
LargeDF[, left_boundary := foverlaps(LargeDF, Categories)$left][] # Creating left_boundary 
#    ts  timestamp   signal       left      right left_boundary
# 1:  A 0.46771516 10.72175 0.46771516 0.46771516             0
# 2:  A 0.58841492 10.35459 0.58841492 0.58841492             0
# 3:  A 1.14494484 10.50301 1.14494484 1.14494484             1
# 4:  A 1.18298225 10.82431 1.18298225 1.18298225             1
# 5:  A 1.69822678 10.04780 1.69822678 1.69822678             1
# 6:  A 1.83189609 10.75001 1.83189609 1.83189609             1
# 7:  A 1.90947475 10.94715 1.90947475 1.90947475             1
# 8:  A 2.73305266 10.14449 2.73305266 2.73305266             2
# 9:  A 3.02371968 10.17724 3.02371968 3.02371968             3
# ...

1
感谢您清晰的回答!我会更仔细地阅读这些帖子:(https://dev59.com/geo6XIcBkEYKwwoYKRDG)和(https://dev59.com/cF4c5IYBdhLWcg3wzs-Q)。 - Wordsmyth
1
NP,请也看一下使用指南 - David Arenburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接