R-ohjelmointi.org

Tilastotieteellistä ohjelmointia R-kielellä

Henkilön iän laskeminen vuosissa

Työssäni melko usein vastaan tuleva ongelma on henkilön iän laskeminen vuosissa hänen syntymäaikansa perusteella. Ongelma on R:ssä yllättävän vaikea ratkaista, jos haluaa iän samalla tavalla laskettuna kuin henkilö sen kalenteria käyttäen laskisi. Oikea ratkaisu myös unohtuu ainakin minulta aina käyttökertojen välissä.

Oletetaan, että henkilö on syntynyt 1982-08-09 ja nykyinen päiväys on 2012-08-09. Usein näkee käytettävän karkeana arviona seuraavaa menetelmää:

birth<-c("1982-08-09")
current<-c("2012-08-09")
floor(as.numeric(as.Date(current)-as.Date(birth)) / 365.25)
[1] 30

Tämä antaa kyseisessä tapauksessa järkevän vastauksen, mutta entäs jos nyt on 2008-02-28 ja henkilö syntyi 2007-02-28. Tuloksena on nolla, joten ko. ratkaisu ei toimi kaikissa tapauksissa luotettavasti!

Saman voisi toteuttaa myös difftime()-funktiolla, joka antaa määritellä päivämäärävälin pituuden yksikön, mutta yksiköksi ei voi määritellä vuotta.

Toinen usein ehdotettu ratkaisu käyttää lubridate-pakettia:

library(lubridate)
floor(new_interval(as.POSIXct(birth, tz="GMT"), as.POSIXct(current, tz="GMT")) / duration(num = 1, units = "years"))
[1] 30

Tämä antaa oikean vastauksen myös jälkimmäisen esimerkin tapauksessa, mutta hieman häiritsevästi se vaatii vuosien pyöristämistä alaspäin, sillä pelkän jakolaskun antama vastaus on hieman oikeaa vastausta suurempi (30.02192). Jos henkilön syntymäpäivä olisi säilynyt samana (1982-08-09), mutta nyt olisi 2012-08-08 eli päivä ennen henkilö 30. syntymäpäivää, antaisi tämäkin ratkaisumalli kuitenkin väärän vastauksen:

floor(new_interval(as.POSIXct(birth, tz="GMT"), as.POSIXct("2012-08-08", tz="GMT")) / duration(num = 1, units = "years"))
[1] 30

Tämäkään ratkaisumalli ei siis toimi oikein kaikissa tilanteissa!

Löysinkin parhaiten soveltuvan ratkaisun ongelmaan vanhasta R-help -postilistan viestistä. Brian D. Ripley antoi viestissä funktion age_years() koodin:

age_years <- function(from, to) 
{ 
     lt <- as.POSIXlt(c(from, to)) 
     age <- lt$year[2] - lt$year[1] 
     mons <- lt$mon + lt$mday/50 
     if(mons[2] < mons[1]) age <- age -1 
     age 
} 
age_years(birth, current)
[1] 30
 
age_years(birth, "2012-08-08")
[1] 29

Tuolla B. D. Ripleyn tekemällä funktiolla kaikki testaamani laskutoimitukset tuntuvat toimivan oikein.


Category