将时间戳(开始,结束)转换为时间序列数据。 align.time()和colnames的错误

时间:2013-06-28 11:01:03

标签: r time time-series xts

我是R的新手,但是在参加了一个介绍课程并稍微玩了一下后,我希望它可以1)更优雅地解决我的建模目标(与Excel相比,这是我的备份计划)和2 )是一个有用的技能,以摆脱这个项目。

任务/目标:

我正在尝试使用驾驶日记数据来模拟和模拟电动汽车的潜在能源和温室气体排放。具体做法是:

  1. 我想要翻译成日记数据(开始和结束时间戳,以及下面数千个驱动程序的其他数据 - 下面的基本示例):
  2. 24小时时间序列数据,这样,对于24小时的每一分钟,我确切地知道谁在驾驶车辆,以及它属于哪个“行程”(对于该驾驶员)。我的问题主要集中在这个问题上。
  3. 我想要的输出类型: 注意:此输出 NOT 与下面提供的示例数据相关。我使用了某一天的前十分钟和一些理论旅行作为例子

    enter image description here

    对于这个问题不是必不可少的,但可能有用的知道:我将使用上面的输出来交叉引用其他特定于驱动程序的数据,以根据与之相关的事物计算汽油(或电力)的逐分钟消耗量。那次旅行,例如停车位置或行程距离。我想在R中这样做,但在进入这一步之前必须首先找出上述问题。

    我到目前为止的解决方案基于:

    问题:

    简化数据示例:

    a <- c("A","A","A","B","B","B","C","C","C")
    b <- c(1, 2, 3, 1, 2, 3, 1, 2, 3)
    c <- as.POSIXct(c(0.29167, 0.59375, 0.83333, 0.45833, 0.55347, 0.27083, 0.34375, 0.39236, 0.35417)*24*3600 + as.POSIXct("2013-1-1 00:00") )
    d <- as.POSIXct(c(0.334027778, 0.614583333, 0.875, 0.461805556, 0.563888889, 0.295138889, 0.375, 0.503472222, 0.364583333)*24*3600 + as.POSIXct("2013-1-1 00:00"))
    e <- c(2, 8, 2, 5, 5, 2, 5, 5, 2)
    f <- as.POSIXct(c(0, 0.875, 0, 0.479166666666667, 0.580555555555556, 0.489583333333333, 0.430555555555556, 0.541666666666667, 0.711805555555555)*24*3600 + as.POSIXct("2013-1-1 00:00"))
    g <- as.POSIXct(c(0, 0.885, 0, 0.482638888888889, 0.588194444444444, 0.496527777777778, 0.454861111111111, 0.559027777777778, 0.753472222222222)*24*3600 + as.POSIXct("2013-1-1 00:00"))
    h <- c(0, 1, 0, 1, 4, 8, 8, 1, 5)
    i <- as.POSIXct(c(0, 0, 0, 0.729166666666667, 0.595833333333333, 0.534722222222222, 0.59375, 0.779861111111111, 0.753472222222222)*24*3600 + as.POSIXct("2013-1-1 00:00"))
    j <- as.POSIXct(c(0, 0, 0, 0.736111111111111, 0.605555555555556, 0.541666666666667, 0.611111111111111, 0.788194444444445, 0.75625)*24*3600 + as.POSIXct("2013-1-1 00:00"))
    k <- c(0, 0, 0, 4, 4, 2, 5, 8,1)
    testdata <- data.frame(a,b,c,d,e,f,g,h,i,j,k)
    names(testdata) <- c("id", "Day", "trip1_start", "trip1_end", "trip1_purpose", "trip2_start", "trip2_end", "trip2_purpose", "trip3_start", "trip3_end", "trip3_purpose")
    

    在这个示例数据中,我有三个驱动程序(id = A,B,C),每个驱动程序在三个不同的日期(日= 1,2,3)。请注意,某些驾驶员可能会有不同的行程次数。时间戳表示驾驶活动的开始和结束时间。

    然后我创建一整天(2013年1月1日)的分钟间隔

    start.min <- as.POSIXct("2013-01-01 00:00:00 PST")
    end.max <- as.POSIXct("2013-01-01 23:59:59 PST")
    tinterval <- seq.POSIXt(start.min, end.max, na.rm=T, by = "mins")
    

    在给定用户驾驶的分钟内插入“1”:

    out1 <- xts(,align.time(tinterval,60))
    # loop over each user
    for(i in 1:NROW(testdata)) {
      # paste the start / end times into an xts-style range
      timeRange <- paste(format(testdata[i,c("trip1_start","trip1_end")]),collapse="/")
      # add the minute "by parameter" for timeBasedSeq
      timeRange <- paste(timeRange,"M",sep="/")
      # create the by-minute sequence and align to minutes to match "out"
      timeSeq <- align.time(timeBasedSeq(timeRange),60)
      # create xts object with "1" entries for times between start and end
      temp1 <- xts(rep(1,length(timeSeq)),timeSeq)
      # merge temp1 with out and fill non-matching timestamps with "0"
      out1 <- merge(out1, temp1, fill=0)
    }
    # add column names
    colnames(out1) <- paste(testdata[,1], testdata[,2], sep = ".")
    

    这个想法是为每次旅行重复这个,例如out2,out3等,其中我用“2”,“3”等填充任何驱动周期,然后对所有得到的 x 数据帧进行求和/合并,最终得到所需的结果

    不幸的是,当我尝试为out2重复这个...

    out2 <- xts(,align.time(tinterval,60))
    for(i in 1:NROW(testdata)) {
      timeRange2 <- paste(format(testdata[i,c("trip2_start","trip2_end")]),collapse="/")
      timeRange2 <- paste(timeRange2,"M",sep="/")
      timeSeq2 <- align.time(timeBasedSeq(timeRange2),60)
      temp2 <- xts(rep(2,length(timeSeq2)),timeSeq2)
      out2 <- merge(out2, temp2, fill=0)
    }
    colnames(out2) <- paste(testdata[,1], testdata[,2], sep = ".")
    head(out2)
    

    我收到以下错误:

      
        
    • UseMethod中的错误(“align.time”):对于“Date”类的对象,“align.time”没有适用的方法
    •   
    • colnames<-中的错误(*tmp*,值= c(“A.1”,“A.2”,“A.3”,“B.1”,“B.2” ,:尝试在较少的对象上设置'colnames'   比两个维度
    •   

    我的out2代码出了什么问题?

    我可以了解其他更好的解决方案或套餐吗?

    我意识到这可能是一种非常迂回的方式来达到我想要的输出。

    非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

在此解决方案中,我读取您的原​​始数据并对其进行格式化以获取我之前答案的生成数据。所提供的数据仅限于驾驶员的22次旅行,但此处的重塑不受行程次数的限制。这个想法类似于用于生成样本数据的想法。我正在使用data.table,因为每个组操作数据非常方便。

因此,对于每个(日,司机),我执行以下操作:

  1. 创建一个长度为零的零向量
  2. 使用XXXstrip_start和XXXstrip_end读取开始和结束位置。
  3. 创建序列seq(开始,结束)
  4. 使用此序列通过数字序列
  5. 更改零

    这是我的代码:

    start.min <- as.POSIXct("2013-01-01 00:00:00 PST")
    hours.min <- format(seq(start.min, 
                            length.out=24*60, by = "mins"),
                        '%H:%M')
    library(data.table)
    diary <- read.csv("samplediary.csv",
                      stringsAsFactors=FALSE)
    DT <- data.table(diary,key=c('id','veh_assigned','day'))
    
    dat <- DT[, as.list({ .SD;nb.trip=sum_trips
               tripv <- vector(mode='integer',length(hours.min))
               if(sum_trips>0){
                 starts = mget(paste0('X',seq(nb.trip),'_trip_start'))
                 ends = mget(paste0('X',seq(nb.trip),'_trip_end'))
                 ids <- mapply(function(x,y){
                                            seq(as.integer(x),as.integer(y))},
                               starts,ends,SIMPLIFY = FALSE)
                 for (x in seq_along(ids))tripv[ids[[x]]] <- x
                 }
                tripv
               }),
       by=c('id','day')]
    setnames(x=dat,old=paste0('V',seq(hours.min)),hours.min)
    

    如果您对10个第一个变量进行分组,那么您将获得以下内容:

    dat[1:10,1:10,with=FALSE]
    
    
           id day 00:00 00:01 00:02 00:03 00:04 00:05 00:06 00:07
     1: 3847339   1     0     0     0     0     0     0     0     0
     2: 3847384   1     0     0     0     0     0     0     0     0
     3: 3847436   1     0     0     0     0     0     0     0     0
     4: 3847439   1     0     0     0     0     0     0     0     0
     5: 3847510   1     0     0     0     0     0     0     0     0
     6: 3847536   1     0     0     0     0     0     0     0     0
     7: 3847614   1     0     0     0     0     0     0     0     0
     8: 3847683   1     0     0     0     0     0     0     0     0
     9: 3847841   1     0     0     0     0     0     0     0     0
    10: 3847850   1     0     0     0     0     0     0     0     0
    

    一个想法是创建数据的热图(至少每天)以获得一些直觉并查看重叠的驱动程序。这里有两种使用latticeggplot2执行此操作的方法,但首先我将使用reshape2

    以长格式重新整理数据
    library(reshape2)
    dat.m <- melt(dat,id.vars=c('id','day'))
    

    然后我绘制热图以查看哪些驱动程序与其他驱动程序重叠,例如:

    library(lattice)
    levelplot(value~as.numeric(variable)*factor(id),data=dat.m)
    

    enter image description here

    library(ggplot2)
    ggplot(dat.m, aes(x=as.numeric(variable),y=factor(id)))+ 
            geom_tile(aes(fill = value)) +
      scale_fill_gradient(low="grey",high="blue")
    

    enter image description here

答案 1 :(得分:0)

这不是您问题的答案。老实说,我不清楚您在图像中显示的数据与数据示例之间的转换。好像你无法重现这些数据。所以这是一个生成数据可重现示例的函数。我认为验证你的模型至少是有用的。

对数据进行抽样的功能

library(reshape2)
start.min <- as.POSIXct("2013-01-01 00:00:00 PST")
hours.min <- format(seq(start.min, 
                        length.out=24*60, by = "mins"),
                    '%H:%M')

## function to generate a trip sample
## min.dur : minimal duration of a trip
## max.dur : maximal duration of a trip
## min.trip : minimal number of trips that a user can do 

gen.Trip <- function(min.dur=3,max.dur=10,min.trip=100){
  ## gen number of trip
  n.trip <- sample(seq(min.trip,20),1)
  ## for each trip generate the durations
  durations <- rep(seq(1,n.trip),
                   times=sample(seq(min.dur,max.dur),
                                max(min.dur,n.trip),rep=TRUE))
  ## generate a vector of positions
  rr <- rle(durations)
  mm <- cumsum(rr$lengths)
  ## idrty part here
  pos <- sort(sample(seq(1,length(hours.min)-2*max(mm)),
              n.trip,rep=FALSE)) + mm
  ## assign each trip to each posistion  
  val <- vector(mode='integer',length(hours.min))
  for(x in seq_along(pos))
    val[seq(pos[x],length.out=rr$len[x])] <- rr$val[x]
  val
}

为100名司机生成行程

set.seed(1234)
nb.drivers <- 100
res <- replicate(nb.drivers,gen.Trip(),simplify=FALSE)
res <- do.call(rbind,res)
colnames(res) <- hours.min
rownames(res) <- paste0('driv',seq(nb.drivers))

宽幅

head(res[,10:30])
  ##       00:09 00:10 00:11 00:12 00:13 00:14 00:15 00:16 00:17 00:18 00:19
## driv1     0     0     0     0     0     0     1     1     1     1     1
## driv2     0     1     1     1     1     1     1     2     2     2     1
## driv3     0     0     0     0     0     0     0     0     0     0     0
## driv4     1     1     1     0     0     0     0     0     0     0     0
## driv5     0     0     0     0     0     0     0     0     0     0     1
## driv6     0     0     0     0     0     0     0     0     0     0     0
##       00:20 00:21 00:22 00:23 00:24 00:25 00:26 00:27 00:28 00:29
## driv1     1     1     0     0     2     2     2     2     2     2
## driv2     0     0     0     0     0     0     3     3     3     3
## driv3     0     0     0     0     0     0     0     0     0     0
## driv4     0     0     0     0     0     0     0     0     0     0
## driv5     1     1     1     1     1     1     1     1     0     0
## driv6     0     0     0     0     0     0     0     0     0     0

长格式

res.m <- melt(res)
head(res.m)
##    Var1  Var2 value
## 1 driv1 00:00     0
## 2 driv2 00:00     0
## 3 driv3 00:00     0
## 4 driv4 00:00     0
## 5 driv5 00:00     0
## 6 driv6 00:00     0