Claudio
Claudio

Reputation: 63

How can I convert a time shown as a character into time value with R?

I have a dataset calles marathon and I have tried to use lubridate and churn to convert the characters of marathon$Official.Time into time value in order to work on them. I would like the times to be shown in minutes (meaning that 2 hours are shown as 120 minutes).

data.frame':    5616 obs. of  11 variables:
$ Overall.Position : int  1 2 3 4 5 6 7 8 9 10 ...
$ Gender.Position  : int  1 2 3 4 5 6 7 8 9 10 ...
$ Category.Position: int  1 1 2 2 3 4 3 4 5 5 ...
$ Category         : chr  "MMS" "MMI" "MMI" "MMS" ...
$ Race.No          : int  21080 14 2 21077 18 21 21078 21090 21084 12 ...
$ Country          : chr  "Kenya" "Kenya" "Ethiopia" "Kenya" ...
$ Official.Time    : chr  "2:12:12" "2:12:14" "2:12:20" "2:12:29" ...

I tried with:

  library(lubridate)
  times(marathon$Official.Time) 

Or

  library(chron)
  chron(times=marathon$Official.Time)
  as.difftime(marathon$Official.Time, units = "mins")

But I only get NA

Upvotes: 1

Views: 1188

Answers (2)

hrbrmstr
hrbrmstr

Reputation: 78792

NOTE: @mathemetical.coffee's solution is ++gd better than these.


Pretty straightforward to kick it out manually:

library(stringi)
library(purrr)

df <- data.frame(Official.Time=c("2:12:12","2:12:14","2:12:20","2:12:29"),
                 stringsAsFactors=FALSE)

map(df$Official.Time, function(x) {
  stri_split_fixed(x, ":")[[1]] %>%
    as.numeric() %>%
    `*`(c(60, 1, 1/60)) %>%
    sum()
}) -> df$minutes

df
##   Official.Time  minutes
## 1       2:12:12    132.2
## 2       2:12:14 132.2333
## 3       2:12:20 132.3333
## 4       2:12:29 132.4833

You can also do it with just base R operations and w/o "piping":

df$minutes <- sapply(df$Official.Time, function(x) {

 x <- strsplit(x, ":", TRUE)[[1]]
 x <- as.numeric(x)
 x <- x * (c(60, 1, 1/60))

 sum(x)

}, USE.NAMES=FALSE)

If "stuck" with base R then I'd prbly actually do:

vapply(df$Official.Time, function(x) {

 x <- strsplit(x, ":", TRUE)[[1]]
 x <- as.numeric(x)
 x <- x * (c(60, 1, 1/60))

 sum(x)

}, double(1), USE.NAMES=FALSE)

to ensure type safety.

But, chron can also be used:

library(chron)

60 * 24 * as.numeric(times(df$Official.Time))

NOTE that lubridate has no times() function.

Upvotes: 0

mathematical.coffee
mathematical.coffee

Reputation: 56905

You were almost there with difftime (which requires two times and gives you the difference). Instead, use as.difftime (which requires one "difference" - ie marathon time) and specify the format as hours:minutes:seconds.

> as.difftime("2:12:12", format="%H:%M:%S", units="mins")
Time difference of 132.2 mins
> as.numeric(as.difftime("2:12:12", format="%H:%M:%S", units="mins"))
[1] 132.2

No extra packages needed.

Upvotes: 1

Related Questions