【问题标题】:R: How to handle times without dates?R:如何处理没有日期的时间?
【发布时间】:2014-05-04 19:02:18
【问题描述】:

我的数据包括Date 以及Time enterTime exit。后两者包含如下数据:08:0212:0223:45 等。

我想操作 Time eXXX 数据 - 例如,从 Time exit 中减去 Time enter 以计算持续时间,或者绘制 Time enterTime exit 的分布,例如查看是否大多数进入是在 10:00 之前,或者如果大多数退出是在 17:00 之后。

我查看过的所有包裹都需要在时间之前加上日期,例如01/02/2012 12:33.

这是可能的,还是我应该每次都简单地附加一个相同的日期以进行计算?这看起来有点乱!

【问题讨论】:

标签: r date time r-faq


【解决方案1】:

感谢您的反馈,并为造成的混乱感到抱歉,我已对其进行了一些编辑以澄清。

新编辑:

首先,chron 包和具有固定格式的strptime 都可以很好地工作,如其他答案所示。我只想简单介绍一下lubridate,因为它更容易使用,而且时间格式也很灵活。

示例数据

df <- data.frame(TimeEnterChar = c(rep("07:58", 10), "08:02", "08:03", "08:05", "08:10", "09:00"),
                 TimeExitChar  = c("16:30", "16:50", "17:00", rep("17:02", 10), "17:30", "18:59"),
                 stringsAsFactors = F)

如果你只想计算8:00之后的进入时间,那么你可以直接比较字符。下面应该会晚 5 个进入时间。

sum(df$TimeEnterChar > "08:00")

如果您想要更多,就个人而言,我喜欢 lubridate 包处理时间数据,尤其是带有日期的时间戳,尽管它根本不是本文的重点。

library(lubridate)
# Convert character to a "Period" class by lubridate, shows in form of H M S
df$TimeEnterTime <- hm(df$TimeEnterChar)
df$TimeExitTime  <- hm(df$TimeExitChar)
head(df)

sum(df$TimeEnterTime > hm("08:00"))

你仍然可以比较时间。

关于将它们用作数字的更多信息: 我假设只需要分钟级的时间。因此,我将秒数除以 60 得到分钟数。

df$DurationMinute <- as.numeric( df$TimeExitTime - df$TimeEnterTime )/60
hist(df$DurationMinute, breaks = seq(500, 600, 5))

head(df)
  TimeEnterChar TimeExitChar TimeEnterTime TimeExitTime DurationMinute
1         07:58        16:30     7H 58M 0S   16H 30M 0S            512
2         07:58        16:50     7H 58M 0S   16H 50M 0S            532
3         07:58        17:00     7H 58M 0S    17H 0M 0S            542
4         07:58        17:02     7H 58M 0S    17H 2M 0S            544
5         07:58        17:02     7H 58M 0S    17H 2M 0S            544
6         07:58        17:02     7H 58M 0S    17H 2M 0S            544

您可以简单地绘制直方图来查看进入和退出之间的持续时间分布。

您还可以查看进入/退出时间的分布。但是转换轴需要一些努力。

df$TimeEnterNumMin <- as.numeric(df$TimeEnterTime) / 60
df$TimeExitNumMin  <- as.numeric(df$TimeExitTime) / 60

hist(df$TimeEnterNumMin, breaks = seq(0, 1440, 60), xaxt = 'n', main = "Whole by 1hr")
axis(side = 1, at = seq(0, 1440, 60), labels = paste0(seq(0, 24, 1), ":00"))

hist(df$TimeEnterNumMin, breaks = seq(420, 600, 15), xaxt = 'n', main = "Morning by 15min")
axis(side = 1, at = seq(420, 600, 60), labels = paste0(seq(7, 10, 1), ":00"))

我没有润色情节,也没有使轴灵活。请根据您的需要做。希望对您有所帮助。


下面是旧的无用帖子:(无需阅读。保留,以免 cmets 看起来很奇怪)

遇到了类似的问题,并受到这篇文章的启发。 @G。 Grothendieck 和@David Arenburg 为改变时代提供了很好的答案。

