R从不平衡的面板数据集中填充多个时间序列
R Padding multiple time series from within an unbalanced panel data set
我有一个按 ID 显示每日收入(和其他变量)的面板数据集,其中收入为 0 的那一天未报告。我想用 0 填充这些空白以进行分析,这意味着对于每个 ID 的时间序列,我需要确保每天都有一个观察值。每个系列可以在不同于其他系列的日期开始或结束。我一直在尝试使用 "padr" 包,但使用以下示例代码时我一直收到 "unused argument" 错误:
library(padr)
library(dplyr)
#unbalanced panel data
ID <- c(1,1,1,1,
2,2,2,2,2,2,
3,3,3,3,3,3,3,
4,4,4)
DT <- today() + c(1,3,4,5, #ID = 1
3,4,7,8,9,10, #ID = 2
2,5,6,7,8,9,10, #ID = 3
8,10,11) #ID = 4
#The end date denote the max date for each ID
EndDT <- today() + c(5,5,5,5, #ID = 1
13,13,13,13,13,13, #ID = 2
10,10,10,10,10,10,10, #ID = 3
15,15,15) #ID = 4
#random variables v1 and v2 to represent revenue and other variables
set.seed(1)
v1 <- rnorm(20,mean = 10000, sd = 5)
v2 <- rnorm(20,mean = 5000, sd = 1.5)
df <- as.data.frame(cbind(ID,DT,EndDT,v1,v2))
#format to simpler date
df$DT <- as.Date(DT, origin="1970-01-01")
df$EndDT <- as.Date(EndDT, origin="1970-01-01")
df_padded <- arrange(df,ID,DT) %>%
pad(by='DT',group='ID', end_val='EndDT') %>%
fill_by_value(v1,v2, value=0)
我的错误信息:
Error in pad(., by = "DT", group = "ID", end_val = "EndDT") :
unused argument (group = "ID")
也非常欢迎不涉及 padr 的回答。
和padr折腾了一段时间,决定自己写一个函数。此函数适用于示例集,但很快 运行 就会遇到真实数据的问题。无论哪种方式,我认为这可能对其他人有用,所以在这里:
date.pad <- function(df, date.var, group, replace.vars, new.val=0){
require("dplyr")
require("lazyeval")
require("lubridate")
tempdf1 <- arrange_(df,group,date.var)
finaldf <- tempdf1[0,]
unique.id <- unique(tempdf1[,group])
nonreplaced.vars <- setdiff(colnames(tempdf1),replace.vars)
nonreplaced.vars <- nonreplaced.vars[!nonreplaced.vars==date.var]
for(i in seq_along(unique.id)){
filter_criteria <- interp(~y==x, .values=list(y=as.name(group),x=i)) #necessary for NSE
tempdf2 <- filter_(tempdf1,filter_criteria)
min.date <- min(tempdf2[[date.var]])
max.date <- max(tempdf2[[date.var]])
all.days <- as.Date(seq(min.date,max.date,by="days"),origin="1970-01-01")
distinct.days <- unique(tempdf2[,date.var])
app.days <- as.Date(setdiff(all.days,distinct.days),origin="1970-01-01")
tempdf3 <- tempdf2[0,]
for(n in seq_along(app.days)){
tempdf3[n,date.var] <- app.days[n]
}
for(j in seq_along(nonreplaced.vars)){
tempdf3[1:nrow(tempdf3),nonreplaced.vars[j]] <- tempdf2[1,nonreplaced.vars[j]]
}
finaldf <- bind_rows(finaldf,tempdf3)
}
finaldf[replace.vars] <-new.val
finaldf <- bind_rows(finaldf,df) %>% arrange_(group,date.var)
return(finaldf)
}
for.exmpl <- date.pad(df=df1, date.var="DT", group="ID", replace.vars=c("v1","v2"), new.val=0)
for.exmpl
这是我设计的一个新答案,它在我的一个应用程序之外更适用,并且使用的代码更少:
library(tidyverse)
temp <- group_by(df1,ID) %>%
complete(DT = seq.Date(min(DT),max(EndDT),by="day")) %>%
fill(EndDT,sometext) %>%
arrange(ID,DT)
temp[is.na(temp)] <- 0
View(temp)
这导致:
# A tibble: 33 x 6
# Groups: ID [4]
ID DT EndDT v1 v2 sometext
<dbl> <date> <date> <dbl> <dbl> <chr>
1 1. 2018-05-04 2018-05-08 9997. 5001. textvar
2 1. 2018-05-05 2018-05-08 0. 0. textvar
3 1. 2018-05-06 2018-05-08 10001. 5001. textvar
4 1. 2018-05-07 2018-05-08 9996. 5000. textvar
5 1. 2018-05-08 2018-05-08 10008. 4997. textvar
6 2. 2018-05-06 2018-05-16 10002. 5001. textvar
7 2. 2018-05-07 2018-05-16 9996. 5000. textvar
8 2. 2018-05-08 2018-05-16 0. 0. textvar
9 2. 2018-05-09 2018-05-16 0. 0. textvar
10 2. 2018-05-10 2018-05-16 10002. 5000. textvar
# ... with 23 more rows
(请忽略 "sometext" 变量。我在下面测试我的函数时创建了它。)
您的代码没有 运行,因为您在 end_val
参数中指定了一个字符。这应该是 Date
,您只能在所有组中指定一个日期。
为了用 padr
做你想做的事,你应该结合 DT 和 EndDT 列。这样,对于每个 ID,其最终日期都出现在 DT 列中:
df %>%
group_by(ID) %>%
summarise(DT = max(EndDT)) %>%
mutate(v1 = NA, v2 = NA) %>%
bind_rows(df %>% select(-EndDT), .) %>%
group_by(ID, DT) %>%
filter(row_number() == 1) %>%
group_by(ID) %>%
pad()
我有一个按 ID 显示每日收入(和其他变量)的面板数据集,其中收入为 0 的那一天未报告。我想用 0 填充这些空白以进行分析,这意味着对于每个 ID 的时间序列,我需要确保每天都有一个观察值。每个系列可以在不同于其他系列的日期开始或结束。我一直在尝试使用 "padr" 包,但使用以下示例代码时我一直收到 "unused argument" 错误:
library(padr)
library(dplyr)
#unbalanced panel data
ID <- c(1,1,1,1,
2,2,2,2,2,2,
3,3,3,3,3,3,3,
4,4,4)
DT <- today() + c(1,3,4,5, #ID = 1
3,4,7,8,9,10, #ID = 2
2,5,6,7,8,9,10, #ID = 3
8,10,11) #ID = 4
#The end date denote the max date for each ID
EndDT <- today() + c(5,5,5,5, #ID = 1
13,13,13,13,13,13, #ID = 2
10,10,10,10,10,10,10, #ID = 3
15,15,15) #ID = 4
#random variables v1 and v2 to represent revenue and other variables
set.seed(1)
v1 <- rnorm(20,mean = 10000, sd = 5)
v2 <- rnorm(20,mean = 5000, sd = 1.5)
df <- as.data.frame(cbind(ID,DT,EndDT,v1,v2))
#format to simpler date
df$DT <- as.Date(DT, origin="1970-01-01")
df$EndDT <- as.Date(EndDT, origin="1970-01-01")
df_padded <- arrange(df,ID,DT) %>%
pad(by='DT',group='ID', end_val='EndDT') %>%
fill_by_value(v1,v2, value=0)
我的错误信息:
Error in pad(., by = "DT", group = "ID", end_val = "EndDT") :
unused argument (group = "ID")
也非常欢迎不涉及 padr 的回答。
和padr折腾了一段时间,决定自己写一个函数。此函数适用于示例集,但很快 运行 就会遇到真实数据的问题。无论哪种方式,我认为这可能对其他人有用,所以在这里:
date.pad <- function(df, date.var, group, replace.vars, new.val=0){
require("dplyr")
require("lazyeval")
require("lubridate")
tempdf1 <- arrange_(df,group,date.var)
finaldf <- tempdf1[0,]
unique.id <- unique(tempdf1[,group])
nonreplaced.vars <- setdiff(colnames(tempdf1),replace.vars)
nonreplaced.vars <- nonreplaced.vars[!nonreplaced.vars==date.var]
for(i in seq_along(unique.id)){
filter_criteria <- interp(~y==x, .values=list(y=as.name(group),x=i)) #necessary for NSE
tempdf2 <- filter_(tempdf1,filter_criteria)
min.date <- min(tempdf2[[date.var]])
max.date <- max(tempdf2[[date.var]])
all.days <- as.Date(seq(min.date,max.date,by="days"),origin="1970-01-01")
distinct.days <- unique(tempdf2[,date.var])
app.days <- as.Date(setdiff(all.days,distinct.days),origin="1970-01-01")
tempdf3 <- tempdf2[0,]
for(n in seq_along(app.days)){
tempdf3[n,date.var] <- app.days[n]
}
for(j in seq_along(nonreplaced.vars)){
tempdf3[1:nrow(tempdf3),nonreplaced.vars[j]] <- tempdf2[1,nonreplaced.vars[j]]
}
finaldf <- bind_rows(finaldf,tempdf3)
}
finaldf[replace.vars] <-new.val
finaldf <- bind_rows(finaldf,df) %>% arrange_(group,date.var)
return(finaldf)
}
for.exmpl <- date.pad(df=df1, date.var="DT", group="ID", replace.vars=c("v1","v2"), new.val=0)
for.exmpl
这是我设计的一个新答案,它在我的一个应用程序之外更适用,并且使用的代码更少:
library(tidyverse)
temp <- group_by(df1,ID) %>%
complete(DT = seq.Date(min(DT),max(EndDT),by="day")) %>%
fill(EndDT,sometext) %>%
arrange(ID,DT)
temp[is.na(temp)] <- 0
View(temp)
这导致:
# A tibble: 33 x 6
# Groups: ID [4]
ID DT EndDT v1 v2 sometext
<dbl> <date> <date> <dbl> <dbl> <chr>
1 1. 2018-05-04 2018-05-08 9997. 5001. textvar
2 1. 2018-05-05 2018-05-08 0. 0. textvar
3 1. 2018-05-06 2018-05-08 10001. 5001. textvar
4 1. 2018-05-07 2018-05-08 9996. 5000. textvar
5 1. 2018-05-08 2018-05-08 10008. 4997. textvar
6 2. 2018-05-06 2018-05-16 10002. 5001. textvar
7 2. 2018-05-07 2018-05-16 9996. 5000. textvar
8 2. 2018-05-08 2018-05-16 0. 0. textvar
9 2. 2018-05-09 2018-05-16 0. 0. textvar
10 2. 2018-05-10 2018-05-16 10002. 5000. textvar
# ... with 23 more rows
(请忽略 "sometext" 变量。我在下面测试我的函数时创建了它。)
您的代码没有 运行,因为您在 end_val
参数中指定了一个字符。这应该是 Date
,您只能在所有组中指定一个日期。
为了用 padr
做你想做的事,你应该结合 DT 和 EndDT 列。这样,对于每个 ID,其最终日期都出现在 DT 列中:
df %>%
group_by(ID) %>%
summarise(DT = max(EndDT)) %>%
mutate(v1 = NA, v2 = NA) %>%
bind_rows(df %>% select(-EndDT), .) %>%
group_by(ID, DT) %>%
filter(row_number() == 1) %>%
group_by(ID) %>%
pad()