如何将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
函数(或nicestringr
包中的其他函数),以提取字符串的不同部分。此函数可以假定日、月和年始终位于同一位置且长度相同
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倍,因此当您有大量数据时,这可能会更慢。