Zpět na přehled cvičení

Rkový skript ke stažení: R

Co si zde představíme?

Datum v Rku

Základním datovým typem pro práci s datumy je třída Date:

datum <- as.Date(c("1999-03-29", "2001-12-31", "2025-10-01", "1969-01-01", "1968-01-01"))
print(datum)               # základní formát YYYY-MM-DD
## [1] "1999-03-29" "2001-12-31" "2025-10-01" "1969-01-01" "1968-01-01"
summary(datum)             # základní popisné charakteristiky
##         Min.      1st Qu.       Median         Mean      3rd Qu.         Max. 
## "1968-01-01" "1969-01-01" "1999-03-29" "1992-10-18" "2001-12-31" "2025-10-01"
as.numeric(datum)          # počet dní od "1970-01-01" - interní reprezentace data  
## [1] 10679 11687 20362  -365  -731
as.Date(0)
## [1] "1970-01-01"

Data lze pochopitelně přijmout pod jiným formátem:

datum2 <- as.Date(c("29/03/99", "31/12/00", "01/10/25", "01/01/69", "01/01/68"), format = "%d/%m/%y")
print(datum2)               # vytiskne v základním formátu (pozor na krátký formát roku %y)
## [1] "1999-03-29" "2000-12-31" "2025-10-01" "1969-01-01" "2068-01-01"

Formát data se dá změnit do různých podob:

format(datum, "%Y-%m-%d")  # defaultní nastavení
## [1] "1999-03-29" "2001-12-31" "2025-10-01" "1969-01-01" "1968-01-01"
format(datum, "%d-%m-%Y")  # den, měsíc, rok
## [1] "29-03-1999" "31-12-2001" "01-10-2025" "01-01-1969" "01-01-1968"
format(datum, "%d-%m-%y")  # rok jen na dvě poslední čísla
## [1] "29-03-99" "31-12-01" "01-10-25" "01-01-69" "01-01-68"
format(datum, "%D")        # americký formát pro měsíc/den/rok  
## [1] "03/29/99" "12/31/01" "10/01/25" "01/01/69" "01/01/68"
format(datum, "%m/%d/%Y")  # to samé - měsíc, den, rok
## [1] "03/29/1999" "12/31/2001" "10/01/2025" "01/01/1969" "01/01/1968"

Z datumu lze jednoduše vyseparovat den v týdnu, měsíc či čtvrtletí:

Sys.getlocale("LC_TIME")              # jazyk v závislosti na nastaveném locale 
## [1] "Czech_Czechia.utf8"
weekdays(datum)
## [1] "pondělí" "pondělí" "středa"  "středa"  "pondělí"
weekdays(datum, abbreviate = TRUE)
## [1] "po" "po" "st" "st" "po"
months(datum)
## [1] "březen"   "prosinec" "říjen"    "leden"    "leden"
months(datum, abbreviate = TRUE)
## [1] "bře" "pro" "říj" "led" "led"
quarters(datum)
## [1] "Q1" "Q4" "Q4" "Q1" "Q1"

Díky reprezentaci jako počet dní od 1970-01-01 lze jednoduše operovat s časem:

datum + 365                   # datum o 365 dní později
## [1] "2000-03-28" "2002-12-31" "2026-10-01" "1970-01-01" "1968-12-31"
datum - 1                     # datum předchozího dne
## [1] "1999-03-28" "2001-12-30" "2025-09-30" "1968-12-31" "1967-12-31"
difftime(datum, "2000-01-01") # počet dní od konkrétního data
## Time differences in days
## [1]   -277.9583    730.0417   9405.0417 -11321.9583 -11687.9583

Datum a čas pomocí POSIX

Současný čas lze získat následujícím způsobem:

(ted <- Sys.time())
## [1] "2025-09-29 17:49:36 CEST"
class(ted)
## [1] "POSIXct" "POSIXt"
as.numeric(ted)   # počet sekund od následujícího data
## [1] 1759160977
as.POSIXct(0)
## [1] "1970-01-01 01:00:00 CET"

POSIX a jeho varianty je obecnější třída datumu, která uvažuje nejen datum, ale i konkrétní čas na sekundy přesně včetně určení časové zóny. Jeho local time verze funguje jako list s následujícími položkami:

