如何将R中的日期拆分为多个列

如何将R中的日期拆分为多个列,r,vectorization,R,Vectorization,我有一个数据集,看起来像: mother_id,dateOfBirth 1,1962-09-24 2,1991-02-19 3,1978-11-11 我需要从出生日期提取组成元素(日、月、年),并将它们放在相应的列中,如下所示: mother_id,dateOfBirth,dayOfBirth,monthOfBirth,yearOfBirth 1,1962-09-24,24,09,1962 2,1991-02-19,19,02,1991 3,1978-11-11,11,11,1978 目前,

我有一个数据集,看起来像:

mother_id,dateOfBirth
1,1962-09-24
2,1991-02-19
3,1978-11-11
我需要从出生日期提取组成元素(日、月、年),并将它们放在相应的列中,如下所示:

mother_id,dateOfBirth,dayOfBirth,monthOfBirth,yearOfBirth
1,1962-09-24,24,09,1962
2,1991-02-19,19,02,1991
3,1978-11-11,11,11,1978
目前,我将其编码为循环:

data <- read.csv("/home/tumaini/Desktop/IHI-Projects/Data-Linkage/matching file dss nacp.csv",stringsAsFactors = F)
dss_individuals <- read.csv("/home/tumaini/Desktop/IHI-Projects/Data-Linkage/Data/dssIndividuals.csv", stringsAsFactors = F)

lookup <- data[,c("patientid","extId")]

# remove duplicates
lookup <- lookup[!(duplicated(lookup$patientid)),]

dss_individuals$dateOfBirth <- as.character.Date(dss_individuals$dob)


dss_individuals$dayOfBirth <- 0
dss_individuals$monthOfBirth <- 0
dss_individuals$yearOfBirth <- 0

# Loop starts here    
for(i in 1:nrow(dss_individuals)){ #nrow(dss_individuals)
    split_list <- unlist(strsplit(dss_individuals[i,]$dateOfBirth,'[- ]'))

    dss_individuals[i,]["dayOfBirth"] <- split_list[3]
    dss_individuals[i,]["monthOfBirth"] <- split_list[2]
    dss_individuals[i,]["yearOfBirth"] <- split_list[1]
}

数据对每个零件使用
格式
一次:

dss_individuals$dayOfBirth <- format(dss_individuals$dateOfBirth,"%d")
dss_individuals$monthOfBirth <- format(dss_individuals$dateOfBirth,"%m")
dss_individuals$yearOfBirth <- format(dss_individuals$dateOfBirth,"%Y")

dss\u个人$dayOfBirth不确定这是否能解决速度问题,但这里有一个更好的方法,使用dplyr和lubridate。一般来说,在操作data.frames时,我个人建议使用data.tables或dplyr。tables应该更快,但dplyr更详细,这是我个人更喜欢的,因为我发现在几个月没有读过代码之后,更容易提取代码

library(dplyr)
library(lubridate)

dat <- data.frame( mother_id = c(1,2,3),
                   dateOfBirth = ymd(c( "1962-09-24" ,"1991-02-19" ,"1978-11-11"))
)


dat %>%  mutate( year  = year(dateOfBirth) , 
                 month = month(dateOfBirth),
                 day   = day(dateOfBirth)  )

检查基本包中的
substr
函数(或nice
stringr
包中的其他函数),以提取字符串的不同部分。此函数可以假定日、月和年始终位于同一位置且长度相同

strsplit
函数是矢量化的,因此使用
rbind.data.frame
将列表转换为数据帧可以:

do.call(rbind.data.frame, strsplit(df$dateOfBirth, split = '-'))

结果需要转换才能使用:您可以使用
do.call
t
函数进行转换。

我比较了
substr
格式
的速度,以及
lubridate
的使用情况。如果变量存储为日期,则
lubridate
format
似乎比
substr
快得多。但是,如果变量存储为字符向量,substr将是最快的。显示了单次运行的结果

x <- sample(
    seq(as.Date('1000/01/01'), as.Date('2000/01/01'), by="day"),
    400000, replace = T)

