R循环-有没有更有效的方法?
我有一个数据框,其中每一行都有一个唯一的ID。我需要根据开始日期与结束日期和批准日期之间的最大天数复制这些行中的每一行R循环-有没有更有效的方法?,r,loops,for-loop,nested-loops,R,Loops,For Loop,Nested Loops,我有一个数据框,其中每一行都有一个唯一的ID。我需要根据开始日期与结束日期和批准日期之间的最大天数复制这些行中的每一行 ID <- c(1,2) Value <- c(10,20) StartDate <- c(as.Date("01/01/2015", '%d/%m/%Y'), as.Date("01/01/2015", '%d/%m/%Y')) EndDate <- c(as.Date("31/01/2015", '%d/%m/%Y'), as
ID <- c(1,2)
Value <- c(10,20)
StartDate <- c(as.Date("01/01/2015", '%d/%m/%Y'),
as.Date("01/01/2015", '%d/%m/%Y'))
EndDate <- c(as.Date("31/01/2015", '%d/%m/%Y'),
as.Date("15/01/2015", '%d/%m/%Y'))
AppDate <- c(as.Date("15/01/2015", '%d/%m/%Y'),
as.Date("15/02/2015", '%d/%m/%Y'))
df <- data.frame(ID, Value, StartDate, EndDate, AppDate)
df <- df[rep(row.names(df), ifelse(as.numeric(df$AppDate) >
as.numeric(df$EndDate),as.numeric(df$AppDate-df$StartDate),
as.numeric(df$EndDate-df$StartDate)) + 1),]
ID这里有一个矢量化的解决方案。注意:您的代码不符合我尝试使用的EndDate和AppDate最大值的概念,但是如果这不是您想要的,您可以相应地修改代码
library(dplyr)
df <- df %>% group_by(ID) %>% mutate(Days = rep(seq(min(StartDate), max(EndDate, df$AppDate), 'days'), ceiling(nrow(df) / n()))[1:n()])
这是一个矢量化的解决方案。注意:您的代码不符合我尝试使用的EndDate和AppDate最大值的概念,但是如果这不是您想要的,您可以相应地修改代码
library(dplyr)
df <- df %>% group_by(ID) %>% mutate(Days = rep(seq(min(StartDate), max(EndDate, df$AppDate), 'days'), ceiling(nrow(df) / n()))[1:n()])
通常,我建议使用交叉连接SQL查询返回笛卡尔乘积(两个集合之间的所有组合)。但是,您可以使用merge()
在R中复制交叉联接,而不使用任何by
参数,并且使用all=True
。从那里,筛选EndDate
截止日期:
# CALCULATE CONDITIONAL END DATE
df$TrueEndDate <- as.Date(ifelse(df$AppDate > df$EndDate,
df$AppDate,
df$EndDate), origin="1970-01-01")
# CREATE A SEQUENTIAL DATES DATA FRAME (HERE IS 60 DAYS FROM 2015-01-01)
dates <- data.frame(Date=as.Date(unlist(lapply(0:60, function(x)
as.Date("2015-01-01") + x)),
origin="1970-01-01"))
# RUN CROSS JOIN MERGE, PULLING ONLY NEEDED FIELDS
mergedf <- merge(df[c('ID', 'StartDate', 'TrueEndDate')], dates, all=TRUE)
# FILTER OUT DATES PAST ROW'S TRUE END DATE
mergedf <- mergedf[(mergedf$Date <= mergedf$TrueEndDate),]
# CLEANUP
mergedf <- mergedf[with(mergedf, order(ID)), ] # ORDER BY ID
row.names(mergedf) <- 1:nrow(mergedf) # RESET ROW NAMES
#计算条件结束日期
df$TrueEndDate df$EndDate,
df$AppDate,
df$EndDate),origin=“1970-01-01”)
#创建连续日期数据框(这里是从2015-01-01开始的60天)
日期通常,我建议使用交叉连接SQL查询返回笛卡尔乘积(两个集合之间的所有组合)。但是,您可以使用merge()
在R中复制交叉联接,而不使用任何by
参数,并且使用all=True
。从那里,筛选EndDate
截止日期:
# CALCULATE CONDITIONAL END DATE
df$TrueEndDate <- as.Date(ifelse(df$AppDate > df$EndDate,
df$AppDate,
df$EndDate), origin="1970-01-01")
# CREATE A SEQUENTIAL DATES DATA FRAME (HERE IS 60 DAYS FROM 2015-01-01)
dates <- data.frame(Date=as.Date(unlist(lapply(0:60, function(x)
as.Date("2015-01-01") + x)),
origin="1970-01-01"))
# RUN CROSS JOIN MERGE, PULLING ONLY NEEDED FIELDS
mergedf <- merge(df[c('ID', 'StartDate', 'TrueEndDate')], dates, all=TRUE)
# FILTER OUT DATES PAST ROW'S TRUE END DATE
mergedf <- mergedf[(mergedf$Date <= mergedf$TrueEndDate),]
# CLEANUP
mergedf <- mergedf[with(mergedf, order(ID)), ] # ORDER BY ID
row.names(mergedf) <- 1:nrow(mergedf) # RESET ROW NAMES
#计算条件结束日期
df$TrueEndDate df$EndDate,
df$AppDate,
df$EndDate),origin=“1970-01-01”)
#创建连续日期数据框(这里是从2015-01-01开始的60天)
日期我认为本问答中的数据表答案提供了有效解决方案的一般原则:。谷歌“R expand date range data.table”应该提供几个类似的例子。我认为本问答中的data.table
答案提供了有效解决方案的一般原则:。谷歌的“R扩展日期范围数据表”应该提供几个类似的例子。感谢它的完美工作。与我编写的代码相比,我喜欢矢量化版本的简单性。这比我预期的要慢得多,这是最快的方法吗?取决于数据的大小、组的数量和处理的日期范围。此外,如果您定义“慢”,它可能会有所帮助。有一个名为data.table
的不同包被认为比dplyr
更有效。我不使用它,因为我发现dplyr
更加通用和直观(个人观点)。其他人可能会帮助您将代码转换为data.table
版本。谢谢您,它工作得非常好。与我编写的代码相比,我喜欢矢量化版本的简单性。这比我预期的要慢得多,这是最快的方法吗?取决于数据的大小、组的数量和处理的日期范围。此外,如果您定义“慢”,它可能会有所帮助。有一个名为data.table
的不同包被认为比dplyr
更有效。我不使用它,因为我发现dplyr
更加通用和直观(个人观点)。其他人可能可以帮助您将代码转换为data.table
version。
SELECT ID.ID, ID.Value, ID.StartDate,
CASE WHEN ID.AppDate > ID.EndDate
THEN ID.AppDate
ELSE ID.EndDate
END As TrueEndDate,
Dates.Dates
FROM ID, Dates
WHERE Dates.Dates <= CASE WHEN ID.AppDate > ID.EndDate
THEN ID.AppDate ELSE ID.EndDate
END
ORDER BY ID.ID, Dates.Dates