gsub для работы с датами в r в данных

Я имею дело с очень большим набором данных студентов университетов, где даты в форме

%d/%m/%y

Мне нужно потренироваться в возрасте.

Мои данные выглядят примерно так, как они были извлечены из базы данных:

data <- data.table(DOB=c("12/12/01", "8/05/80", "2/11/99"), 
                  started =c("5/10/10", "4/01/12", "27/08/11"))

Проблема в том, что для расчета возраста целый год не указан.

Я попытался изменить годы на числовые:

data$DOB<-as.Date(data$DOB, "%d/%m/%y")
data$start<-as.Date(data$start, "%d/%m/%y")
data$DOB<-as.numeric(format(data$DOB,"%Y"))
data$start<-as.numeric(format(data$start,"%Y"))
data$age<-data$start-data$dob

Очевидно, это не работает, так как мне нужно добавить в 20 и 19.

Есть ли способ, которым я могу использовать gsub, чтобы поставить '20' перед всеми, где dob меньше или равен 15, а '19' перед всеми dob больше 15.

Я не думаю, что в моем наборе данных есть 85-летние.

3 ответа

Решение

И аналогичный подход с использованием substr а также nchar функции базы R.

library(data.table)

dt <-data.table(DOB=c("12/12/01", "8/05/80", "2/11/99"), 
                started =c("5/10/10", "4/01/12", "27/08/11"))

dt

#         DOB  started
# 1: 12/12/01  5/10/10
# 2:  8/05/80  4/01/12
# 3:  2/11/99 27/08/11


WholeYear = function(x){

            v1 = substr(x, 1, nchar(x)-2)
            v2 = substr(x, nchar(x)-1, nchar(x))

            ifelse(as.numeric(v2) <= 15, paste0(v1,"20",v2), paste0(v1,"19",v2)) 

                        }


dt$DOB = sapply(dt$DOB, WholeYear)
dt$started = sapply(dt$started, WholeYear)

dt


#           DOB    started
# 1: 12/12/2001  5/10/2010
# 2:  8/05/1980  4/01/2012
# 3:  2/11/1999 27/08/2011
data<-data.frame(DOB=c('12/12/01', '8/05/80', '2/11/99'), 
                 started =c('5/10/10', '4/01/12', '27/08/11'))

library(stringr)
toFourYear <- function(x){
  x <- str_split(x, "/")
  x <- lapply(x,
         function(t){
            t[3] <- if (as.numeric(t[3]) < 15) paste0("20", t[3]) else paste0("19", t[3])
           t
         })    
  x <- vapply(x, paste0, character(1), collapse = "/")
  x
}

data$DOB <- toFourYear(data$DOB)
data$started <- toFourYear(data$started)

Будет ли это работать для вас?

Или, избегая дополнительного использования pkg и делая векторизованную дату против строковых манипуляций:

dat <- data.table(DOB=c("12/12/01", "8/05/80", "2/11/99"), 
                  started =c("5/10/10", "4/01/12", "27/08/11"))

#' Convert a vector of date strings (with 2-digit years) into dates, taking
#' into account a "cutoff" year to demark when a date belongs in one 
#' century or another.
#'
#' @param d vector of character strings
#' @param format date string format for the 'd'
#' @param cutoff_year 2-digit year where dates in 'd' will be considered
#'        part of one century or another
#' @param output_format date format for the output character vector
as_date_with_cutoff <- function(d, format="%d/%m/%y", 
                                cutoff_year=15, output_format="%d/%m/%Y") {

  d <- as.Date(d, format)

  d <- as.Date(ifelse(d < sprintf("19%s-12-31", cutoff_year), 
                     format(d, "19%y-%m-%d"), format(d)))

  as.character(format(d, output_format))

}

# orig
dat
##         DOB  started
## 1: 12/12/01  5/10/10
## 2:  8/05/80  4/01/12
## 3:  2/11/99 27/08/11

dat$DOB <- as_date_with_cutoff(dat$DOB)
dat$started <- as_date_with_cutoff(dat$started)

# converted
dat
##           DOB    started
## 1: 12/12/2001 05/10/2010
## 2: 08/05/1980 04/01/2012
## 3: 02/11/1999 27/08/2011
Другие вопросы по тегам