Calculer proprement un âge sous R

Divers

Le calcul d’un âge sous R n’est pas forcément aussi trivial qu’il n’y parait.

Rappel sur les âges

Il convient en premier lieu de rappeler les principaux âges utilisés les démographes :

L’âge — on précise parfois âge chronologique — est une des caractéristiques fondamentales de la structure des populations.
On l’exprime généralement en années, ou en années et mois, voire en mois et jours, pour les enfants en bas âge ; parfois en années et fractions décimales d’année. Les démographes arrondissent d’ordinaire l’âge à l’unité inférieure, l’exprimant ainsi en années révolues, ou années accomplies, le cas échéant en mois révolus, ou mois accomplis. Cet âge est aussi l’âge au dernier anniversaire. On trouve aussi, dans les statistiques, l’âge atteint dans l’année, qui est égal à la différence de millésimes entre l’année considérée et l’année de naissance. [...] On est parfois conduit à préciser que l’on considère un âge exact, pour éviter toute confusion avec un âge en années révolues, qui représente en fait une classe d’âges exacts.

Source : Demopædia (322)

Le package lubridate

Le package lubridate est spécialement développé pour faciliter la manipulation et le calcul autour des dates. La version de développement intègre depuis peu une fonction time_length adaptée au calcul des âges exacts.

Pour installer la version de développement de lubridate, on aura recours au package devtools :

library(devtools)
install_github('hadley/lubridate')
library(lubridate)

Nous noterons naiss la date de naissance et evt la date à laquelle nous calculerons l’âge.

Calcul d’un âge exact

Une approche simple consiste à calculer une différence en jours puis à diviser par 365. Or, le souci c’est que toutes les années n’ont pas le même nombre de jours. Regardons par exemple ce qui se passe si l’on calcule l’âge au 31 décembre 1999 d’une personne née le 1er janvier 1900.

naiss <- ymd("1900-01-01")
evt <- ymd("1999-12-31")
time_length(interval(naiss, evt), "days")
## [1] 36523
time_length(interval(naiss, evt), "days") / 365
## [1] 100.063

Or, au 31 décembre 1999, cette personne n’a pas encore fêté son centième anniversaire. Le calcul précédent ne prend pas en compte les années bissextiles. Une approche plus correcte serait de considérer que les années durent en moyenne 365,25 jours.

time_length(interval(naiss, evt), "days") / 365.25
## [1] 99.99452

Si cette approche fonctionne avec cet exemple, ce n’est plus le cas dans d’autres situations.

evt <- ymd("1903-01-01")
time_length(interval(naiss, evt), "days") / 365.25
## [1] 2.997947

Or, à la date du premier janvier 1903, cette personne a fêté son troisième anniversaire.

Pour calculer proprement un âge en années (ou en mois), il est dès lors nécessaire de prendre en compte la date anniversaire et le fait que la durée de chaque année (mois) est variable. C’est justement ce que fait la fonction time_length appliquée à un objet de type interval. On détermine le dernier et le prochain anniversaire et l’on rajoute, à l’âge atteint au dernier anniversaire, le ratio entre le nombre de jours entre l’événement et le dernier anniversaire par le nombre de jour entre le prochain et le dernier anniversaire.

naiss <- ymd("1900-01-01")
evt <- ymd("1999-12-31")
time_length(interval(naiss, evt), "years")
## [1] 99.99726
evt <- ymd("1903-01-01")
time_length(interval(naiss, evt), "years")
## [1] 3
evt <- ymd("1918-11-11")
time_length(interval(naiss, evt), "years")
## [1] 18.86027

Attention, cela n’est valable que si l’on présente à la fonction time_length un objet de type interval (pour lequel on connait dès lors la date de début et la date de fin). Si l’on passe une durée à la fonction time_length, le calcul s’effectuera alors en prenant en compte la durée moyenne d’une année.

naiss <- ymd("1900-01-01")
evt <- ymd("1999-12-31")
 time_length(interval(naiss, evt), "years")
