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

时间:2016-07-04 12:08:28

标签: 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

目前,我把它编码为循环:

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]
}

这似乎有效,但由于我有40万行,因此非常慢。有没有办法让我更有效地完成这项工作?

5 个答案:

答案 0 :(得分:3)

我比较了def finder = new FileNameFinder() def files = finder.getFileNames 'D:\\Data', '**/*.sln' print files substrformat的使用速度。如果变量存储为日期,lubridatelubridate似乎比format快得多。但是,如果变量存储为字符向量,则substr将是最快的。显示单次运行的结果。

substr

答案 1 :(得分:2)

不确定这是否会解决您的速度问题,但这是使用dplyr和lubridate更好的方法。一般来说,在操作data.frames时,我个人建议使用data.tables或dplyr。 Data.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)  )

或者您可以使用mutate_each函数来保存必须多次写入变量名称(尽管您对输出变量名称的控制较少)

dat %>% mutate_each( funs(year , month , day) , dateOfBirth)

答案 2 :(得分:2)

以下是一些解决方案。这些解决方案每个(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)

,并提供:

  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

2)read.table

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

3)chron :: month.day.year

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

,并提供:

  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:通常在数据中添加年,月,日时,实际上并不是必需的,实际上可以在需要时使用format substr动态生成它们。 1}}或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)

答案 3 :(得分:1)

每个部分使用format一次:

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

答案 4 :(得分:0)

检查基础包中的substr函数(或来自nice stringr包的其他函数)以提取字符串的不同部分。此功能可以假设日,月和年总是在同一个地方并且具有相同的长度。

strsplit函数已进行矢量化,因此使用rbind.data.frame将列表转换为数据框可以正常工作:

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

需要调整结果才能使用:您可以使用do.callt函数进行调整。