基于不同的时间戳,将数据表连接起来

5
我正在处理一个关于合并两个数据表(或数据框)的问题,基于不相等的时间戳(POSIXct)。根据表格A中的特定时间戳,我希望R能够返回表格B中在该时间之前的条目。
以下是一个例子:
我有一个名为“表格A”的数据表,其中包含有关某一时刻活动的数据。
编辑:这些数据与原始帖子中不同,更好地反映了问题:我需要根据时间戳和我称为站点ID的分组变量进行查找。很抱歉一开始没有表达清楚。
             Start.Time Start.Station.ID
1: 2014-04-06 18:24:32              238
2: 2014-04-06 18:20:30              238
3: 2014-04-06 01:04:13              373
4: 2014-04-06 01:03:36              373
5: 2014-04-06 01:03:37              373
6: 2014-04-06 01:03:01              373
7: 2014-04-06 01:02:42              373
8: 2014-04-06 01:02:31              373

我想在表A中添加一列,以指示某个时间点上该站点的“可用性”状态。这些状态可以在表B中找到。
              status_dt station_id availability
 1: 2014-04-06 00:29:02        238    0.9354839
 2: 2014-04-06 00:29:02        373    1.0000000
 3: 2014-04-06 01:29:03        238    1.0000000
 4: 2014-04-06 01:29:03        373    0.6111111
 5: 2014-04-06 02:59:03        238    0.9354839
 6: 2014-04-06 02:59:03        373    0.6666667
    ...
41: 2014-04-06 17:59:03        238    0.8387097
42: 2014-04-06 17:59:03        373    0.4444444
43: 2014-04-06 18:59:03        238    0.9032258
44: 2014-04-06 18:59:03        373    0.5000000
45: 2014-04-06 20:29:03        238    0.7741935
              status_dt station_id availability

时间戳不匹配,因此我想在表A中添加来自表B的状态,该状态是在表A时间戳之前观察到的。
期望结果将会是例如“可用性”列:
             status_dt station_id availability 
1: 2014-04-06 18:24:32        238    0.8387097         
2: 2014-04-06 18:20:30        238    0.8387097            
3: 2014-04-06 01:04:13        373    1.0000000            
4: 2014-04-06 01:03:36        373    1.0000000           
5: 2014-04-06 01:03:37        373    1.0000000            
6: 2014-04-06 01:03:01        373    1.0000000          
7: 2014-04-06 01:02:42        373    1.0000000           
8: 2014-04-06 01:02:31        373    1.0000000          

BodieG的建议是在Start.Station.ID/station_id中的条目唯一时有效,但将其应用于此数据会产生以下结果。
             status_dt station_id availability Start.Station.ID
1: 2014-04-06 18:24:32        373    0.4444444              238
2: 2014-04-06 18:20:30        373    0.4444444              238
3: 2014-04-06 01:04:13        373    1.0000000              373
4: 2014-04-06 01:03:36        373    1.0000000              373
5: 2014-04-06 01:03:37        373    1.0000000              373
6: 2014-04-06 01:03:01        373    1.0000000              373
7: 2014-04-06 01:02:42        373    1.0000000              373
8: 2014-04-06 01:02:31        373    1.0000000              373

第一行和第二行的条目不是我预期的(或者说是希望的):它们指的是站点373而不是238的“可用性”。

我猜想代码必须要适应时间戳和站点ID,但我现在感到很困扰...... 另外,我无法确定使用建议的xts包是否有所帮助,因为这里明显存在重复的时间步长...

再次提醒,任何提示都非常感谢。 提前致谢!

为了可重复性:
表A:

structure(list(Start.Time = structure(c(1396808672, 1396808430, 
1396746253, 1396746216, 1396746217, 1396746181, 1396746162, 1396746151
), class = c("POSIXct", "POSIXt"), tzone = "UTC"), Start.Station.ID = c(238, 
238, 373, 373, 373, 373, 373, 373)), .Names = c("Start.Time", 
"Start.Station.ID"), class = c("data.table", "data.frame"), row.names = c(NA, 
-8L))

