插入缺失日期/时间的行
Posted
技术标签:
【中文标题】插入缺失日期/时间的行【英文标题】:Insert rows for missing dates/times 【发布时间】:2013-05-23 03:05:02 【问题描述】:我是 R 的新手,但已经转向它来解决我正在尝试处理的大型数据集的问题。目前,我针对分钟间隔时间戳(月/日/年小时:分钟)(X 值)设置了 4 列数据(Y 值),如下所示:
timestamp tr tt sr st
1 9/1/01 0:00 1.018269e+02 -312.8622 -1959.393 4959.828
2 9/1/01 0:01 1.023567e+02 -313.0002 -1957.755 4958.935
3 9/1/01 0:02 1.018857e+02 -313.9406 -1956.799 4959.938
4 9/1/01 0:03 1.025463e+02 -310.9261 -1957.347 4961.095
5 9/1/01 0:04 1.010228e+02 -311.5469 -1957.786 4959.078
我遇到的问题是缺少一些时间戳值 - 例如9/1/01 0:13 和 9/1/01 0:27 之间可能存在间隙,并且此类间隙在数据集中是不规则的。我需要将这些系列中的几个放入同一个数据库中,并且由于每个系列的缺失值不同,因此日期当前并未在每一行上对齐。
我想为这些缺失的时间戳生成行,并用空白值(没有数据,不为零)填充 Y 列,这样我就有了一个连续的时间序列。
老实说,我不太确定从哪里开始(在我继续学习之前并没有真正使用过 R!)但是任何帮助将不胜感激。到目前为止,我已经安装了 chron 和 zoo,因为它们似乎很有用。
谢谢!
【问题讨论】:
看看这个问题:***.com/questions/16742725/adding-missing-rows 其实我很早就发现了,而且一定是不小心关闭了标签,然后才能阅读它!我会根据他们的建议玩一玩。谢谢! :) @Thomas 如果我按如下方式加载数据:> # set Home directory > home = setwd(Sys.getenv("HOME")); > > # make path to the csv file > fpath = file.path(home, "Desktop", "at0901.csv"); > # read the csv file > at0901 = read.csv(fpath, header=TRUE);
然后我尝试按照推荐的帖子将“时间戳”列转换为 POSIXct 值,但得到以下信息:ts$timestamp <- as.POSIXct(ts$timestamp, format="%m/%d/%y %H:%M") Error in ts$timestamp : object of type 'closure' is not subsettable
抱歉我的无知 - 我已经用非常早的编码知识抛出了这个项目!
【参考方案1】:
这是一个老问题,但我只是想发布一个处理这个问题的 dplyr 方法,因为我在寻找类似问题的答案时遇到了这篇文章。我发现它比动物园的方法更直观、更容易。
library(dplyr)
ts <- seq.POSIXt(as.POSIXct("2001-09-01 0:00",'%m/%d/%y %H:%M'), as.POSIXct("2001-09-01 0:07",'%m/%d/%y %H:%M'), by="min")
ts <- seq.POSIXt(as.POSIXlt("2001-09-01 0:00"), as.POSIXlt("2001-09-01 0:07"), by="min")
ts <- format.POSIXct(ts,'%m/%d/%y %H:%M')
df <- data.frame(timestamp=ts)
data_with_missing_times <- full_join(df,original_data)
timestamp tr tt sr st
1 09/01/01 00:00 15 15 78 42
2 09/01/01 00:01 20 64 98 87
3 09/01/01 00:02 31 84 23 35
4 09/01/01 00:03 21 63 54 20
5 09/01/01 00:04 15 23 36 15
6 09/01/01 00:05 NA NA NA NA
7 09/01/01 00:06 NA NA NA NA
8 09/01/01 00:07 NA NA NA NA
同样使用 dplyr,这使得做一些事情变得更容易,比如将所有缺失的值更改为其他值,这对我在 ggplot 中绘图时派上用场。
data_with_missing_times %>% group_by(timestamp) %>% mutate_each(funs(ifelse(is.na(.),0,.)))
timestamp tr tt sr st
1 09/01/01 00:00 15 15 78 42
2 09/01/01 00:01 20 64 98 87
3 09/01/01 00:02 31 84 23 35
4 09/01/01 00:03 21 63 54 20
5 09/01/01 00:04 15 23 36 15
6 09/01/01 00:05 0 0 0 0
7 09/01/01 00:06 0 0 0 0
8 09/01/01 00:07 0 0 0 0
【讨论】:
可以在代码的前3行解释清楚吗?你是怎么做到的?我想在不同的日期执行此操作,例如从 2017 年 3 月 1 日到 2017 年 9 月 30 日。我有点困惑。所以,请你解释一下。提前致谢。 使用 lubridate 包,您还可以以更直观的方式生成日期。在这段代码中,我演示了不带分秒的日期生成:package(lubridate); ts <- seq(ymd("1991-01-01"), ymd("2015-12-31"), by="day")
嗨,我遇到了类似的问题,只是我在时间戳前面有另一个变量,称为 Product Id,并且这个变量重复了每个集合的整个时间戳值。我正在尝试使用 group_by 对我的数据集进行分组,然后使用上面讨论的时间戳完成功能,它似乎不起作用。你能建议一下,应该怎么做?【参考方案2】:
我认为最简单的方法是先设置日期,如前所述,转换为动物园,然后设置合并:
df$timestamp<-as.POSIXct(df$timestamp,format="%m/%d/%y %H:%M")
df1.zoo<-zoo(df[,-1],df[,1]) #set date to Index
df2 <- merge(df1.zoo,zoo(,seq(start(df1.zoo),end(df1.zoo),by="min")), all=TRUE)
开始和结束是从您的 df1(原始数据)中给出的,并且您正在设置 - 例如 min - 根据您的示例需要。 all=TRUE 将缺失日期的所有缺失值设置为 NA。
【讨论】:
这对我有用 - 我现在有一个完整的时间序列,其中缺少 Y 值的 NA。非常感谢! 我在 df1.zoo 和 df2 的起始行之间有 2 小时的差异。 df2 2 小时后开始!有什么想法吗? 当我这样做时我得到Error in del/by : non-numeric argument to binary operator
。任何想法为什么?【参考方案3】:
日期填充在 R 的 padr
包中实现。如果您存储数据框,则日期时间变量存储为 POSIXct
或 POSIXlt
。您需要做的就是:
library(padr)
pad(df_name)
请参阅 vignette("padr") 或此博客文章了解其工作原理。
【讨论】:
谢谢@edwin。我在rstudio中没有作为自动完成的一部分出现的功能有点麻烦。现在已经修好了。感谢您的回复。 哇,这似乎是一个非常方便的解决方案。不幸的是,我得到“if (!all(dt_var[1:(length(dt_var) - 1)] 您能否分享一个产生此错误的示例?请使用包的github:edwinth/padr【参考方案4】:我认为这可以通过在tidyr
包中使用complete
来完成。
library(tidyverse)
df <- df %>%
complete(timestamp = seq.POSIXt(min(timestamp), max(timestamp), by = "minute"),
tr, tt, sr,st)
您还可以初始化您的开始日期和结束日期,而不是使用min(timestamp)
和max(timestamp)
。
【讨论】:
这个答案非常有帮助,谢谢!使用它时,您是否收到过错误“尚不支持长向量。请求的输出大小必须小于 2147483647”?我似乎无法解决这个问题,我只按原样处理我的数据子集(以加快处理速度,直到我得到正确的代码)。 我还没有看到这个错误,如果你能分享一个你正在尝试做的事情的例子,也许它可以被视为专家。【参考方案5】:# some made-up data
originaldf <- data.frame(timestamp=c("9/1/01 0:00","9/1/01 0:01","9/1/01 0:03","9/1/01 0:04"),
tr = rnorm(4,0,1),
tt = rnorm(4,0,1))
originaldf$minAsPOSIX <- as.POSIXct(originaldf$timestamp, format="%m/%d/%y %H:%M", tz="GMT")
# Generate vector of all minutes
ndays <- 1 # number of days to generate
minAsNumeric <- 60*60*24*243 + seq(0,60*60*24*ndays,by=60)
# convert those minutes to POSIX
minAsPOSIX <- as.POSIXct(minAsNumeric, origin="2001-01-01", tz="GMT")
# new df
newdf <- merge(data.frame(minAsPOSIX),originaldf,all.x=TRUE, by="minAsPOSIX")
【讨论】:
太棒了,让我深入研究一下,看看我是否能理解发生了什么以及如何修改它来满足我的需要。看起来很清晰(相对而言!)。谢谢! 太棒了!如果您发现答案有帮助,我会感谢您通过检查左侧的灰色标记来接受答案。一切顺利,-托马斯 这看起来会起作用 - 没有错误,只有几个问题。实际上,我在原始帖子中弄乱了日期格式-应该是%y-%m-%d %H:%M
。无论如何,我已经编辑了代码来解决这个问题,并且新的时间戳出现了一些错误。例如,使用 2009-01-01 至 2009-01-31(2009 年 1 月 1 日至 31 日)的数据,我在“newdf”中得到以下结果:1 2009-09-01 00:00:00 <NA> NA NA NA NA
- 换句话说,它正在获取时间戳混淆(将月份从 01 设置为 09)并用 NA 填充所有列,即使 Y 值应该可用。
我正在使用的代码(尝试处理 2009 年 1 月的所有数据)是:# set timestamps as POSIXct values at0901mod2$minAsPOSIX <- as.POSIXct(at0901mod2$timestamp, format="%y-%m-%d %H:%M", tz="") # Generate vector of all minutes ndays <- 31 # number of days to generate minAsNumeric <- 60*60*24*243 + seq(0,60*60*24*ndays,by=60) # convert those minutes to POSIX minAsPOSIX <- as.POSIXct(minAsNumeric, origin="2001-01-01", tz="") # new df newdf <- merge(data.frame(minAsPOSIX),at0901mod2,all.x=TRUE, by="minAsPOSIX")
【参考方案6】:
如果您想用零替换上述任何方法获得的 NA 值,您可以这样做:
df[is.na(df)] <- 0
(我原本想对 Ibollar 的回答发表评论,但我缺乏必要的声誉,因此我将其发布为答案)
【讨论】:
【参考方案7】:df1.zoo <- zoo(df1[,-1], as.POSIXlt(df1[,1], format = "%Y-%m-%d %H:%M:%S")) #set date to Index: Notice that column 1 is Timestamp type and is named as "TS"
full.frame.zoo <- zoo(NA, seq(start(df1.zoo), end(df1.zoo), by="min")) # zoo object
full.frame.df <- data.frame(TS = as.POSIXlt(index(full.frame.zoo), format = "%Y-%m-%d %H:%M:%S")) # conver zoo object to data frame
full.vancouver <- merge(full.frame.df, df1, all = TRUE) # merge
【讨论】:
【参考方案8】:在 R 中处理时间序列数据方面有一些进步,例如tsibble
package 整齐地添加了这样的时间序列操作:
library(tsibble)
library(lubridate)
ts <- lubridate::dmy_hm(c("9/1/01 0:00","9/1/01 0:01","9/1/01 0:03","9/1/01 0:27"))
originaldf <- tsibble(timestamp = ts,
tr = rnorm(4,0,1),
tt = rnorm(4,0,1),
index = timestamp)
originaldf %>%
fill_gaps()
【讨论】:
【参考方案9】:我一直在寻找类似的东西,而不是填写缺失的时间戳,我的数据是以月和日为单位的。所以我想生成一个月份序列来满足闰年等等。我用lubridate
:
date <- df$timestamp[1]
date_list <- c(date)
while (date < df$timestamp[nrow(df)])
date <- date %m+% months(1)
date_list <- c(date_list,date)
date_list <- format(as.Date(date_list),"%Y-%m-%d")
df_1 <- data.frame(months=date_list, stringsAsFactors = F)
这会给我一个增量月份的日期列表。然后我加入
df_with_missing_months <- full_join(df_1,df)
【讨论】:
R 中的循环并不是正确的答案。我确信有一种更有效的方法。以上是关于插入缺失日期/时间的行的主要内容,如果未能解决你的问题,请参考以下文章