Running pace and time calculator function for R

With an upcoming half-marathon, I went looking online for a good race time and race pace calculator (of which there are some good simple ones and some more interesting ones). But let’s face it. What I really wanted was an R function but I couldn’t find one out there. So I made a couple functions that maybe I’ll package up and post to CRAN someday. In the meantime, here they are.

What you do with these splits is, of course, up to you. I suppose the nouveaux thing is to program the virtual partner on your Garmin to match your desired pace. That way, you can play a real-life video game and run at the same time. Win-win. Alternatively, you can use any number of old-school approaches to carry all your splits with you on your run (then  argue discuss online about your favourite split-carrying method ad nauseam). But I digress.

photo 1

Back in the day before Garmins and Virutal Partners, we had Sharpies. (Photo: NACN)

Technical note: I decided to build the functions on seconds as a time unit. I find working with date and time objects and such in R really tricky (and somewhat overcomplicated for this application). So the math is done on seconds and the times/paces are reported as character vectors in the format “mm:ss”. This can be annoying if you want to do something with the numbers after the fact but I leave it to you to convert the character to date/time format.

There are two main functions here:

  1. The calcTime function takes a race distance (in mi or km) and a pace (in min/mi or min/km, consistent with the distance input) and calculates a total time.
  2. The calcPace function takes a race distance (in mi or km, which you specify)  and a race time in mm:ss and calculates pace in both min/mi and min/km. It also outputs tables of race time per mi or per km and for the finish distance.

Because of the formatting weirdness, both main functions (calcTime and calcPace) require the use of a third function CharMinSec, which converts seconds (numeric) to “mm:ss” (character). This function is embedded in the other two functions, just FYI.

calcTime to calculate a total race time from a /mi or /km pace:

# Calculate total race time from pace
calcTime <- function(racePace, raceDistance){
 
  # racePace is the per unit pace in mm:ss - character
  # raceDistance is the total race distance - numeric
  # Pace and race distance must use same units (km or mi or whatever)
 
  # Seconds to character time function
  CharMinSec <- function(sec){
    outMin <- floor(sec/60)
    outSec <- ((sec/60)-outMin)*60
    if(outSec==0 | round(outSec)<10){
      outChar <- paste0(outMin,":0",round(outSec))
    } else {
      outChar <- paste(outMin,round(outSec),sep=":")
    }
    outChar
  }
 
  paceMinSec <- as.numeric(strsplit(racePace,':')[[1]])
  paceSec <- paceMinSec[1]*60+ paceMinSec[2]
  raceMin <- floor(paceSec*raceDistance/60)
  raceSec <- ((paceSec*raceDistance/60)-raceMin)*60
  raceTime <- CharMinSec(raceMin*60+raceSec)
  list(TotalTime=raceTime, Minutes=raceMin, Seconds=raceSec)
}

# Example of 4:15/km for a half-marathon
# (Since we're being a bit nerdy anyway, let's get nerdy about the distance too.)
calcTime("4:15",21.097494)

$TotalTime
[1] "89:40"
$Minutes
[1] 89
$Seconds
[1] 39.86097

# Example of 6:45/mi for a 5 miler
calcTime("7:45", 5)

$TotalTime
[1] "38:45"
$Minutes
[1] 38
$Seconds
[1] 45

calcPace to calculate a /mi or /km pace from a race time and distance and to create race time tables by mi or km:

