【问题标题】:R convert between zoo object and data frame, results inconsistent for different numbers of columns?R在动物园对象和数据框之间转换,不同列数的结果不一致?
【发布时间】:2012-12-13 09:35:03
【问题描述】:

我很难在数据框和动物园对象之间切换,特别是保持有意义的列名,以及单变量和多变量情况之间的不一致:

library(zoo)

#sample data, two species counts over time
t = as.Date(c("2012-01-01", "2012-01-02", "2012-01-03", "2012-01-04"))
n1 = c(4, 5, 9, 7)  #counts of Lepisma saccharina
n2 = c(2, 6, 0, 11) #counts of Thermobia domestica
df = data.frame(t, n1, n2)
colnames(df) <- c("Date", "Lepisma saccharina", "Thermobia domestica")

#converting to zoo loses column names in univariate case...
> z1 <- read.zoo(df[,1:2]) #time series for L. saccharina
> colnames(z1)
NULL
> colnames(z1) <- c("Lepisma saccharina") #can't even set column name manually
Error in `colnames<-`(`*tmp*`, value = "Lepisma saccharina") : 
  attempt to set colnames on object with less than two dimensions
#... but not in multivariate case
> z2 <- read.zoo(df) #time series for both species
> colnames(z2)
[1] "Lepisma saccharina"  "Thermobia domestica"

要从动物园对象返回原始格式的数据框,使用as.data.frame 是不够的,因为它不包含日期列(日期在行名中结束):需要做更多工作.

zooToDf <- function(z) {
    df <- as.data.frame(z) 
    df$Date <- time(z) #create a Date column
    rownames(df) <- NULL #so row names not filled with dates
    df <- df[,c(ncol(df), 1:(ncol(df)-1))] #reorder columns so Date first
    return(df)
}

这在多变量情况下效果很好,但在单变量情况下显然无法恢复有意义的列名:

> df2b <- zooToDf(z2)
> df2b
        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

> df1b <- zooToDf(z1)
> df1b
        Date z
1 2012-01-01 4
2 2012-01-02 5
3 2012-01-03 9
4 2012-01-04 7

有没有一种简单的方法来处理两种单变量多变量情况?看来z1 需要以某种方式记住列名。

【问题讨论】:

  • 自我注意:“drop”的基本问题有时会导致单变量和多变量情况之间的不一致,这通常出现在数据帧中,而不仅仅是转换为动物园对象时。请参阅data.tabledatatable.r-forge.r-project.org/datatable-faq.pdf 的常见问题解答,其中开发人员指出“在[.data.frame 中,我们经常设置drop=FALSE。当我们忘记时,在选择单列并且突然向量为返回而不是单列 data.frame。在[.data.table 中,我们借此机会使其保持一致并丢弃。”
  • 问题中所谓的不一致是即使没有动物园,R 也是如何工作的。事实上,zoo 与 R 的工作方式是一致的。如果它不以这种方式工作,那将是不一致的。

标签: r dataframe zoo


【解决方案1】:

如果您不想删除尺寸,请使用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

如果您想将动物园索引作为列包含在 data.frame 中,您可以执行 write.zoo 之类的操作:

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))
}

更新:

为了简洁起见,在尝试编辑您的问题后,我想到了一种根据您的规范创建 df2b 的简单方法(如果您不删除尺寸,这也适用于 z1):

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

【讨论】:

  • fortify.zoo(z1) ?
【解决方案2】:

要将数据框转换为动物园,请使用read.zoo:

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

还要注意drop?read.zoo 中的其他参数的可用性。

要从动物园转换为数据框,包括索引,请使用fortify.zoo

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

(如果加载了 ggplot2,则可以使用 fortify。)

正如问题下方的 cmets 所述,该问题以及其他一些答案要么已过时,要么存在一些重大误解。建议您查看https://cran.r-project.org/web/packages/zoo/vignettes/zoo-design.pdf,其中讨论了 zoo 的设计理念,其中包括与 R 本身的一致性。当然,如果您必须记住 R 的一组默认值和 zoo 的另一组默认值,那么 zoo 会更难使用。

【讨论】:

    【解决方案3】:

    使用timetk 包有一个更新的简单解决方案。它将包括xtszoo在内的几种时间序列格式转换为tibbles。只需将as.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
    

    【讨论】:

      【解决方案4】:

      我想绕一圈。首先,将动物园写入 csv 文件,然后再次将其读取到 data.frame。默认情况下,索引列将命名为“索引”,但您可以使用参数进行更改。

      library(zoo)
      date <-
        seq.Date(
          from = as.Date("2017-01-01"),
          to = as.Date("2017-01-10"),
          by = "days"
        )
      value <- seq.int(from = 100, to = length(date))
      vzoo <- zoo(value, date)
      write.zoo(
        vzoo,
        index.name = "Date",
        file = "tmp.txt",
        sep = ",",
        col.names = TRUE
      )
      vzoo.df <- read.csv("tmp.txt", sep = ',')
      

      【讨论】:

        【解决方案5】:

        您可以简单地创建一个新数据集并添加 as.data.frame 来包装 fortify.zoo。这应该会有所帮助。 z2=as.data.frame(fortify.zoo(z, name = "Date"))

        【讨论】:

          猜你喜欢
          • 2021-11-02
          • 2020-12-23
          • 1970-01-01
          • 1970-01-01
          • 2017-02-28
          • 2014-11-15
          • 2012-02-27
          • 2014-07-22
          • 1970-01-01
          相关资源
          最近更新 更多