【问题标题】:gsub for dealing with dates in r in datagsub 用于处理数据中 r 中的日期
【发布时间】:2015-09-14 10:03:04
【问题描述】:

我正在处理非常大的大学生数据集,其中日期格式为

%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 在所有 dob 小于或等于 15 的前面加上一个 '20' 并在所有 dob 大于 15 的前面加上一个 '19'。

我认为我的数据集中没有 85 岁的人。

【问题讨论】:

  • 创建数据时日期是否应该是字符串;例如"12/12/01"?
  • 是的,数据是由第三方以字符串形式提供的,采用这种日期格式。要求他们以 %Y 格式再次提取它的计算成本非常高。
  • 好的,您能否编辑您的帖子以更正此问题?

标签: r data.table gsub 2-digit-year


【解决方案1】:
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)

这对你有用吗?

【讨论】:

    【解决方案2】:

    以及使用基本 R 的 substrnchar 函数的类似方法。

    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
    

    【讨论】:

      【解决方案3】:

      或者,避免额外使用 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多