矢量化使用strsplit的函数

时间:2014-04-19 20:36:55

标签: r vectorization strsplit

我正在尝试创建一个将时间(字符形式)转换为十进制格式的函数,使得1对应于上午1点,23对应于11点,24表示当天结束。

这是执行此操作的两个功能。这里有一个函数矢量化,而其他函数

time2dec <- function(time0)
{
time.dec <-as.numeric(substr(time0,1,2))+as.numeric(substr(time0,4,5))/60+(as.numeric(substr(time0,7,8)))/3600
return(time.dec)
}

time2dec1 <- function(time0)
{
time.dec <-as.numeric(strsplit(time0,':')[[1]][1])+as.numeric(strsplit(time0,':')[[1]][2])/60+as.numeric(strsplit(time0,':')[[1]][3])/3600
return(time.dec)
}

这就是我得到的......

times <- c('12:23:12','10:23:45','9:08:10')

#>time2dec(times)
[1] 12.38667 10.39583       NA
Warning messages:
1: In time2dec(times) : NAs introduced by coercion
2: In time2dec(times) : NAs introduced by coercion

#>time2dec1(times)
[1] 12.38667

我知道time2dec是向量化的,为最后一个元素提供NA,因为它以小时为单位提取9:而不是9。这就是我创建time2dec1的原因,但我不知道为什么它没有被矢量化。

我也有兴趣获得更好的功能来做我想做的事情。 我看到this解释了我问题的一部分,但没有提供做我正在尝试的事情的线索。

4 个答案:

答案 0 :(得分:4)

不要试图重新发明轮子:

times1 <- difftime(as.POSIXct(times, "%H:%M:%S", tz="GMT"),
                   as.POSIXct("0:0:0", "%H:%M:%S", tz="GMT"), 
                   units="hours")
#Time differences in hours
#[1] 12.386667 10.395833  9.136111

as.numeric(times1)
#[1] 12.386667 10.395833  9.136111

答案 1 :(得分:2)

 as.numeric( strptime(times, "%H:%M:%S")-strptime(Sys.Date(), "%Y-%m-%d" ))
[1] 12.386667 10.395833  9.136111

基本上与Roland相同,但绕过了一些步骤,如果可以,我尽量避免使用difftime。有太多的错误出现,因为我真的不了解功能或类......或者其他什么。当我与Roland的时间相比时,他的速度更快了。哦,好吧。

模仿@ G.Grothendieck的努力(基本上与他优雅的背景解决方案类似:

num <- apply( matrix(scan(text=gsub(":", " ", ch), what=numeric(0)),nrow=3), 2, 
                 function(x) x[1]+x[2]/60 +x[3]/3600 )
#Read 9 items
num
#[1] 12.386667 10.395833  9.136111

这实际上回答了原来的问题:

 num <- sapply( strsplit(ch, ":"), function(x){ x2 <- as.numeric(x);
                                                x2[1]+x2[2]/60 +x2[3]/3600})
 num
#[1] 12.386667 10.395833  9.136111

答案 2 :(得分:2)

在下文中,我们将使用此测试向量:

ch <- c('12:23:12','10:23:45','9:08:10')

1)要修复问题中的解决方案,我们前缀为0,然后用最后两位替换任意3位数的字符串:

num.substr <- function(...) as.numeric(substr(...))
time2dec <- function(time0) {
    t0 <- sub("\\d(\\d\\d)", "\\1", paste0(0, time0))
    num.substr(t0, 1, 2) + num.substr(t0, 4, 5) / 60 + num.substr(t0, 7, 8) / 3600
}

time2dec(ch)
## [1] 12.386667 10.395833  9.136111

2)使用gsubfn包中的strapply解析字符串会更容易:

strapply(ch, "^(.?.):(..):(..)", 
   ~ as.numeric(h) + as.numeric(m)/60 + as.numeric(s)/36000,
   simplify = c)
## [1] 12.383667 10.384583  9.133611

3)我们可以将字符串操作减少为仅删除冒号,然后将生成的字符串转换为数字,以便我们可以用数字方式对其进行操作:

num <- as.numeric(gsub(":", "", ch))
num %/% 10000 + num %% 10000 %/% 100 / 60 + num %% 100 / 3600
## [1] 12.386667 10.395833  9.136111

4) chron包中有一个"times"类,内部表示一天中的几分之一。将其转换为小时可以提供简单的解决方案:

library(chron)

24 * as.numeric(times(ch))
## [1] 12.386667 10.395833  9.136111

已添加添加了更多解决方案。

答案 3 :(得分:1)

以下是您想要的

sapply(strsplit(times, ":"), function(d) {
  sum(as.numeric(d)*c(1,1/60,1/3600))
})

一步一步:

strsplit(times, ":")

返回带有字符向量的列表。每个字符向量包含时间的三个部分(小时,分钟,秒)。我们现在想要将列表中的每个元素转换为数值。为此,我们需要对每个元素应用一个函数,并将后面的结果放入一个sapply所做的向量中。

sapply(strsplit(times, ":", function(d) {
})

至于功能。我们首先需要使用as.numeric将字符值转换为数值。我们将第一个元素与1相乘,第二个元素与1/60相乘,第三个元素与1/3600相乘并添加结果(我们使用sum)。导致

sapply(strsplit(times, ":"), function(d) {
  sum(as.numeric(d)*c(1,1/60,1/3600))
})