在r中使用带有替换函数的data.table

时间:2015-07-13 19:51:58

标签: r data.table

我今天遇到了以下问题,我想知道是否有更好的方法来完成我想要做的事情。

假设我有以下data.table(只是每小时时间戳):

library(data.table)
tdt <- data.table(Timestamp = seq(as.POSIXct("1980-01-01 00:00:00"), as.POSIXct("2015-01-01 00:00:00"), '1 hour'))

> tdt
                  Timestamp
     1: 1980-01-01 00:00:00
     2: 1980-01-01 01:00:00
     3: 1980-01-01 02:00:00
     4: 1980-01-01 03:00:00
     5: 1980-01-01 04:00:00
    ---                    
306813: 2014-12-31 20:00:00
306814: 2014-12-31 21:00:00
306815: 2014-12-31 22:00:00
306816: 2014-12-31 23:00:00
306817: 2015-01-01 00:00:00

我的目标是将时间戳的分钟更改为10分钟。

我知道我可以使用:

library(lubridate)
minute(tdt$Timestamp) <- 10

但这并没有利用数据表的超快速度(我需要)。在我的笔记本电脑上,这是:

> system.time(minute(tdt$Timestamp) <- 10)
   user  system elapsed 
  11.29    0.16   11.45 

所以,我的问题是:我们可以在数据表语法中以某种方式使用替换函数,以便它可以使用data.table的速度执行我想要的操作吗?如果答案是否定的,那么快速执行此操作的任何其他data.table解决方案都是可以接受的。

如果你想知道我尝试的其中一件事是:

tdt[, Timestamp2 := minute(Timestamp) <- 10]

哪个不起作用。

预期输出(但使用数据表语法):

> tdt
                  Timestamp
     1: 1980-01-01 00:10:00
     2: 1980-01-01 01:10:00
     3: 1980-01-01 02:10:00
     4: 1980-01-01 03:10:00
     5: 1980-01-01 04:10:00
    ---                    
306813: 2014-12-31 20:10:00
306814: 2014-12-31 21:10:00
306815: 2014-12-31 22:10:00
306816: 2014-12-31 23:10:00
306817: 2015-01-01 00:10:00

3 个答案:

答案 0 :(得分:11)

POSIXct对象只是一个带有一些属性的双重

storage.mode(as.POSIXct("1980-01-01 00:00:00"))
## [1] "double"

因此,为了有效地操纵 ,您可以将其视为一个,例如

tdt[, Timestamp := Timestamp + 600L]

将通过引用 为每行添加600秒(10分钟)

一些基准

tdt <- data.table(Timestamp = seq(as.POSIXct("1600-01-01 00:00:00"), 
                                  as.POSIXct("2015-01-01 00:00:00"), 
                                  '1 hour'))
system.time(minute(tdt$Timestamp) <- 10)
# user  system elapsed 
# 124.86    1.95  127.68 
system.time(set(tdt, j = 1L, value = `minute<-`(tdt$Timestamp, 10)))
# user  system elapsed 
# 124.99    1.83  128.25 
system.time(tdt[, Timestamp := Timestamp + dminutes(10)])
# user  system elapsed 
# 0.39    0.04    0.42 
system.time(tdt[, Timestamp := Timestamp + 600L])
# user  system elapsed 
# 0.01    0.00    0.01 

答案 1 :(得分:7)

替换功能分两步进行:

  1. 创建所需输出的函数
  2. 然后将该输出分配给结果。
  3. 您可以运行step 1 without running step 2。然后,可以使用该结果设置data.table列(此处使用set,但您也可以使用:=)。

    library(lubridate)
    library(data.table)
    tdt <- data.table(Timestamp = seq(as.POSIXct("1980-01-01 00:00:00"), as.POSIXct("2015-01-01 00:00:00"), '1 hour'))
    minute(tdt$Timestamp) <- 20
    print( `minute<-`(tdt$Timestamp,11) )
    set( tdt, j=1L,value=`minute<-`(tdt$Timestamp,11)  )
    

    编辑:小型data.table与大数据。基准测试

    library(lubridate)
    library(data.table)
    library(microbenchmark)
    
    # Config
    tms <- 5L
    
    # Sample data, 1 column
    tdt <- data.table(Timestamp = seq(as.POSIXct("1980-01-01 00:00:00"), as.POSIXct("2015-01-01 00:00:00"), '1 hour'))
    minute(tdt$Timestamp) <- 20
    
    tdf <- as.data.frame( tdt )
    
    
    # Sample data, lots of columns
    bdf <- cbind( tdf, as.data.frame( replicate( 100, runif(nrow(tdt)) ) ) )
    bdt <- as.data.table( bdf )
    
    # Benchmark
    microbenchmark(
      `minute<-`(tdt$Timestamp,10), # How long does the operation to generate the new vector itself take?
      set( tdt, j=1L,value=`minute<-`(tdt$Timestamp,11)  ), # One column: How long does it take to generate the new vector and replace the contents in the data.table?
      minute( tdf$Timestamp ) <- 12, # One column: How long does it take to do it with a data.frame?
      set( tdt, j=1L,value=`minute<-`(bdt$Timestamp,13)  ), # Many columns: How long does it take to generate the new vector and replace the contents in the data.table?
      minute( bdf$Timestamp ) <- 14, #  Many columns: How long does it take to do it with a data.frame?
      times = tms
    )
    
    Unit: seconds
                                                        expr      min       lq     mean   median       uq      max neval
                               `minute<-`(tdt$Timestamp, 10) 1.304388 1.385883 1.417616 1.389316 1.459166 1.549327     5
     set(tdt, j = 1L, value = `minute<-`(tdt$Timestamp, 11)) 1.314495 1.344277 1.376241 1.352124 1.389083 1.481225     5
                                 minute(tdf$Timestamp) <- 12 1.342104 1.349231 1.488639 1.378840 1.380659 1.992358     5
     set(tdt, j = 1L, value = `minute<-`(bdt$Timestamp, 13)) 1.337944 1.383429 1.402802 1.418211 1.418922 1.455503     5
                                 minute(bdf$Timestamp) <- 14 1.332482 1.333713 1.355331 1.335728 1.342607 1.432127     5
    

    看起来并不快,这掩盖了我对正在发生的事情的理解。奇怪。

答案 2 :(得分:3)

我想这应该适合你:

mailItem.UserProperties.Add("myid", Outlook.OlUserPropertyType.olText);
mailItem.UserProperties["myid"].Value = myid;