tedlt <- as.POSIXlt(ted) # z ct (calendar time) do lt (local time)
tedlt$sec    # 0–61: sekundy (včetně zlomků vteřiny)
## [1] 36.98691
tedlt$min    # 0–59: minuty
## [1] 49
tedlt$hour   # 0–23: hodiny
## [1] 17
tedlt$wday   # 0-6: den v týdnu počínaje nedělí
## [1] 1
tedlt$mday   # 1-31: den v měsíci
## [1] 29
tedlt$yday   # 0-365: den v roce
## [1] 271
tedlt$mon    # 0-11: měsíců po prvním měsíci v roce
## [1] 8
tedlt$year   # let od 1900
## [1] 125
tedlt$isdst  # Day-Saving-Time - 1 = letní čas, 0 = zimní čas, -1 = neznámo
## [1] 1
tedlt$zone   # časové pásmo
## [1] "CEST"
tedlt$gmtoff # odchylka v sekundách od GMT, NA či 0 znamenají neznámé
## [1] 7200

Tyto třídy mají své vlastní speciální funkce:

trunc(tedlt, units = "hours")   # useknutí nižších jednotek
## [1] "2025-09-29 17:00:00 CEST"
round(tedlt, units = "days")    # zaokrouhlení na dané jednotky
## [1] "2025-09-30 CEST"
# Vygenerování aritmetické posloupnosti časů
posloupnost_dni <- seq(from = as.Date("1970-01-01"), to = as.Date("1970-12-31"), by = "day")
posloupnost_tydnu <- seq(from = as.Date("1970-01-01"), to = as.Date("1970-12-31"), by = "week")
posloupnost_po5dnech <- seq(from = as.Date("1970-01-01"), to = as.Date("1970-12-31"), by = 5)    
posloupnost_posekundach <- seq(from = as.POSIXct("1970-01-01"), to = as.POSIXct("1970-12-31"), by = 123456) 
posloupnost_odelce11 <- seq(from = as.Date("1970-01-01"), to = as.Date("1970-12-31"), length.out = 11)
# Konverze zadaných datumů na faktorovou proměnnou dle zadaných intervalů
fposloupnost_po5dnech <- cut(posloupnost_po5dnech,              # hodnoty ke kategorizování
                             breaks = posloupnost_odelce11,     # meze intervalů
                             right = FALSE)                     # převod na faktor
fposloupnost_po5dnech_tydne <- cut(posloupnost_po5dnech,        # hodnoty ke kategorizování
                                   breaks = "weeks",            # meze intervalů lze udat i v jednotkách
                                   start.on.monday = TRUE,      # zda by týden měl začít pondělkem
                                   right = FALSE)               # převod na faktor

Speciální třídou v říši datumů a časů je difftime udávající rozdíl mezi dvěma časy:

(autodif <- difftime(ted + 12345, ted, units = "auto"))    # automatické určení vhodné jednotky 
## Time difference of 3.429167 hours
difftime(ted + 12345, ted, units = "secs")
## Time difference of 12345 secs
difftime(ted + 12345, ted, units = "mins")
## Time difference of 205.75 mins
difftime(ted + 12345, ted, units = "hours")
## Time difference of 3.429167 hours
difftime(ted + 12345, ted, units = "days")
## Time difference of 0.1428819 days
difftime(ted + 12345, ted, units = "weeks")
## Time difference of 0.02041171 weeks
units(autodif) <- "mins"                         # změna jednotek v uložené proměnné třídy difftime
autodif                                          # class difftime má svůj speciální print
## Time difference of 205.75 mins
as.character(autodif)                            # jako string jen pouhé číslo
## [1] "205.75"
as.numeric(autodif, units = "days")              # převod na číslo včetně jednotky
## [1] 0.1428819

Proměnná typu difftime se dá použít jako argument by při tvorbě aritmetické posloupnosti pomocí seq:

