在浪费了将近一天后,我正在寻求帮助。我有一个大数据帧(bdf)和一个小数据帧(sdf)。我想将变量z添加到bdf,具体取决于sdf $ y的值(它随时间变量而变化)。
这是一个可重复的例子:
bdf <- data.frame(tb = seq(as.POSIXct("2013-05-19 17:11:22 GMT", tz="GMT"), by=5624*24, length.out=10))
bdf
tb
1 2013-05-19 17:11:22
2 2013-05-21 06:40:58
3 2013-05-22 20:10:34
4 2013-05-24 09:40:10
5 2013-05-25 23:09:46
6 2013-05-27 12:39:22
7 2013-05-29 02:08:58
8 2013-05-30 15:38:34
9 2013-06-01 05:08:10
10 2013-06-02 18:37:46
sdf <- data.frame(ts = as.POSIXct(c("2013-05-22", "2013-05-25", "2013-05-30"), tz="GMT"), y = c(0.2, -0.1, 0.3))
> sdf
ts y
1 2013-05-22 0.2
2 2013-05-25 -0.1
3 2013-05-30 0.3
我想在bdf中使用以下sdf $ y值创建变量z:
0.2对于行,其中bdf $ tb的范围从第一个bdf $ tb到sdf $ ts的第一个和第二个值之间的中间值。在这个简单的例子中,这是dbf的第1行到第3行的情况,其时间bdf $ tb低于“2013-05-23 12:00:00 GMT”。
-0.1对于行,其中bdf $ tb的范围从sdf $ ts的第1和第2值之间的中间到sdf $ ts的第2和第3值之间的中间。在这个简单的例子中,这是dbf的第4行和第5行的情况,在“2013-05-23 12:00:00 GMT”和“2013-05-27 12:00:00 GMT”之间的时间为bdf $ tb
对于所有行,其中bdf $ tb的范围是从sdf $ ts的第2和第3值到bdf $ tb的最后一个值的中间值。在这个简单的例子中,这是dbf的第1到6到10行,其时间大于“2013-05-23 12:00:00 GMT”。
因此,最后,大数据帧bdf应如下所示:
tb z
1 2013-05-19 17:11:22 0.2
2 2013-05-21 06:40:58 0.2
3 2013-05-22 20:10:34 0.2
4 2013-05-24 09:40:10 -0.1
5 2013-05-25 23:09:46 -0.1
6 2013-05-27 12:39:22 0.3
7 2013-05-29 02:08:58 0.3
8 2013-05-30 15:38:34 0.3
9 2013-06-01 05:08:10 0.3
10 2013-06-02 18:37:46 0.3
我无法成功使用dplyr :: mutate并且无处使用循环...任何帮助都将非常感激。我希望我清楚地将这个问题描述为遵守礼仪(这是我的第一个问题)。
答案 0 :(得分:7)
以下是使用data.table
&#39> 滚动加入的解决方案:
require(data.table)
setkey(setDT(sdf), ts)
sdf[bdf, roll = "nearest"]
# ts y
# 1: 2013-05-19 17:11:22 0.2
# 2: 2013-05-21 06:40:58 0.2
# 3: 2013-05-22 20:10:34 0.2
# 4: 2013-05-24 09:40:10 -0.1
# 5: 2013-05-25 23:09:46 -0.1
# 6: 2013-05-27 12:39:22 0.3
# 7: 2013-05-29 02:08:58 0.3
# 8: 2013-05-30 15:38:34 0.3
# 9: 2013-06-01 05:08:10 0.3
# 10: 2013-06-02 18:37:46 0.3
setDT
通过引用将data.frame转换为data.table 。
setkey
按提供的列按递增顺序对data.table 按引用排序,并将这些列标记为键列(以便我们可以稍后加入这些关键专栏。
在data.table中,x[i]
在i
是data.table时执行连接。如果您还不熟悉,我会推荐您this answer来了解data.table联接。
x[i]
执行 equi-join 。也就是说,它在x
中为i
中的每一行找到匹配的行索引,然后从x
中提取这些行以返回连接结果以及来自i
的相应行。如果i
中的某行未在x
中找到匹配的行索引,则默认情况下该行NA
将为x
。
但是,x[i, roll = .]
执行滚动加入。当没有匹配时,最后一个观察结果是前进(roll = TRUE
或-Inf
),或者下一个观察结果可以向后进行(roll = Inf
),或者滚动到最近的值(roll = "nearest"
)。在这种情况下,您需要roll = "nearest"
IIUC。
HTH
答案 1 :(得分:3)
这是我的方法:
library(zoo)
m <- c(rollmean(as.POSIXct(sdf$ts), 2), Inf)
transform(bdf, z = sdf$y[sapply(tb, function(x) which.max(x < m))])
# tb z
#1 2013-05-19 17:11:22 0.2
#2 2013-05-21 06:40:58 0.2
#3 2013-05-22 20:10:34 0.2
#4 2013-05-24 09:40:10 -0.1
#5 2013-05-25 23:09:46 -0.1
#6 2013-05-27 12:39:22 0.3
#7 2013-05-29 02:08:58 0.3
#8 2013-05-30 15:38:34 0.3
#9 2013-06-01 05:08:10 0.3
#10 2013-06-02 18:37:46 0.3
更新:已删除转换为数字(不需要)
简要说明:
as.POSIXct(sdf$ts)
将日期转换为POSIXct样式的日期时间rollmean(as.POSIXct(sdf$ts), 2)
计算每两个连续行的滚动平均值。这恰好是您想要用于分离观察的时间。 rollmean
来自包zoo
。计算rollmean(..,2)
意味着与输入向量相比,输出向量缩短了1。rollmean
的结果包装在c(.., Inf)
中的原因,这意味着将无穷大值作为最后一个值添加到rollmean向量中。这样可以确保返回z
中sdf
的最后一个条目(具体示例中为0.3)。transform
将z
列添加到bdf
sapply(tb, function(x) which.max(x < m))
循环遍历bdf$tb
中的条目,并为每个条目计算bdf$tb
小于(早于)m
(保存向量)的最大索引rollmean条目)。每个bdf$tb
条目仅返回最大(最新)索引。sdf$y[sapply(tb, function(x) which.max(x < m))]
中使用索引向量来提取sdf$y
的相应元素,然后将其存储/复制到z
中的新bdf
列希望有所帮助
答案 2 :(得分:3)
编辑注释:我最初得到的结果与我现在认为与我对R difftime对象缺乏了解有关的结果略有不同。 POSIXt
对象中的时区对我来说仍然是一个谜,但我现在看到,当我强迫一个&#39; difftime&#39;反对&#39;数字&#39;我在&#34;天&#34;中获得了价值。
findInterval
函数作为索引创建函数非常有用,该函数映射值 - 向量,其中一个值具有多个相邻的非重叠区间。你真的只有两个时间点分成三个区间。
bdf$z <- c(0.2,-0.1,0.3)[findInterval(bdf$tb,
c(-Inf,
sdf$ts[2] - 0.5*as.numeric(difftime(sdf$ts[2], sdf$ts[1], units="secs")),
sdf$ts[3] - 0.5*as.numeric(difftime(sdf$ts[3], sdf$ts[2],units="sec")),
Inf))]
> bdf
tb z
1 2013-05-19 17:11:22 0.2
2 2013-05-21 06:40:58 0.2
3 2013-05-22 20:10:34 0.2
4 2013-05-24 09:40:10 -0.1
5 2013-05-25 23:09:46 -0.1
6 2013-05-27 12:39:22 0.3
7 2013-05-29 02:08:58 0.3
8 2013-05-30 15:38:34 0.3
9 2013-06-01 05:08:10 0.3
10 2013-06-02 18:37:46 0.3
我还检查了我的结果是否会受到findIntervals中的间隔是否在右边而不是左边(默认值)关闭的影响,并且没有看到差异。
答案 3 :(得分:3)
这似乎现在绝对没必要,但在基地R
bdf$z <- numeric(nrow(bdf))
for(i in seq_along(bdf$z)){
ind <- which.min(abs(bdf$tb[i] - sdf$ts))
bdf$z[i] <- sdf$y[ind]
}
虽然有点笨拙,但它具有清晰度的优势,可以轻松适应dplyr
library(dplyr)
bdf %>% rowwise() %>%
mutate(z= sdf$y[which.min(abs(as.numeric(tb)-as.numeric(sdf$ts)))])
#Source: local data frame [10 x 2]
#Groups: <by row>
# tb z
#1 2013-05-19 17:11:22 0.2
#2 2013-05-21 06:40:58 0.2
#3 2013-05-22 20:10:34 0.2
#4 2013-05-24 09:40:10 -0.1
#5 2013-05-25 23:09:46 -0.1
#6 2013-05-27 12:39:22 0.3
#7 2013-05-29 02:08:58 0.3
#8 2013-05-30 15:38:34 0.3
#9 2013-06-01 05:08:10 0.3
#10 2013-06-02 18:37:46 0.3