# Calculate pace from total race time
calcPace <- function(raceDistance, raceTime, raceUnits){
 
  # raceDistance is the total race distance (in km or mi) - numeric
  # raceTime is the total goal time of the race (in MM:SS) - character
  # raceUnits is the distance units of raceDistance (either "km" or "mi")
 
  # Seconds to character time function
  CharMinSec <- function(sec){
    outMin <- floor(sec/60)
    outSec <- ((sec/60)-outMin)*60
    if(outSec==0 | round(outSec)<10){
      outChar <- paste0(outMin,":0",round(outSec))
    } else {
      outChar <- paste(outMin,round(outSec),sep=":")
    }
    outChar
  }
 
  minsec <- as.numeric(strsplit(raceTime,':')[[1]])
  sec <- minsec[1]*60+ minsec[2]
 
  # race distances
  if(raceUnits=="mi"){
    kmDist <- round(raceDistance*1.609344,2)
    miDist <- round(raceDistance,2) 
  } else {
    kmDist <- round(raceDistance,2)
    miDist <- round(raceDistance*0.62137119,2)
  }

  # km pace
  secPerKM <- sec/kmDist
  paceKM <- CharMinSec(secPerKM)
  # mi pace
  secPerMI <- sec/miDist
  paceMI <- CharMinSec(secPerMI)
 
  # km splits
  splitKM <- data.frame(km=c(1:floor(kmDist),kmDist))
  splitKM$min <- floor(secPerKM/60*splitKM$km)
  splitKM$sec <- round(secPerKM*splitKM$km - splitKM$min*60)
  splitKM$time <- lapply(secPerKM*splitKM$km, CharMinSec)
  # mi splits
  splitMI <- data.frame(mile=c(1:floor(miDist),miDist))
  splitMI$min <- floor(secPerMI/60*splitMI$mile)
  splitMI$sec <- round(secPerMI*splitMI$mile - splitMI$min*60)
  splitMI$time <- lapply(secPerMI*splitMI$mile, CharMinSec)
 
  # output
  list(km_pace=paceKM, km_splits=splitKM, mi_pace=paceMI, mi_splits=splitMI)
}

# Example for a 90min half-marathon
calcPace(21.097494, "90:00", "km")

$km_pace
[1] "4:16"

$km_splits
    km min sec  time
1  1.0   4  16  4:16
2  2.0   8  32  8:32
3  3.0   12 48 12:48
4  4.0   17  4 17:04
5  5.0   21 20 21:20
6  6.0   25 36 25:36
7  7.0   29 51 29:51
8  8.0   34  7 34:07
9  9.0   38 23 38:23
10 10.0  42 39 42:39
11 11.0  46 55 46:55
12 12.0  51 11 51:11
13 13.0  55 27 55:27
14 14.0  59 43 59:43
15 15.0  63 59 63:59
16 16.0  68 15 68:15
17 17.0  72 31 72:31
18 18.0  76 47 76:47
19 19.0  81  3 81:03
20 20.0  85 18 85:18
21 21.0  89 34 89:34
22 21.1  89 60 90:00

$mi_pace
[1] "6:52"

$mi_splits
    mile min sec  time
1   1.00   6  52  6:52
2   2.00  13  44 13:44
3   3.00  20  36 20:36
4   4.00  27  28 27:28
5   5.00  34  19 34:19
6   6.00  41  11 41:11
7   7.00  48   3 48:03
8   8.00  54  55 54:55
9   9.00  61  47 61:47
10 10.00  68  39 68:39
11 11.00  75  31 75:31
12 12.00  82  23 82:23
13 13.00  89  15 89:15
14 13.11  90   0 90:00

# Example for a 40min 5-miler
calcPace(5, "38:00", "mi")

$km_pace
[1] "4:43"

$km_splits
    km min sec  time
1 1.00   4  43  4:43
2 2.00   9  26  9:26
3 3.00  14  10 14:10
4 4.00  18  53 18:53
5 5.00  23  36 23:36
6 6.00  28  19 28:19
7 7.00  33   3 33:03
8 8.00  37  46 37:46
9 8.05  37  60 38:00

$mi_pace
[1] "7:36"

$mi_splits
  mile min sec  time
1    1   7  36  7:36
2    2  15  12 15:12
3    3  22  48 22:48
4    4  30  24 30:24
5    5  38   0 38:00
6    5  38   0 38:00

It might be fun to include some more complicated calculations in a complete R package, like the run-walk calculator, or the age-grade estimator (I hesitate to call this a “calculator”). If I find myself unemployed or on a long flight, I’m on it.

Advertisements
This entry was posted in R, Sports and tagged , , , , , , , , , . Bookmark the permalink.

One Response to Running pace and time calculator function for R

  1. Pingback: Cycling gear ratio calculator for R (or why you should just go buy a SRAM Eagle 1×12 group right now) | David R. Roberts

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s