我有一个40k~不同医生(MPIN)的开始和结束日期的数据框。我们可以使用以下代码创建说明性数据框:
x <- seq(as.Date("2014-01-01"), as.Date("2015-10-31"), by = "days")
y <- c(1:150)
mpins <- c(1000000:9999999)
s = 40000
df <- data.frame(start_date = as.Date(sample(x, s, replace = TRUE)),
MPIN = sample(mpins, s, replace = FALSE))
df$end_date <- as.Date(df$start_date + sample(y, s, replace = TRUE))
head(df)
start_date MPIN end_date
1 2015-10-31 1093782 2016-03-27
2 2014-12-06 4932382 2015-04-30
3 2015-02-28 5577980 2015-03-29
4 2014-07-31 9824869 2014-11-17
5 2014-06-14 5845130 2014-06-22
6 2014-07-13 2773056 2014-10-17
我现在要做的是找到一种非常快速的方法来创建一个新数据框,其中包含每个唯一月份的字段(格式化为&#34; YYYY-mm&#34;),用于每个唯一的MPIN在一个如下所示的数据框中:
head(target_df)
months MPIN
1 2015-10 1093782
2 2015-11 1093782
3 2015-12 1093782
4 2016-01 1093782
5 2016-02 1093782
6 2016-03 1093782
我已经提出了一个循环函数来做到这一点,但我觉得这是非常低效的。使用40k~MPIN,大约需要2分钟,MPIN列表只会随着时间的推移而变大。以下是我当前的解决方案:
df2 <- function(x) {
tm1 <- df[x, ]
dates <- data.frame(seq(as.Date(tm1$start_date),
as.Date(tm1$end_date),
by = "days"))
colnames(dates) <- c("dates")
dates$months <- substr(as.character(dates$dates), 1, 7)
dates <- dates[which(!duplicated(dates$months)), ]
dates$MPIN <- tm1$MPIN
dates$dates <- NULL
print(dates)
}
a <- (1:nrow(df))
system.time(df3 <- do.call("rbind", lapply(a, function(x) df2(x))))
df3$unique <- paste0(df3$MPIN, "-", df3$months)
df3 <- df3[which(!duplicated(df3$unique)), ]
df3$unique <- NULL
head(df3)
months MPIN
1 2015-10 1093782
2 2015-11 1093782
32 2015-12 1093782
63 2016-01 1093782
94 2016-02 1093782
123 2016-03 1093782
任何加快此过程的建议都将不胜感激。谢谢!
更新
略微调整了@Michele_Usuelli的有用推荐,我能够将这个过程加速约80%。
我原来的功能结果:
user system elapsed
122.57 1.50 126.01
使用以下功能的结果:
user system elapsed
25.52 0.15 26.06
library(data.table)
library(dplyr)
# for each record, create a sequence of dates
df <- data.table(df)
df4 <- df[, list(date = seq(start_date, end_date, by = "day"),
MPIN = MPIN),
by = 1:nrow(df)]
# determine the unique month-MPIN combinations
df5 <- df4 %>%
group_by(month = paste0(format(date, "%Y"), "-", format(date, "%m")), MPIN) %>%
summarise(n = n()) %>%
select(-n)
答案 0 :(得分:1)
这应该快得多:
library(data.table)
library(dplyr)
# for each record, create a sequence of dates
df <- data.table(df)
df4 <- df[, list(date = seq(start_date, end_date, by = "day"),
MPIN = MPIN),
by = 1:nrow(df)]
# determine the unique month-MPIN combinations
df5 <- df4 %>%
group_by(month = format(date, "%m"), MPIN) %>%
summarise(n = n())
结果是否相同?
答案 1 :(得分:0)
您应该可以使用rep
函数实现此目的,这是一个简单的示例:
monnb <- function(d) { lt <- as.POSIXlt(as.Date(d, origin="1900-01-01"))
lt$year*12 + lt$mon }
df$length <- monnb(df$end_date) - monnb(df$start_date)
res <- df[rep(row.names(df), times=df$length), c("start_date", "MPIN")]
要获取每条记录的月份,您可以对MPIN中的行执行running count并将其添加到开始日期。