合并两个不规则时间序列

17

我有两个多元时间序列x和y,它们的时间范围大致相同(其中一个在另一个之前两年开始,但它们在同一日期结束)。这两个序列都有缺失观察值,既是在日期列旁边的空列中,也是因为其中一个序列有几个在另一个序列中找不到的日期,反之亦然。

我想创建一个数据框(或类似的结构),其中包含一列列出在x或y中找到的所有日期,没有重复的日期。对于每个日期(行),我想将来自x的观察值与来自y的观察值水平堆叠在一起,并用NA填充丢失的单元格。例如:

>x
"1987-01-01"   7.1    NA   3
"1987-01-02"   5.2    5    2
"1987-01-06"   2.3    NA   9

>y
"1987-01-01"   55.3   66   45
"1987-01-03"   77.3   87   34

# result I would like
"1987-01-01"   7.1    NA   3   55.3   66   45
"1987-01-02"   5.2    5    2   NA     NA   NA
"1987-01-03"   NA     NA   NA  77.3   87   34
"1987-01-06"   2.3    NA   9   NA     NA   NA

我尝试了以下方法:使用zoo包的merge.zoo方法,但这似乎只是将两个序列并排放置在一起,并且来自每个序列的日期(以数字形式,例如“1987-01-02”显示为6210)出现在两个单独的列中。

我已经坐了几个小时几乎没有进展,所以任何帮助都会很感激。

编辑:根据Soumendra的建议,包含一些代码如下:

atcoa <- read.csv(file = "ATCOA_full_adj.csv", header = TRUE)
atcob <- read.csv(file = "ATCOB_full_adj.csv", header = TRUE)
atcoa$date <- as.Date(atcoa$date)
atcob$date <- as.Date(atcob$date)

# only number of observations and the observations themselves differ 
>str(atcoa)
'data.frame':   6151 obs. of  8 variables:
 $ date        :Class 'Date'  num [1:6151] 6210 6213 6215 6216 6217 ...
 $ max         : num  4.31 4.33 4.38 4.18 4.13 4.05 4.08 4.05 4.08 4.1 ...
 $ min         : num  4.28 4.31 4.28 4.13 4.05 3.95 3.97 3.95 4 4.02 ...
 $ close       : num  4.31 4.33 4.31 4.15 4.1 3.97 4 3.97 4.08 4.02 ...
 $ avg         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ tot.vol     : int  877733 89724 889437 1927113 3050611 846525 1782774 1497998 2504466 5636999 ...
 $ turnover    : num  3762300 388900 3835900 8015900 12468100 ...
 $ transactions: int  12 9 24 17 31 26 34 35 37 33 ...

>atcoa[1:1, ]
date a.max a.min a.close a.avg a.tot.vol a.turnover a.transactions
1 1987-01-02  4.31  4.28    4.31    NA    877733    3762300             12

# using timeSeries package
ts.atcoa <- timeSeries::as.timeSeries(atcoa, format = "%Y-%m-%d")
ts.atcob <- timeSeries::as.timeSeries(atcob, format = "%Y-%m-%d")

>str(ts.atcoa)
Time Series:          
 Name:               object
Data Matrix:        
 Dimension:          6151 7
 Column Names:       a.max a.min a.close a.avg a.tot.vol a.turnover a.transactions
 Row Names:          1970-01-01 01:43:30  ...  1970-01-01 04:12:35
Positions:          
 Start:              1970-01-01 01:43:30
 End:                1970-01-01 04:12:35
With:               
 Format:             %Y-%m-%d %H:%M:%S
 FinCenter:          GMT
 Units:              a.max a.min a.close a.avg a.tot.vol a.turnover a.transactions
 Title:              Time Series Object
 Documentation:      Wed Aug 17 13:00:50 2011

>ts.atcoa[1:1, ]
GMT
 a.max a.min a.close a.avg a.tot.vol a.turnover a.transactions
 1970-01-01 01:43:30  4.31  4.28    4.31    NA    877733    3762300             12

# The following will create an object of class "data frame" and mode "list", which contains observations for the days mutual for the two series
>ts.atco <- timeSeries::merge(atcoa, atcob)  # produces same result as base::merge, apparently
>ts.atco[1:1, ]
date a.max a.min a.close a.avg a.tot.vol a.turnover a.transactions b.max b.min b.close b.avg b.tot.vol b.turnover b.transactions
1 1989-08-25  7.92  7.77    7.79    NA    269172    2119400             19  7.69  7.56    7.64    NA  81176693  593858000             12

编辑:通过使用zoo包解决了问题

atcoa <- read.zoo(read.csv(file = "ATCOA_full_adj.csv", header = TRUE))
atcob <- read.zoo(read.csv(file = "ATCOB_full_adj.csv", header = TRUE))

names(atcoa) <- c("a.max", "a.min", "a.close",
                   "a.avg", "a.tot.vol", "a.turnover", "a.transactions")
names(atcob) <- c("b.max", "b.min", "b.close",
                   "b.avg", "b.tot.vol", "b.turnover", "b.transactions")

atco <- merge.zoo(atcoa, atcob)

感谢大家的帮助。