system.time({
    y <- substr(x, 1, 4)
    m <- substr(x, 6, 7)
    d <- substr(x, 9, 10)
})
# user  system elapsed 
# 3.775   0.004   3.779 

system.time({
    y <- format(x,"%y")
    m <- format(x,"%m")
    d <- format(x,"%d")
})
# user  system elapsed 
# 1.118   0.000   1.118 

system.time({
    y <- year(x)
    m <- month(x)
    d <- day(x)
})
# user  system elapsed 
# 0.951   0.000   0.951 

x1 <- as.character(x)
system.time({
    y <- substr(x1, 1, 4)
    m <- substr(x1, 6, 7)
    d <- substr(x1, 9, 10)
})
# user  system elapsed 
# 0.082   0.000   0.082 

x以下是一些解决方案。这些解决方案分别(i)使用1或2行代码,(ii)返回数字年、月和日列。此外,前两个解决方案不使用包——第三个使用chron的
month.day.year
功能

1)POSIXlt转换为
“POSIXlt”
类并拾取零件

lt <- as.POSIXlt(DF$dateOfBirth, origin = "1970-01-01")
transform(DF, year = lt$year + 1900, month = lt$mon + 1, day = lt$mday)
2)读取表格

cbind(DF, read.table(text = format(DF$dateOfBirth), sep = "-", 
  col.names = c("year", "month", "day")))
给予:

  mother_id dateOfBirth year month day
1         1  1962-09-24 1962     9  24
2         2  1991-02-19 1991     2  19
3         3  1978-11-11 1978    11  11
  mother_id dateOfBirth year month day
1         1  1962-09-24 1962     9  24
2         2  1991-02-19 1991     2  19
3         3  1978-11-11 1978    11  11
  mother_id dateOfBirth month day year
1         1  1962-09-24     9  24 1962
2         2  1991-02-19     2  19 1991
3         3  1978-11-11    11  11 1978
3)时间:月、日、年

library(chron)
cbind(DF, month.day.year(DF$dateOfBirth))
给予:

  mother_id dateOfBirth year month day
1         1  1962-09-24 1962     9  24
2         2  1991-02-19 1991     2  19
3         3  1978-11-11 1978    11  11
  mother_id dateOfBirth year month day
1         1  1962-09-24 1962     9  24
2         2  1991-02-19 1991     2  19
3         3  1978-11-11 1978    11  11
  mother_id dateOfBirth month day year
1         1  1962-09-24     9  24 1962
2         2  1991-02-19     2  19 1991
3         3  1978-11-11    11  11 1978
注1:通常情况下,在将年、月和日添加到数据中时,这并不是真正必要的,事实上,它们可以在需要时使用
格式
substr
as.POSIXlt
动态生成,因此您可能会仔细检查是否确实需要这样做

注2:输入数据框,
DF
为可复制形式,假设为:

Lines <- "mother_id,dateOfBirth
1,1962-09-24
2,1991-02-19
3,1978-11-11"

DF <- read.csv(text = Lines)

行检查lubridate包,该包直接从日期提取年、月和事物。有多种方法可以做到这一点。我喜欢
splitstackshape::cSplit(dss_个体,“dateOfBirth”,“-”,drop=F)
@abhiie或者我尝试过你的解决方案,但它似乎为每个观察到的dayOfBirth等给出了一个统一的值,即dateOfBirth和结果之间没有相关性dayOfBirth@ChirayuChamoli现在让我看看lubridate包装,谢谢您可以通过将操作包装在system.time中来简化计时方式,例如
system.time({ys.time()谢谢。我根据建议编辑了代码。。)@C_GCan你能在你的帖子中包含结果吗?当然。我只添加了一次结果@James@user53777谢谢。结果很有趣。您可能也应该将
as.character
调用放入计时中,以便进行公平比较。如图所示,lubridate实际上比目前推荐的许多其他解决方案都要快:)
lubridate
在后台使用POSIXlt对象。这些对象使用的内存比日期对象多5倍,因此当您有大量数据时,这可能会更慢。