【问题标题】:joining data based on a moving time window in R基于 R 中的移动时间窗口连接数据
【发布时间】:2011-08-03 11:13:58
【问题描述】:

我有每小时记录一次的天气数据,以及每 4 小时记录一次的位置数据 (X,Y)。我想知道 X,Y 位置的温度。天气数据并不完全相同。因此,我为每个位置编写了这个循环,以扫描天气数据,寻找日期/时间中的“最近”并从该时间提取数据。问题是我编写它的方式,对于位置 #2,它会扫描天气数据,但不允许分配分配给位置 #1 的最接近的时间信息。假设位置 #1 和 2 是在下午 6 点和下午 6:10 的 10 分钟内拍摄的,最近的天气时间是下午 6 点。我无法选择允许下午 6 点的天气数据。我有点像这样设置它,因为我的位置数据集中有 200 个位置(比如 3 个月),我不希望它从天气数据的时间 0 开始,当我知道最近的天气数据只是为最后一个位置,也恰好是该数据集的 3 个月。下面是一些示例数据和我的代码。我不知道这是否有意义。

<h6>####Location data</h6>

<p>X   Y   DateTime <br />
1   2   4/2/2003    18:01:01
3   2   4/4/2003    17:01:33
2   3   4/6/2003    16:03:07
5   6   4/8/2003    15:03:08
3   7   4/10/2003   14:03:06
4   5   4/2/2003    13:02:00
4   5   4/4/2003    12:14:43
4   3   4/6/2003    11:00:56
3   5   4/8/2003    10:02:06</p>

<h2>2   4   4/10/2003   9:02:19</h2>

<p>Weather Data
DateTime        WndSp   WndDir  Hgt
4/2/2003 17:41:00   8.17    102.86  3462.43
4/2/2003 20:00:00   6.70    106.00  17661.00
4/2/2003 10:41:00   6.18    106.00  22000.00
4/2/2003 11:41:00   5.78    106.00  22000.00
4/2/2003 12:41:00   5.48    104.00  22000.00
4/4/2003 17:53:00   7.96    104.29  6541.00
4/4/2003 20:53:00   6.60    106.00  22000.00
4/4/2003 19:41:00   7.82    105.00  7555.00
4/4/2003 7:41:00    6.62    105.00  14767.50
4/4/2003 8:41:00    6.70    106.00  17661.00
4/4/2003 9:41:00    6.60    106.00  22000.00
4/5/2003 20:41:00   7.38    106.67  11156.67
4/6/2003 18:07:00   7.82    105.00  7555.00
4/6/2003 21:53:00   6.18    106.00  22000.00
4/6/2003 21:41:00   6.62    105.00  14767.50
4/6/2003 4:41:00    7.96    104.29  6541.00
4/6/2003 5:41:00    7.82    105.00  7555.00
4/6/2003 6:41:00    7.38    106.67  11156.67
4/8/2003 18:53:00   7.38    106.67  11156.67
4/8/2003 22:53:00   5.78    106.00  22000.00
4/8/2003 1:41:00    5.78    106.00  22000.00
4/8/2003 2:41:00    5.48    104.00  22000.00
4/8/2003 3:41:00    8.17    102.86  3462.43
4/10/2003 19:53:00  6.62    105.00  14767.50
4/10/2003 23:53:00  5.48    104.00  22000.00
4/10/2003 22:41:00  6.70    106.00  17661.00
4/10/2003 23:41:00  6.60    106.00  22000.00
4/10/2003 0:41:00   6.18    106.00  22000.00
4/11/2003 17:41:00  8.17    102.86  3462.43</p>

<h2>4/12/2003 18:41:00  7.96    104.29  6541.0</h2>

.

weathrow = 1
for (i in 1:nrow(SortLoc)) {
    t = 0
    while (t < 1) {
        timedif1 = difftime(SortLoc$DateTime[i], SortWeath$DateTime[weathrow], units="auto")
        timedif2 =  difftime(SortLoc$DateTime[i], SortWeath$DateTime[weathrow+1], units="auto") 
        if (timedif2 < 0) {
            if (abs(timedif1) < abs(timedif2)) {
                SortLoc$WndSp[i]=SortWeath$WndSp[weathrow]
                SortLoc$WndDir[i]=SortWeath$WndDir[weathrow]
                SortLoc$Hgt[i]=SortWeath$Hgt[weathrow]
            } else {
                SortLoc$WndSp[i]=SortWeath$WndSp[weathrow+1]
                SortLoc$WndDir[i]=SortWeath$WndDir[weathrow+1]
                SortLoc$Hgt[i]=SortWeath$Hgt[weathrow+1]
            }
            t = 1
        }
        if (abs(SortLoc$DateTime[i] - SortLoc$DateTime[i+1] < 50)) {
            weathrow=weathrow
        } else {
            weathrow = weathrow+1
            #if(weathrow = nrow(SortWeath)){t=1}
        }
    } #end while
}

【问题讨论】:

  • 如果这是一个 R 问题,您能否提供一些易于使用的 R 格式的示例数据?即,少量的 dput(object) 就可以了。
  • R代码上面有一小部分数据。我不确定 dput(object) 是什么意思,因为我正在学习。
  • 如果您将一个对象(变量)放入 dput(object) 中,它将输出其他人可以用来复制和粘贴您的部分数据的内容。

标签: r date loops


【解决方案1】:

您可以使用findInterval 函数找到最接近的值:

