【问题标题】:POSIX Vector Comparison -- searching through and finding a match between DATE vectors efficiently?POSIX 向量比较——有效地搜索并找到 DATE 向量之间的匹配项?
【发布时间】:2011-08-26 23:55:52
【问题描述】:

我有 55 个POSIXct 类型向量。 ptime 向量是参考向量。我想在 ptime 和其余向量之间找到匹配的日期。匹配日期后,我想进行时间比较。随后进行时间比较,结果将填充到 data.frame(test) 中,并带有适当的分类号。

# create the reference and the other vectors 
ptime <- sample(seq(as.POSIXct('2005-08-01'),as.POSIXct('2006-05-31'), by='hour'),1051)
dawn <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),by='hour'),1095)
sunrise <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),by='hour'),1095)
sunset <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),by='hour'),1095)
dusk <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),by='hour'),1095)

# extract the date to compare using only the `dawn` vector
# all other vectors (except ptime) have the same date and length
pt <- as.Date(ptime)
dw <- as.Date(dawn)

# create data.frame
time <- c(1:1051)
test<-data.frame(time)

# I use a data.frame because I want to re-populate an existing data.frame
> str(test)
'data.frame':   1051 obs. of  1 variable:
 $ time: int  1 2 3 4 5 6 7 8 9 10 ...

# this is the loop that matches and assigns
for( b in 1:length(ptime) ){
    for( a in 1:length(dawn) ) {
      if( dw[a] == pt[b] ){
            if( ptime[b] < dawn[a] ) {
                test$time[b] <- 1
            }else if( ptime[b] < sunrise[a] ) {
                test$time[b] <- 2
            }else if( ptime[b] < sunset[a] ) {
                test$time[b] <- 3
            }else if( ptime[b] < dusk[a] ) {
                test$time[b] <- 4
            }else
                test$time[b] <- 1
        }
    }
}

# output result shows the categorization sequence of 1, 2, 3, and 4
> head(test)
  time
1    1
2    1
3    3
4    1
5    1
6    3

上面的代码完成了我想做的事情......但它需要98.58 秒。我有更多长度不同的数据(最多 5000 个)。

由于我是这方面的新手,我的猜测是......需要这么多时间的是日期的比较。每次必须进行新的比较时dw[a] == pt[b],该过程必须搜索dw[a]。另外,if-else 语句是完成任务所必需的吗?

谁能提供一种更快/更有效的方法来loop 通过、查找匹配项并存储结果? 非常感谢。谢谢

【问题讨论】:

  • 您的代码不可重现,换句话说,当我在我的机器上运行它时会出错。请让您的示例可重现。
  • 编辑了我的帖子。示例代码应该可以工作。谢谢
  • 请再试一次。为确保您的示例可重现,请从干净的 R 会话开始并尝试运行您的代码。
  • 我们去吧。对此感到抱歉

标签: r datetime date matching


【解决方案1】:

根据 OP 的更新编辑

接下来的内容仍然主要是我的猜测。我在您的编辑中修正了一些错别字以得到这个:

ptime <- sample(seq(as.POSIXct('2005-08-01'),as.POSIXct('2006-05-31'), 
                by='hour'),1051)
dawn <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),
                by='hour'),1095)
sunrise <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),
                by='hour'),1095)
sunset <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),
                by='hour'),1095)
dusk <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31'),
                by='hour'),1095)

# extract the date to compare using only the `dawn` vector
# all other vectors (except ptime) have the same date and length
pt <- as.Date(ptime)
dw <- as.Date(dawn)

# create data.frame
time <- c(1:1051)
test<-data.frame(time)

这是我的疯狂尝试:

tmp <- outer(pt, dw, "==")
tmp[upper.tri(tmp)] <- NA
tmp <- which(tmp,arr.ind = TRUE)

test$time[ tmp[ ptime[ tmp[,1] ] < dawn[ tmp[,2] ],1] ] <- 1
test$time[ tmp[ ptime[ tmp[,1] ] < sunrise[ tmp[,2] ],1 ] ] <- 2
test$time[ tmp[ ptime[ tmp[,1] ] < sunset[ tmp[,2] ],1 ] ] <- 3
test$time[ tmp[ ptime[ tmp[,1] ] < dusk[ tmp[,2] ],1] ] <- 4

那是一些丑陋、丑陋的子集索引。丑到我相信必须有更好的方法来组织数据以避免这种情况。它也很模糊,我不确定我能否清楚地解释发生了什么,但我认为这就是你所描述的。

【讨论】:

  • 很抱歉没有发布可重现的数据,但看起来您已经完成了非常简单。我唯一会做不同的事情是抵消日期x &lt;- sample(seq(as.POSIXct('2000-08-01'),as.POSIXct('2003-12-31'),by = "hour"),1000)y &lt;- sample(seq(as.POSIXct('2000-01-01'),as.POSIXct('2005-12-31'),by = "hour"),5000) 并创建不同的长度。生成的数据存储在数据框test$time 中,您会推荐什么其他“方便”的形式?我还在学习,非常感谢您分享您的知识
  • 另外...日出、日落等都是 POSIXct 日期/时间向量,其 DATE 与 dawn 相同
  • joran...运行您发布的if-else 语句会引发错误...In if (x[d[, 1]] &lt; y[d[, 2]]) { : the condition has length &gt; 1 and only the first element will be used
  • @wisfool 这就是为什么我说我提供的代码只是一个草图。如果您需要更多帮助,则必须编辑您的问题以包含一个独立的、可重现的示例。有关如何执行此操作的一些建议,请参阅 here
  • @joran... 感谢您的关注和帮助。在您的代码的帮助下,我能够非常快速地完成任务……这就是我所拥有的……d &lt;- which(outer(as.Date(ptime, tz='MST'),as.Date(dawn, tz='MST'),"=="),arr.ind = TRUE) test$time &lt;- ifelse( (ptime[d[,1]] &lt; dawn[d[,2]]) | (ptime[d[,1]] &gt; dusk[d[,2]]), 1, ifelse( ptime[d[,1]] &lt; sunrise[d[,2]], 2, ifelse( ptime[d[,1]] &lt; sunset[d[,2]], 3, 4 ) ) )
【解决方案2】:

真正的快速解决方案

ptime <- sample(seq(as.POSIXct('2005-08-01'),as.POSIXct('2006-05-31'), by='hour'),1051)
dawn <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31')),1095)
sunrise <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31')),1095)
sunset <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31')),1095)
dusk <- sample(seq(as.POSIXct('2005-01-01'),as.POSIXct('2007-12-31')),1095)

time <- c(1:1051)
test<-data.frame(time)

# From joran
#creates a matrix that lists the IDs that match each other
d <- which(outer(as.Date(ptime, tz='MST'),as.Date(dawn, tz='MST'),"=="),arr.ind = TRUE)

>head(d)
     row col
[1,]  86 213
[2,] 226 213
[3,] 346 213
[4,] 492 214
[5,] 272 215

#This `ifelse` handles multivalued vectors
test$time <- ifelse( (ptime[d[,1]] < dawn[d[,2]]) | (ptime[d[,1]] > dusk[d[,2]]), 1, 
             ifelse(ptime[d[,1]] < sunrise[d[,2]], 2, 
             ifelse( ptime[d[,1]] < sunset[d[,2]], 3, 4 ) ) )

感谢 joran,这在我的机器上运行在 0.00。矢量化是关键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多