回答
從this blog entry的評論,我發現eeptools
包中的age_calc
函數。它處理邊緣情況(閏年等),檢查輸入並看起來相當健壯。
library(eeptools)
x <- as.Date(c("2011-01-01", "1996-02-29"))
age_calc(x[1],x[2]) # default is age in months
[1] 46.73333 224.83118
age_calc(x[1],x[2], units = "years") # but you can set it to years
[1] 3.893151 18.731507
floor(age_calc(x[1],x[2], units = "years"))
[1] 3 18
爲您的數據
yourdata$age <- floor(age_calc(yourdata$birthdate, units = "years"))
假設你想在整數歲。
假設你有一個data.table,你可以做如下:
library(data.table)
library(lubridate)
# toy data
X = data.table(birth=seq(from=as.Date("1970-01-01"), to=as.Date("1980-12-31"), by="year"))
Sys.Date()
方法1:使用 「as.period」 從lubriate包
X[, age := as.period(Sys.Date() - birth)][]
birth age
1: 1970-01-01 44y 0m 327d 0H 0M 0S
2: 1971-01-01 43y 0m 327d 6H 0M 0S
3: 1972-01-01 42y 0m 327d 12H 0M 0S
4: 1973-01-01 41y 0m 326d 18H 0M 0S
5: 1974-01-01 40y 0m 327d 0H 0M 0S
6: 1975-01-01 39y 0m 327d 6H 0M 0S
7: 1976-01-01 38y 0m 327d 12H 0M 0S
8: 1977-01-01 37y 0m 326d 18H 0M 0S
9: 1978-01-01 36y 0m 327d 0H 0M 0S
10: 1979-01-01 35y 0m 327d 6H 0M 0S
11: 1980-01-01 34y 0m 327d 12H 0M 0S
選項2:如果你不知道就像選項1的格式一樣,你可以這樣做:
yr = duration(num = 1, units = "years")
X[, age := new_interval(birth, Sys.Date())/yr][]
# you get
birth age
1: 1970-01-01 44.92603
2: 1971-01-01 43.92603
3: 1972-01-01 42.92603
4: 1973-01-01 41.92329
5: 1974-01-01 40.92329
6: 1975-01-01 39.92329
7: 1976-01-01 38.92329
8: 1977-01-01 37.92055
9: 1978-01-01 36.92055
10: 1979-01-01 35.92055
11: 1980-01-01 34.92055
相信選項2應該是更可取的。
我一直在想這件事,並且對迄今爲止的兩個答案感到不滿。我喜歡使用lubridate
,正如@KFB所做的那樣,但我也希望事情能夠很好地包裝在一個函數中,就像我在使用eeptools
包的答案中一樣。因此,這裏的使用lubridate區間方法與一些不錯的選擇包裝函數:
#' Calculate age
#'
#' By default, calculates the typical "age in years", with a
#' \code{floor} applied so that you are, e.g., 5 years old from
#' 5th birthday through the day before your 6th birthday. Set
#' \code{floor = FALSE} to return decimal ages, and change \code{units}
#' for units other than years.
#' @param dob date-of-birth, the day to start calculating age.
#' @param age.day the date on which age is to be calculated.
#' @param units unit to measure age in. Defaults to \code{"years"}. Passed to \link{\code{duration}}.
#' @param floor boolean for whether or not to floor the result. Defaults to \code{TRUE}.
#' @return Age in \code{units}. Will be an integer if \code{floor = TRUE}.
#' @examples
#' my.dob <- as.Date('1983-10-20')
#' age(my.dob)
#' age(my.dob, units = "minutes")
#' age(my.dob, floor = FALSE)
age <- function(dob, age.day = today(), units = "years", floor = TRUE) {
calc.age = interval(dob, age.day)/duration(num = 1, units = units)
if (floor) return(as.integer(floor(calc.age)))
return(calc.age)
}
使用示例:
> my.dob <- as.Date('1983-10-20')
> age(my.dob)
[1] 31
> age(my.dob, floor = FALSE)
[1] 31.15616
> age(my.dob, units = "minutes")
[1] 16375680
> age(seq(my.dob, length.out = 6, by = "years"))
[1] 31 30 29 28 27 26
我並不高興與任何反應的,當涉及到計算時代幾個月或幾年,當處理閏年時,所以這是我使用lubridate軟件包的功能。
基本上,它會將from
和to
之間的間隔切分爲(最多)年度塊,然後調整該塊是否爲閏年的時間間隔。總間隔是每個塊的年齡的總和。
library(lubridate)
#' Get Age of Date relative to Another Date
#'
#' @param from,to the date or dates to consider
#' @param units the units to consider
#' @param floor logical as to whether to floor the result
#' @param simple logical as to whether to do a simple calculation, a simple calculation doesn't account for leap year.
#' @author Nicholas Hamilton
#' @export
age <- function(from, to = today(), units = "years", floor = FALSE, simple = FALSE) {
#Account for Leap Year if Working in Months and Years
if(!simple && length(grep("^(month|year)",units)) > 0){
df = data.frame(from,to)
calc = sapply(1:nrow(df),function(r){
#Start and Finish Points
st = df[r,1]; fn = df[r,2]
#If there is no difference, age is zero
if(st == fn){ return(0) }
#If there is a difference, age is not zero and needs to be calculated
sign = +1 #Age Direction
if(st > fn){ tmp = st; st = fn; fn = tmp; sign = -1 } #Swap and Change sign
#Determine the slice-points
mid = ceiling_date(seq(st,fn,by='year'),'year')
#Build the sequence
dates = unique(c(st,mid,fn))
dates = dates[which(dates >= st & dates <= fn)]
#Determine the age of the chunks
chunks = sapply(head(seq_along(dates),-1),function(ix){
k = 365/(365 + leap_year(dates[ix]))
k*interval(dates[ix], dates[ix+1])/duration(num = 1, units = units)
})
#Sum the Chunks, and account for direction
sign*sum(chunks)
})
#If Simple Calculation or Not Months or Not years
}else{
calc = interval(from,to)/duration(num = 1, units = units)
}
if (floor) calc = as.integer(floor(calc))
calc
}
我喜歡做這個使用lubridate
包,借用我原來在另一post遇到的語法。
有必要根據R日期對象標準化輸入日期,最好使用lubridate::mdy()
或lubridate::ymd()
或相似的函數(如適用)。您可以使用函數生成描述兩個日期之間所用時間的間隔,然後使用duration()
函數來定義如何將該間隔「切塊」。
我總結了簡單的情況下,計算從下面兩個日期的時代,使用最新的語法R.
df$DOB <- mdy(df$DOB)
df$EndDate <- mdy(df$EndDate)
df$Calc_Age <- interval(start= df$DOB, end=df$EndDate)/
duration(n=1, unit="years")
年齡可能向下調整至最接近的整數完全使用基本R'地板()`函數,如下所示:
df$Calc_AgeF <- floor(df$Calc_Age)
可替換地,在基R中的digits=
參數round()
函數可用於舍向上或向下,並指定小數的確切數目在返回值中,像這樣:
df$Calc_Age2 <- round(df$Calc_Age, digits = 2) ## 2 decimals
df$Calc_Age0 <- round(df$Calc_Age, digits = 0) ## nearest integer
值得注意的是,一旦輸入日期通過以上(即,和duration()
功能)中所述的計算步驟中通過,返回值將是數字,並不再在R.日期對象這是顯著而lubridate::floor_date()
嚴格限於日期時間對象。
無論輸入日期是否出現在data.table
或data.frame
對象中,上述語法都適用。
- 1. 從出生日期得到年齡?
- 2. 查找年齡和出生日期並按年齡分組R
- 3. 從出生日期確定年齡
- 4. 從出生日期計算年齡
- 5. 從SAS年齡計算出生日期
- 6. 顯示年齡從出生日期?
- 7. SQL查詢從計算出生年齡和日期字段
- 8. 通過出生日期字段在crm 2013年計算年齡
- 9. 我怎樣才能出生日期的日期從年齡數
- 10. 基於出生日期的EOFY年齡
- 11. 根據出生日期計算年齡
- 12. 年齡檢查由出生日期到確切日期,爲jquery.validate
- 13. 從powerquery中的日期字段計算年齡和年齡桶
- 14. 按年齡分組按年齡計算從出生日期SQL Server
- 15. 從出生日期(使用日曆)計算年齡IN Jsf
- 16. SQL組學生按年齡從出生日期起
- 17. 如何計算從出生日期到當前日期的當前年齡?
- 18. 使用javascript計算特定年齡段的出生日期
- 19. 熊貓得到一個日期的年齡(例如:出生日期)
- 20. 根據出生日期計算出年齡組內的年齡和地點
- 21. 的Javascript年齡從出生
- 22. php從出生日期計算年齡html表格
- 23. 從出生日期計算確切年齡(使用1/2)
- 24. 從當前日期和生效計算得出的年齡
- 25. SQLite:如何從出生日期計算年齡
- 26. 如何從clojure出生日期計算年齡?
- 27. 從出生日期開始sql check約束的年齡
- 28. 出生日期的LINQ查詢得到年齡
- 29. 在if語句中得到出生日期的年齡
- 30. 出生日期到使用PHP的年齡範圍
這是我正在尋找的答案。 ([我們再次見面](http://stackoverflow.com/questions/17499013/how-do-i-make-a-list-of-data-frames/24376207#24376207)) – Ben 2017-02-01 21:06:48
警告消息: 'new_interval'已棄用;改用'間隔'。在'1.5.0'版本中已棄用。 – malajisi 2018-02-28 08:35:18
@malajisi謝謝,更新。 – Gregor 2018-02-28 14:38:41