获得独特月份的最快方式,"其他价值"使用日期范围的组合

时间:2016-05-02 22:59:34

标签: r loops

我有一个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)

2 个答案:

答案 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并将其添加到开始日期。