R конвертировать между объектом zoo и фреймом данных, результаты противоречивы для разных номеров столбцов?
Мне сложно переключаться между кадрами данных и объектами зоопарка, особенно сохраняя значимые имена столбцов и несоответствия между одномерными и многомерными случаями:
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
, так как он не будет включать столбец Date (даты в итоге в именах ростов): требуется больше работы,
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
нужно как-то запомнить имя столбца.
Ответы
Ответ 1
Для преобразования из фрейма данных в зоопарк используйте read.zoo
:
library(zoo)
z <- read.zoo(df)
Также обратите внимание на наличие drop
и других аргументов в ?read.zoo
.
и для преобразования из зоопарка во фрейм данных, включая индекс, используйте fortify.zoo
:
fortify.zoo(z, name = "Date")
(Если загружен ggplot2, вы можете просто использовать fortify
.)
Как упомянуто в комментариях под вопросом, вопрос, а также некоторые другие ответы либо устарели, либо имеют серьезные недоразумения. Предлагаем вам ознакомиться с https://cran.r-project.org/web/packages/zoo/vignettes/zoo-design.pdf, в котором обсуждается философия дизайна зоопарка, которая включает согласованность с самим R. Конечно, использовать зоопарк было бы намного сложнее, если бы вы запомнили один набор значений по умолчанию для R и другой для зоопарка.
Ответ 2
Если вы не хотите отбрасывать размеры, используйте 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
Вы можете сделать что-то вроде write.zoo
, если вы хотите включить индекс zoo в качестве столбца в вашем файле 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:
После краткого изложения вашего вопроса я подумал о том, как легко создать 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
Ответ 3
Есть более новое простое решение для этого, используя пакет timetk
. Он преобразует несколько форматов временных рядов, включая xts
и zoo
, в tibble
s. Просто 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"))