Roland Kofler Roland Kofler - 2 months ago 9
R Question

transforming a ts in a data.frame and back

The output of a ts looks like a data.frame:

ts(rnorm(12*5, 17, 8), start=c(1981,1), frequency = 12)

Jan Feb Mar Apr May Jun Jul ...
1981 14.064085 21.664250 14.800249 -5.773095 16.477470 1.129674 16.747669 ...
1982 23.973620 17.851890 21.387944 28.451552 24.177141 25.212271 19.123179 ...
1983 19.801210 11.523906 8.103132 9.382778 4.614325 21.751529 9.540851 ...
1984 15.394517 21.021790 23.115453 12.685093 -2.209352 28.318686 10.159940 ...
1985 20.708447 13.095117 32.815273 9.393895 19.551045 24.847337 18.703991 ...


It would be handy if it is easy to transform it into such a data.frame with colums Jan, Feb, Mar... and rows 1981, 1982, ... and then back.
What's the most elegant solution to do it?

Answer

Here are two ways. The first way creates dimnames for the matrix about to be created and then strings out the data into a matrix, transposes it and converts it to data frame. The second way creates a by list consisting of year and month variables and uses tapply on that later converting to data frame and adding names.

# create test data
set.seed(123)
tt <- ts(rnorm(12*5, 17, 8), start=c(1981,1), frequency = 12)

1) matrix. This solution requires that we have whole consecutive years

dmn <- list(month.abb, unique(floor(time(tt))))
as.data.frame(t(matrix(tt, 12, dimnames = dmn)))

If we don't care about the nice names it is just as.data.frame(t(matrix(tt, 12))) .

2) tapply. A more general solution using tapply is:

tapply(tt, list(year = floor(time(tt)), month = month.abb[cycle(tt)]), c)

If we don't care about names we can replace month.abb[cycle(tt)] with just cycle(tt).

Note: To invert this suppose DF is any of the data frame solutions above. Then try:

ts(c(t(DF)), start = 1981, freq = 12)
Comments