为了比较,我觉得将时间强制转换为数字会有所帮助。与其比较"11:22:33""9:00:00",不如比较as.numeric(hms("11:22:33"))(即40953 秒)和as.numeric(hms("9:00:00"))32400)会容易得多。

as.numeric(hms("11:22:33")) > as.numeric(hms("9:00:00"))  &  as.numeric(hms("11:22:33")) < as.numeric(hms("17:00:00"))
[1] TRUE

以上示例显示 11:22:33 介于上午 9 点和下午 5 点之间。

要从日期或 POSIXct 对象中提取时间,substr("2013-10-01 11:22:33 UTC", 12, 19) 应该可以工作,尽管将时间对象更改为字符串/字符并再次返回时间看起来很愚蠢。

将时间转换为数字应该可以绘制为@G。格洛腾迪克描述道。您可以根据 x 轴标签的需要将数字转换回时间。

【讨论】:

  • 我看不出你回答的重点。 hms("11:22:33") &gt; hms("9:00:00") &amp; hms("11:22:33") &lt; hms("17:00:00") 效果很好,为什么你觉得用as.numeric 包裹每个单独的部分更好?
  • @Gregor 你是绝对正确的。我想我最初这样做的原因是我正在考虑将其转换回时间格式以进行绘图。现在我意识到我可以使用hour(hms("11:22:33")) 而不是做数学运算。谢谢!
  • 我建议删除这个答案。它似乎没有添加任何有用的东西——只是分散了其他答案的注意力。如果我错了并且这里有一些有用的东西,那么应该编辑答案以突出显示。
【解决方案2】:

使用chron package 中的"times" 类:

library(chron)

Enter <- c("09:12", "17:01")
Enter <- times(paste0(Enter, ":00"))

Exit <-  c("10:15", "18:11")
Exit <- times(paste0(Exit, ":00"))

Exit - Enter # durations

sum(Enter < "10:00:00") # no entering before 10am
mean(Enter < "10:00:00") # fraction entering before 10am

sum(Exit >  "17:00:00") # no exiting after 5pm
mean(Exit >  "17:00:00") # fraction exiting after 5pm

table(cut(hours(Enter), breaks = c(0, 10, 17, 24))) # Counts for indicated hours   
 ## (0,10] (10,17] (17,24] 
 ##      1       1       0 

table(hours(Enter))  # Counts of entries each hour
## 9 17 
## 1  1

stem(hours(Enter), scale = 2)
## The decimal point is at the |

##   9 | 0
##  10 | 
##  11 | 
##  12 | 
##  13 | 
##  14 | 
##  15 | 
##  16 | 
##  17 | 0

图形:

tab <- c(table(Enter), -table(Exit))  # Freq at each time.  Enter is pos; Exit is neg.
plot(times(names(tab)), tab, type = "h", xlab = "Time", ylab = "Freq")
abline(v = c(10, 17)/24, col = "red", lty = 2) # vertical red lines
abline(h = 0)  # X axis

【讨论】:

    【解决方案3】:

    这样的东西有用吗?

    SubstracTimes <-  function(TimeEnter, TimeExit){
      (as.numeric(format(strptime(TimeExit, format ="%H:%M"), "%H")) + 
      as.numeric(format(strptime(TimeExit, format ="%H:%M"), "%M"))/60) -
      (as.numeric(format(strptime(TimeEnter, format ="%H:%M"), "%H")) + 
       as.numeric(format(strptime(TimeEnter, format ="%H:%M"), "%M"))/60)
    }
    

    测试:

    TimeEnter <- "08:02"
    TimeExit <- "12:02"
    SubstracTimes(TimeEnter, TimeExit)
    > SubstracTimes(TimeEnter, TimeExit)
    [1] 4
    

    【讨论】:

    • 这适用于加/减,并返回十进制小时数(即 3.5 而不是 3:30)。对于绘图,也许我可以手动为箱分配值,以便绘制输入频率与时间的关系。
    • 也许提供一些示例数据集并准确解释您想要绘制的内容以及预期结果是什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 2017-01-01
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多