## [1] 99.99726
time_length(evt - naiss, "years")
## [1] 100.063
time_length(as.duration(interval(naiss, evt)), "years")
## [1] 100.063

Cas particulier des personnes nées un 29 février

Pour les personnes nées un 29 février, il existe un certain flou concernant leur date d’anniversaire pour les années non bissextiles. Doit-on considérer qu’il s’agit du 28 février ou du 1er mars ?

Au sens strict, on peut considérer que leur anniversaire a lieu entre le 28 février soir à minuit et le 1er mars à 0 heure matin, autrement dit que le 28 février ils n’ont pas encore fêté leur anniversaire. C’est la position adoptée par la fonction time_length.

naiss <- ymd("1992-02-29")
evt <- ymd("2014-02-28")
time_length(interval(naiss, evt), "years")
## [1] 21.99726
evt <- ymd("2014-03-01")
time_length(interval(naiss, evt), "years")
## [1] 22

Cette approche permets également d’être cohérent avec la manière dont les dates sont prises en compte informatiquement. On considère en effet que lorsque seule la date est précisée (sans mention de l’heure), l’heure correspondante est 0:00. Autrement dit, "2014-03-01" est équivalent à "2014-03-01 00:00:00". L’approche adoptée permet donc d’être cohérent lorsque l’anniversaire est calculé en tenant compte des heures.

naiss <- ymd("1992-02-29")
evt <- ymd_hms("2014-02-28 23:00:00")
time_length(interval(naiss, evt), "years")
## [1] 21.99989
evt <- ymd_hms("2014-03-01 00:00:00")
time_length(interval(naiss, evt), "years")
## [1] 22
evt <- ymd_hms("2014-03-01 01:00:00")
time_length(interval(naiss, evt), "years")
## [1] 22.00011
naiss <- ymd_hms("1992-02-29 12:00:00")
evt <- ymd_hms("2014-03-01 01:00:00")
time_length(interval(naiss, evt), "years")
## [1] 22.00011

Âge révolu ou âge au dernier anniversaire

Une fois que l’on sait calculer un âge exact, le calcul d’un âge révolu est assez simple. Il suffit de ne garder que la partie entière de l’âge exact (approche conseillée).

naiss <- ymd("1980-01-09")
evt <- ymd("2015-01-01")
time_length(interval(naiss, evt), "years")
## [1] 34.97808
trunc(time_length(interval(naiss, evt), "years"))
## [1] 34

Une autre approche consiste à convertir l’interval en objet de type période et à ne prendre en compte que les années.

as.period(interval(naiss, evt))
## [1] "34y 11m 23d 0H 0M 0S"
as.period(interval(naiss, evt))@year
## [1] 34

Âge par différence de millésimes

L’âge par différence de millésimes, encore appelé âge atteint dans l’année, s’obtient tout simplement en soustrayant l’année de naissance à l’année de l’événement.

naiss <- ymd("1980-01-09")
evt <- ymd("2015-01-01")
year(evt)-year(naiss)
## [1] 35

Notes

L’ensemble des fonctions présentées peuvent être appliquées à des vecteurs et, par conséquent, aux colonnes d’un tableau de données (data.frame).

Le package epptools fournit de son côté une fonction age_calc (https://github.com/jknowles/eeptool...) qui permet le calcul des âges exacts et révolus.

source("https://raw.githubusercontent.com/jknowles/eeptools/master/R/age_calc.R")
naiss <- as.Date("1980-01-09")
evt <- as.Date("2015-01-01")
age_calc(naiss, evt, units = "years", precise = TRUE)
## [1] 34.97814

En l’absence du package lubridate, il reste facile de calculer une durée en jours avec les fonctions de base de R.

naiss <- as.Date("1900-01-01")
evt <- as.Date("1999-12-31")
evt - naiss
## Time difference of 36523 days
as.integer(evt - naiss)
## [1] 36523