表B:

   structure(list(status_dt = structure(c(1396744142, 1396744142, 
1396747743, 1396747743, 1396753143, 1396753143, 1396754942, 1396754942, 
1396756743, 1396756743, 1396758542, 1396758542, 1396760343, 1396760343, 
1396765743, 1396765743, 1396767542, 1396767542, 1396772943, 1396772943, 
1396778402, 1396778402, 1396781943, 1396781943, 1396785542, 1396785542, 
1396787342, 1396787342, 1396790942, 1396790942, 1396794543, 1396794543, 
1396798143, 1396798143, 1396799943, 1396799943, 1396801743, 1396801743, 
1396805343, 1396805343, 1396807143, 1396807143, 1396810743, 1396810743, 
1396816143, 1396816143, 1396817942, 1396817942, 1396821542, 1396821542, 
1396826942, 1396826942), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    station_id = c(238, 373, 238, 373, 238, 373, 238, 373, 238, 
    373, 238, 373, 238, 373, 238, 373, 238, 373, 238, 373, 238, 
    373, 238, 373, 238, 373, 238, 373, 238, 373, 238, 373, 238, 
    373, 238, 373, 238, 373, 238, 373, 238, 373, 238, 373, 238, 
    373, 238, 373, 238, 373, 238, 373), availability = c(0.935483870967742, 
    1, 1, 0.611111111111111, 0.935483870967742, 0.666666666666667, 
    0.967741935483871, 0.666666666666667, 0.967741935483871, 
    0.666666666666667, 0.935483870967742, 0.666666666666667, 
    0.967741935483871, 0.666666666666667, 0.967741935483871, 
    0.611111111111111, 0.967741935483871, 0.611111111111111, 
    1, 0.444444444444444, 0.870967741935484, 0.5, 0.806451612903226, 
    0.5, 0.774193548387097, 0.388888888888889, 0.709677419354839, 
    0.388888888888889, 0.67741935483871, 0.333333333333333, 1, 
    0.5, 0.903225806451613, 0.444444444444444, 0.935483870967742, 
    0.444444444444444, 0.903225806451613, 0.444444444444444, 
    0.870967741935484, 0.444444444444444, 0.838709677419355, 
    0.444444444444444, 0.903225806451613, 0.5, 0.774193548387097, 
    0.611111111111111, 0.766666666666667, 0.611111111111111, 
    0.774193548387097, 0.555555555555556, 0.870967741935484, 
    0.666666666666667)), .Names = c("status_dt", "station_id", 
"availability"), class = c("data.table", "data.frame"), row.names = c(NA, 
-52L), sorted = "status_dt")

2
您仍然可以使用@BrodieG的解决方案,但按照station_id和时间戳(以此顺序)进行匹配。这将确保通过ID进行精确匹配,但通过时间滚动进行匹配。 - ilir
1
谢谢!同意,@BrodieG的方法仍然有效。我不知道如何实现@ilir的建议。相反,我从data.table介绍中了解到连接发生在特定顺序中,因此我重新排列了数据表中的列。这似乎起作用了:A2 <- A[,c(2,1)]setkey(B, station_id, status_dt) - Stephan
1
你只需要设置不同的键:setkey(A, Start.Station.ID, Start.Time)setkey(B, station_id, status_dt)。然后运行相同的滚动连接 B[A, roll=T] - ilir
谢谢@ilir。这比我的方法好多了。当涉及到data.table时,我需要学习很多。 - Stephan
1
我的方法和你的一样(实际上是通过设置关键字来对表进行排序)。起初决定使用data.tables有些棘手,但这是我在使用R时做出的最好决定。 - ilir
2个回答

4
您可以使用“roll”参数:
setkey(B, status_dt)
B[A, roll=TRUE]

生成:

              status_dt station_id availability Start.Station.ID
 1: 2014-04-06 21:07:42        225    0.4864865              225
 2: 2014-04-06 21:06:50        225    0.4864865              225
 3: 2014-04-06 21:06:49        225    0.4864865              225
 4: 2014-04-06 21:06:15        225    0.4864865              225
 5: 2014-04-06 21:04:35        225    0.4864865              225
 6: 2014-04-06 21:05:33        225    0.4864865              225
 7: 2014-04-06 21:04:45        225    0.4864865              225
 8: 2014-04-06 21:04:37        225    0.4864865              225
 9: 2014-04-06 21:04:35        225    0.4864865              225
10: 2014-04-06 21:01:45        225    0.4864865              225
11: 2014-04-06 21:00:57        225    0.4864865              225
12: 2014-04-06 20:59:04        225    0.4864865              225
13: 2014-04-06 20:58:04        225    0.8648649              225
14: 2014-04-06 20:57:22        225    0.8648649              225
15: 2014-04-06 20:57:24        225    0.8648649              225
16: 2014-04-06 20:56:40        225    0.8648649              225
17: 2014-04-06 20:55:52        225    0.8648649              225
18: 2014-04-06 20:55:25        225    0.8648649              225
19: 2014-04-06 20:55:24        225    0.8648649              225
20: 2014-04-06 20:55:00        225    0.8648649              225
21: 2014-04-06 18:25:30        225    0.9729730              225
22: 2014-04-06 18:25:28        225    0.9729730              225
              status_dt station_id availability Start.Station.ID

这与您期望的输出非常相似,除了我可以确定根据您对问题的描述,它有一些额外的行是合法的。

2

我主要使用zooxts包,这些包基本上是为此编写的。

R> dfA <- as.data.frame(A)
R> a <- xts(dfA[,2], order.by=dfA[,1])
R> dfB <- as.data.frame(B)
R> b <- xts(dfB[,-1], order.by=dfB[,1])

现在我们有两个 xts 对象,我们可以使用 merge() 函数合并它们,并对结果运行 na.locf() 函数,以填充 NA 值为前一个值:

R> na.locf(merge(a, b))
                      a station_id availability
2014-04-06 17:59:03  NA        225     0.972973
2014-04-06 18:25:28 225        225     0.972973
2014-04-06 18:25:30 225        225     0.972973
2014-04-06 18:59:03 225        225     0.621622
2014-04-06 20:29:03 225        225     0.864865
2014-04-06 20:55:00 225        225     0.864865
2014-04-06 20:55:24 225        225     0.864865
2014-04-06 20:55:25 225        225     0.864865
2014-04-06 20:55:52 225        225     0.864865
2014-04-06 20:56:40 225        225     0.864865
2014-04-06 20:57:22 225        225     0.864865
2014-04-06 20:57:24 225        225     0.864865
2014-04-06 20:58:04 225        225     0.864865
2014-04-06 20:59:02 225        225     0.486486
2014-04-06 20:59:04 225        225     0.486486
2014-04-06 21:00:57 225        225     0.486486
2014-04-06 21:01:45 225        225     0.486486
2014-04-06 21:04:35 225        225     0.486486
2014-04-06 21:04:35 225        225     0.486486
2014-04-06 21:04:37 225        225     0.486486
2014-04-06 21:04:45 225        225     0.486486
2014-04-06 21:05:33 225        225     0.486486
2014-04-06 21:06:15 225        225     0.486486
2014-04-06 21:06:49 225        225     0.486486
2014-04-06 21:06:50 225        225     0.486486
2014-04-06 21:07:42 225        225     0.486486
2014-04-06 21:59:02 225        225     0.162162
2014-04-06 23:29:02 225        225     0.162162
R> 

但是在这方面也应该有一个data.table的答案...

编辑:根据评论,这里是只包含a时间戳的合并:

R> na.locf(merge(a, b))[index(a), -1]
                    station_id availability
2014-04-06 18:25:28        225     0.972973
2014-04-06 18:25:30        225     0.972973
2014-04-06 20:55:00        225     0.864865
2014-04-06 20:55:24        225     0.864865
2014-04-06 20:55:25        225     0.864865
2014-04-06 20:55:52        225     0.864865
2014-04-06 20:56:40        225     0.864865
2014-04-06 20:57:22        225     0.864865
2014-04-06 20:57:24        225     0.864865
2014-04-06 20:58:04        225     0.864865
2014-04-06 20:59:04        225     0.486486
2014-04-06 21:00:57        225     0.486486
2014-04-06 21:01:45        225     0.486486
2014-04-06 21:04:35        225     0.486486
2014-04-06 21:04:35        225     0.486486
2014-04-06 21:04:37        225     0.486486
2014-04-06 21:04:45        225     0.486486
2014-04-06 21:05:33        225     0.486486
2014-04-06 21:06:15        225     0.486486
2014-04-06 21:06:49        225     0.486486
2014-04-06 21:06:50        225     0.486486
2014-04-06 21:07:42        225     0.486486
R> 

在这种情况下,我还删除了多余的站点ID列。

感谢您的帮助。我之前没有考虑过xts,所以这是一个很好的提示。然而,预期的输出不应该包含B中的数据;因此,18:59:03的条目不应该出现在输出中。我尝试了na.locf(merge(a, coredata(b)),参考了这里的讨论,但是没有成功。总体来说,@BrodieG的答案似乎解决了我的问题。感谢你们两个的快速支持! - Stephan
我明白了。在这种情况下,实现这个的一种方法是通过 a 重新索引。请看我的更新答案。 - Dirk Eddelbuettel

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