R convert between zoo object and data frame, results inconsistent for different numbers of columns?

If you don't want to drop dimensions, use drop=FALSE:

R> (z1 <- read.zoo(df[,1:2], drop=FALSE))
           Lepisma saccharina
2012-01-01                  4
2012-01-02                  5
2012-01-03                  9
2012-01-04                  7

You can do something like write.zoo if you want to include the zoo index as a column in your data.frame:

zoo.to.data.frame <- function(x, index.name="Date") {
  stopifnot(is.zoo(x))
  xn <- if(is.null(dim(x))) deparse(substitute(x)) else colnames(x)
  setNames(data.frame(index(x), x, row.names=NULL), c(index.name,xn))
}

UPDATE:

After trying to edit your question for brevity, I thought of an easy way to create df2b to your specifications (this will also work for z1 if you don't drop dimensions):

R> (df2b <- data.frame(Date=time(z2), z2, check.names=FALSE, row.names=NULL))
        Date Lepisma saccharina Thermobia domestica
1 2012-01-01                  4                   2
2 2012-01-02                  5                   6
3 2012-01-03                  9                   0
4 2012-01-04                  7                  11

To convert from data frame to zoo use read.zoo:

library(zoo)
z <- read.zoo(df)

Also note the availability of the drop and other arguments in ?read.zoo .

and to convert from zoo to data frame, including the index, use fortify.zoo:

fortify.zoo(z, name = "Date")

(If ggplot2 is loaded then you can just use fortify.)

As mentioned in the comments below the question, the question as well as some of the other answers are either outdated or have some significant misunderstandings. Suggest you review https://cran.r-project.org/web/packages/zoo/vignettes/zoo-design.pdf which discusses the design philosophy of zoo which includes consistency with R itself. Certainly zoo would be a lot harder to use if you had to remember one set of defaults for R and another for zoo.


There's a newer simple solution to this using the timetk package. It will convert several time series formats, including xts and zoo, to tibbles. Simply wrap in as.data.frame to get a data frame.

timetk::tk_tbl(zoo::read.zoo(df))
# A tibble: 4 x 3
  index      `Lepisma saccharina` `Thermobia domestica`
  <date>                    <dbl>                 <dbl>
1 2012-01-01                    4                     2
2 2012-01-02                    5                     6
3 2012-01-03                    9                     0
4 2012-01-04                    7                    11

Tags:

R

Dataframe

Zoo