2014-04-19 89 views
0

我试图做一个函数,将时间(以字符形式)转换为十进制格式,例如1对应于上午1点,23对应于下午11点,24表示一天结束。向量化使用strsplit的函数

下面是这两个函数。这里一个函数向量化,而其他做

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

导致不要试图重新发明轮子:

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 
+0

我的时间字符串非常长(45000),并且处于上述字符格式。将转换为'as.POSIXct'不占用更多的CPU时间? –

+0

它可能比正则表达式更快。当然,它实际上是矢量化的,与使用'apply'功能的解决方案相反。但是你可以用自己的基准测试... – Roland

+0

使用'as.POSIXct'比在几次使用'sapply'快2倍 –

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)) 
}) 
2
as.numeric(strptime(times, "%H:%M:%S")-strptime(Sys.Date(), "%Y-%m-%d")) 
[1] 12.386667 10.395833 9.136111 

基本上相同,罗兰的,但绕过了一些措施,我尝试,如果我能避免使用difftime。有太多的错误产生,因为我不真正了解功能或类...或什么的。当我和罗兰德比赛时,他的速度更快。好吧。

Emulation @G。格罗腾迪克的努力(而且基本上类似合作,以他的优雅strapply解决方案:

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 
+0

我明确使用'difftime',而不是用'-POSIXt'隐式调用它,因为后者自动选择时间单位。 – Roland

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)时钟包有一个"times"类,它在内部将时间表示为一天的几分之一。转换,为小时给出了一个简单的解决方案:

library(chron) 

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

ADDED增加了更多的解决方案。