cas1 <- as.POSIXct("2025-09-30 09:01:25")
cas2 <- as.POSIXct("2025-09-30 11:58:47")
doba <- difftime(cas2, cas1)
seq(as.POSIXct("2025-09-30 09:00:00"), as.POSIXct("2025-09-30 19:00:00"), by = doba)
## [1] "2025-09-30 09:00:00 CEST" "2025-09-30 11:57:22 CEST" "2025-09-30 14:54:44 CEST"
## [4] "2025-09-30 17:52:06 CEST"

Lze také uměle zkonstruovat následovně (třeba výkon v atletice):

as.difftime(123, units = "secs")            # převodem konkrétního čísla v jednotkách
## Time difference of 123 secs
as.difftime(123, units = "mins")
## Time difference of 123 mins
as.difftime("00:54:13")                     # defaultní formát času
## Time difference of 54.21667 mins
wr100m <- as.difftime("00:00:09.58")        # světový rekord v běhu na 100 m 
as.numeric(wr100m)                          # zápis ignoruje desetiny
## [1] 9
as.difftime(9.58, units = "secs")           # takto to funguje jednoduše
## Time difference of 9.58 secs
as.difftime("00:09.52", format = "%M:%OS")  # při převodu ze stringu je třeba upravit očekávaný formát
## Time difference of 9.52 secs
as.difftime("01:30", format = "%H:%M")      # čas s přesností na minuty
## Time difference of 1.5 hours

Výpočetní čas

Až jednou budete provádět simulační studii nebo si budete chtít dopředu odhadnout, jak dlouho budou Vaše výpočty trvat, můžete použít system.time():

vypocetni_cas <- system.time({
  x <- rnorm(2e7)
  y <- log(abs(sin(exp(x))))
})
vypocetni_cas
##    user  system elapsed 
##    1.84    0.17    1.83

Úložky na procvičení

Vyřešte si to sami, aniž byste se dívali do řešení (úplně dole vespod skriptu).

  1. Porovnejte časovou náročnost výpočtů provedených pomocí for cyklu a pomocí apply reformulací.
  2. Rkový balíček survival určený pro analýzu přežití (NMST511) obsahuje dva datasety: jasa a heart. Druhý jmenovaný je zkonstruován z toho prvního jednoduchými transformacemi. Z časových údajů obsažených v originálním jasa napočítejte pro každého pacienta následující:
library(survival)
head(jasa)            # původní originální data (1 řádek na pacienta)
##     birth.dt  accept.dt    tx.date    fu.date fustat surgery      age futime wait.time transplant mismatch
## 1 1937-01-10 1967-11-15       <NA> 1968-01-03      1       0 30.84463     49        NA          0       NA
## 2 1916-03-02 1968-01-02       <NA> 1968-01-07      1       0 51.83573      5        NA          0       NA
## 3 1913-09-19 1968-01-06 1968-01-06 1968-01-21      1       0 54.29706     15         0          1        2
## 4 1927-12-23 1968-03-28 1968-05-02 1968-05-05      1       0 40.26283     38        35          1        3
## 5 1947-07-28 1968-05-10       <NA> 1968-05-27      1       0 20.78576     17        NA          0       NA
## 6 1913-11-08 1968-06-13       <NA> 1968-06-15      1       0 54.59548      2        NA          0       NA
##   hla.a2 mscore reject
## 1     NA     NA     NA
## 2     NA     NA     NA
## 3      0   1.11      0
## 4      0   1.66      0
## 5     NA     NA     NA
## 6     NA     NA     NA
head(heart)           # modifikovaná data vhodně upravená pro analýzu (1-2 řádky pro pacienta)
##   start stop event        age      year surgery transplant id
## 1     0   50     1 -17.155373 0.1232033       0          0  1
## 2     0    6     1   3.835729 0.2546201       0          0  2
## 3     0    1     0   6.297057 0.2655715       0          0  3
## 4     1   16     1   6.297057 0.2655715       0          1  3
## 5     0   36     0  -7.737166 0.4900753       0          0  4
## 6    36   39     1  -7.737166 0.4900753       0          1  4
help(heart)           # zde naleznete vysvětlení jednotlivých proměnných
  1. Nagenerujte si dataset lidí s náhodnými daty narození a daty vstupu do studie. (Je třeba umět generovat náhodná čísla, nejprve se seznamte s dalším cvičením.) Spočtěte věk člověka v době vstupu do studie.