1
你没有展示你实际尝试过什么,但是merge.zoo肯定不只是堆叠zoo对象。merge.zoo有一个帮助页面,其中包括文档和许多示例:?merge.zoo。此外,还有5个vignettes(pdf文档)与zoo一起提供额外的文档和示例。请参阅下面的我的帖子以获取更多信息。 - G. Grothendieck
建议您这样做:nms <- c("", "max", "min", "close", "avg", "tot.vol", "turnover", "transactions"); atcoa <- read.zoo("ATCOA_full_adj.dat", header = TRUE, col.names = paste("a", nms, sep = "."))。此外,由于它看起来不是一个逗号分隔的文件(csv),在给文件命名时最好不要使用csv作为扩展名。 - G. Grothendieck
4个回答

11

试一试这个:

Lines.x <- '"1987-01-01"   7.1    NA   3
"1987-01-02"   5.2    5    2
"1987-01-06"   2.3    NA   9'

Lines.y <- '"1987-01-01"   55.3   66   45
"1987-01-03"   77.3   87   34'

library(zoo)
# in reality x might be in a file and might be read via: x <- read.zoo("x.dat")
# ditto for y. See ?read.zoo and the zoo-read vignette if you need other args too
x <- read.zoo(text = Lines.x)
y <- read.zoo(text = Lines.y)
merge(x,  y)

提供:

           V2.x V3.x V4.x V2.y V3.y V4.y
1987-01-01  7.1   NA    3 55.3   66   45
1987-01-02  5.2    5    2   NA   NA   NA
1987-01-03   NA   NA   NA 77.3   87   34
1987-01-06  2.3   NA    9   NA   NA   NA

对于 Lines.x 和 Lines.y,您是指这些需要手动输入吗?数据集太大了,手动输入不现实。 - Benjamin Allévius
我认为上面答案中的评论建议您使用read.zoo来读取文件。 x <- read.zoo("ATCOA_full_adj.csv") y <- read.zoo("ATCOB_full_adj.csv") 合并(x,y) - Sameer
啊,你说得对。这解决了问题;我会更新原始帖子。 - Benjamin Allévius
如果您正在使用read.zoo,那么您就不需要再使用read.csv了,因为它们都在底层使用read.table。您只需编写read.zoo("ATCOA_full_adj.csv", header=T)即可。希望对您有所帮助。 - Sameer

3
您可以使用timeSeries库从日期中创建timeSeries对象,将它们合并(timeSeries的默认合并行为与zoo和xts不同,并且确切地做了您要求的事情),然后根据需要将结果转换成zoo/xts对象,如果您不想使用timeSeries。
测试的一个快速方法如下,假设您有两个zoo对象zz1和zz2-
library(timeSeries)
as.zoo(merge(as.timeSeries(zz1), as.timeSeries(zz2)))

请将上述命令的输出与下面的内容进行比较。
merge(zz1, zz2)

你可以使用cbind -
cbind(zz1, zz2)

假设没有同名的列,你可以选择想要合并的列用cbind函数来合并,这样你将得到一个zoo对象。

cbind(zz1[, 1:2], zz2[, 2:3]) #Assuming other columns are common

1
谢谢。当我尝试您的方法时,我注意到以下问题:当我在一个日期格式为“%Y-%m-%d”的数据框上使用as.timeSeries时,创建的timeSeries对象将具有日期格式“%Y-%m-%d %H:%M:%S”,而我在函数中指定的format =“%Y-%m-%d”似乎被忽略了。如果我然后合并(使用base :: merge或timeSeries :: merge)两个这样的timeSeries对象,我会得到一个日期格式为“%Y-%m-%d”的数据框,其中仅包含两个对象共同的日期。但是,列包含我想要的信息(就像示例中一样)。有什么解决方法吗? - Benjamin Allévius
原始帖子中已包含代码。 - Benjamin Allévius
as.zoo(merge(as.timeSeries(zz1), as.timeSeries(zz2)))merge(as.timeSeries(zz1), as.timeSeries(zz2)) 有什么区别?我喜欢你的回答。 - johnatasjmo

2

这里,我从stat.ethz.ch找到了一种更通用的方法。

a <- ts(1:10, start=c(2014,6), frequency=12)
b <- ts(1:12, start=c(2015,1), frequency=12)

library(zoo)
m <- merge(a = as.zoo(a), b = as.zoo(b))

获得一个ts对象:

as.ts(m)

第五行末尾的“m”是打错了吗? - EngrStudent

1
这样怎么样?
## Generate unique sorted time values.
i <- sort(unique(c(index(x), index(y))))

## Empty data matrix.
v <- matrix(nrow=length(i), ncol=6, NA)

## Pull in data items.
v[match(index(x), i), 1:3] <- coredata(x)
v[match(index(y), i), 4:6] <- coredata(y)

## Build new zoo object.
d <- zoo(v, order.by=i)

你可能在这方面有些眉目,需要进行一些修改:如果我在赋值给i的时候跳过index(x)和index(y),那么我将得到一个唯一日期的向量(如果只使用索引,它将不起作用,因为两个对象之间没有关联,我必须比较日期)。我可以像你建议的那样,用它来填充矩阵的第一列。然而,我不确定“拉入数据项”阶段是否仍然有效:相反,我可能应该将x和y的日期列与矩阵的第一列进行比较,如果有匹配的话则分配元素。 - Benjamin Allévius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接