# example data:
x <- rnorm(120000)
y <- rnorm(71000)
y <- sort(y) # second vector must be sorted
id <- findInterval(x, y, all.inside=TRUE) # finds position of last y smaller then x
id_min <- ifelse(abs(x-y[id])<abs(x-y[id+1]), id, id+1) # to find nearest

在您的情况下,可能需要一些 as.numeric

# assumed that SortWeath is sorted, if not then SortWeath <- SortWeath[order(SortWeath$DateTime),]
x <- as.numeric(SortLoc$DateTime)
y <- as.numeric(SortWeath$DateTime)
id <- findInterval(x, y, all.inside=TRUE)
id_min <- ifelse(abs(x-y[id])<abs(x-y[id+1]), id, id+1)
SortLoc$WndSp  <- SortWeath$WndSp[id_min]
SortLoc$WndDir <- SortWeath$WndDir[id_min]
SortLoc$Hgt    <- SortWeath$Hgt[id_min]

一些补充:你不应该绝对更新在 for 循环中向 data.frame 添加值。检查这个比较:

N=1000
x <- numeric(N)
X <- data.frame(x=x)
require(rbenchmark)
benchmark(
    vector = {for (i in 1:N) x[i]<-1},
    data.frame = {for (i in 1:N) X$x[i]<-1}
)
#         test replications elapsed relative
# 2 data.frame          100    4.32    22.74
# 1     vector          100    0.19     1.00

data.frame 版本慢了 20 倍以上,如果包含的行越多,则差异越大。

因此,如果您更改脚本并首先初始化结果向量:

tmp_WndSp <- tmp_WndDir <- tmp_Hg <- rep(NA, nrow(SortLoc))

然后循环更新值

tmp_WndSp[i] <- SortWeath$WndSp[weathrow+1]
# and so on...

最后(循环外)更新适当的列:

SortLoc$WndSp <- tmp_WndSp
SortLoc$WndDir <- tmp_WndDir
SortLoc$Hgt <- tmp_Hgt

它应该运行得更快。

【讨论】:

  • 非常感谢!这很好用。并且无需循环!现在来完全测试它!
【解决方案2】:

这是您可能使用的一种策略的示例。这会逐个遍历天气时间,然后取该时间与每个位置时间之间差异的绝对值,然后获取最小的时间差异。这解决了您的展望/回顾问题。您的数据集似乎足够小,移动到半矢量化解决方案应该是您需要的所有速度增益,但如果不是,添加移动窗口应该相对简单,该移动窗口仅在最后一个位置周围通过一些 +/- N 观察。匹配索引。

w <- as.POSIXct(strptime( c("4/2/2003 17:41:00","4/2/2003 20:00:00","4/2/2003 10:41:00","4/2/2003 11:41:00","4/2/2003 12:41:00"),format="%m/%d/%Y %H:%M:%S"))
l <- as.POSIXct(strptime( c("4/2/2003 18:01:01","4/2/2003 17:01:33","4/2/2003 16:03:07","4/2/2003 15:03:08","4/2/2003 14:03:06","4/2/2003 13:02:00"),format="%m/%d/%Y %H:%M:%S"))

window.size <- 5

findClosest <- function(w.i,l) {
    which.min(abs(w.i-l))
}
makeWindow <- function(loc.match.index,i,window.size,n) {
    win.max <- loc.match.index[i-1] + window.size
    if(win.max > n) {
        win.max <- n
    }
    win.min <- loc.match.index[i-1] - window.size
    if(win.min < 1) {
        win.min <- 1
    }
    return(seq(win.min,win.max))
}

loc.match.index <- integer()
n <- length(w)
# Initialize on whole vector
i <- 1
loc.match.index[i] <- findClosest(w[i],l)
# Continue on window
for(i in seq(2,n)) {
    wndw <- makeWindow(loc.match.index,i,window.size,n)
    loc.match.index[i] <- findClosest(w[i],l[wndw]) 
    # Add the start of the window back to the index that was returned
    loc.match.index[i] <- loc.match.index[i] + min(wndw)-1
}
> loc.match.index
[1] 1 1 5 5 5

这里仍有一些地方可以提高效率,但考虑到比较是矢量化的并且可以调整窗口,这应该相当快。

【讨论】:

  • 所以,我的数据集是 120,000 个位置,我的天气已经编译了 5 年,所以有 71,000 个天气数据。我之前已经编写了脚本来执行我认为您所描述的操作,但是需要 8 天的时间来处理并占用 1 台计算机来完成它。对于第 1 点,我计算了每个天气数据(71,000 个差异)的日期/时间差异,然后找到了最小值。现在做 120,000 次。于是有了窗户的想法。我不需要反向计算,也不需要一直搜索到最后。那么,您对窗户的建议……您能否再解释一下?
  • 我尝试运行您提供的带有更多天气数据的小脚本,但出现了一个错误,指出 data.frames 需要具有相同的大小。在我目前的尝试中,天气点多于位置,但在最终版本中,位置点将多于天气。无论哪种方式...
  • @Kerry: 为你添加了一个窗口。
  • @Kerry:我确认它可以在我的计算机上使用不同的矢量长度。当您复制并粘贴它时,它有效吗?我怀疑在从我的简化解决方案转移到基于 data.frame 的解决方案时,您犯了一个错误。也许发布您的代码?如果您提供了 dput() 输出,我会使用 data.frames...以供将来参考,dput 确实让每个人的事情变得更容易。
猜你喜欢
  • 2019-02-09
  • 2021-05-04
  • 2023-03-23
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 2022-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多