将原始数据框转换为可行的时间序列

时间:2016-01-05 12:29:36

标签: r time-series

我有一张电子表格,记录了不同日期40种类似产品的价格。它看起来像这样。

date_1<-seq(as.Date("2010-01-01"), as.Date("2011-01-01"), length.out = 40)
date_2<-seq(as.Date("2011-01-01"), as.Date("2012-01-01"), length.out = 40)
date_3<-seq(as.Date("2012-01-01"), as.Date("2013-01-01"), length.out = 40)
date_4<-seq(as.Date("2013-01-01"), as.Date("2014-01-01"), length.out = 40)
date_5<-seq(as.Date("2014-01-01"), as.Date("2015-01-01"), length.out = 40)
date_6<-seq(as.Date("2015-01-01"), as.Date("2016-01-01"), length.out = 40)

price_1<-floor(seq(20, 50, length.out = 40))
price_2<-floor(seq(20, 60, length.out = 40))
price_3<-floor(seq(20, 70, length.out = 40))
price_4<-floor(seq(30, 80, length.out = 40))
price_5<-floor(seq(40, 100, length.out = 40))
price_6<-floor(seq(50, 130, length.out = 40))

data.frame(date_1,price_1,date_2,price_2,date_3,price_3,date_4,price_4,date_5,price_5,date_6,price_6)

问题是,代表日期和价格的列是交替的(便于记录保存)。如何将上述数据转换为仅包含这40个产品的价格作为行的新数据框,日期为列名?这会生成很多NA,因为每列中的日期不同但是没问题。

3 个答案:

答案 0 :(得分:2)

以下是我使用dplyr / tidyr软件包提出的一种方法:

library(tidyr)
library(dplyr)
date_1<-seq(as.Date("2010-01-01"), as.Date("2011-01-01"), length.out = 40)
date_2<-seq(as.Date("2011-01-01"), as.Date("2012-01-01"), length.out = 40)
date_3<-seq(as.Date("2012-01-01"), as.Date("2013-01-01"), length.out = 40)
date_4<-seq(as.Date("2013-01-01"), as.Date("2014-01-01"), length.out = 40)
date_5<-seq(as.Date("2014-01-01"), as.Date("2015-01-01"), length.out = 40)
date_6<-seq(as.Date("2015-01-01"), as.Date("2016-01-01"), length.out = 40)

price_1<-floor(seq(20, 50, length.out = 40))
price_2<-floor(seq(20, 60, length.out = 40))
price_3<-floor(seq(20, 70, length.out = 40))
price_4<-floor(seq(30, 80, length.out = 40))
price_5<-floor(seq(40, 100, length.out = 40))
price_6<-floor(seq(50, 130, length.out = 40))

df <- data.frame(date_1,price_1,date_2,price_2,date_3,price_3,date_4,price_4,date_5,price_5,date_6,price_6)

dates <- df[, grep('date', names(df))]
dates <- dates %>% gather(date_type, date) %>% select(-date_type)

prices <- df[, grep('price', names(df))]
prices <- prices %>% gather(price_type, price) %>% select(-price_type)

df <- cbind(dates, prices)

然后,要将日期分配到列和价格到行,您可以执行以下操作:

df <- arrange(df, price)
df <- spread(df, date, price)

答案 1 :(得分:2)

使用baseRtidyr即可:

 library(tidyr)
    #add an id to identify the products
    df$id=1:40

    #transform the data to a long format
    long_data <- reshape(df,idvar="id",varying=list(paste0("date_",1:6),paste0("price_",1:6)),v.names=c("date","price"),direction="long",sep="_")
    long_data <- long_data[,!grepl("time",colnames(long_data))]


    #put it back to a wide format
    wide_data <- spread(long_data,date,price)

答案 2 :(得分:2)

使用时间序列数据时,即使您的目标输出很宽(每个时间序列一行),以长格式(每次观察一行)通常也很有帮助。这里有三种可能的方法可以将它变成长形,然后加宽:

1。基地reshape()

要获得长篇,基础reshape绝对是一个强大的选择。以下解决方案改进了已接受的解决方案,因为它适用于任意数量的产品和观察,并消除了不必要的步骤:

df <- data.frame(date_1,price_1,date_2,price_2,date_3,price_3,
                 date_4,price_4,date_5,price_5,date_6,price_6)

# no need to create an id variable
long_form <- reshape(df, # idvar="id" by default
                     varying = list(grep('date_',names(df), value=TRUE), 
                                    grep('price_',names(df), value=TRUE) ),
                     v.names=c("date","price"),
                     direction="long",
                     sep="_")

reshape也可以扩大它。 (我们将在下面的另一种方法中使用spread。)

wide_form <- reshape(long_form, drop='time', timevar='date', direction='wide')  

2。 data.table melt()dcast()(在真实数据集上可能更快)

确保您拥有data.table v1.9.6或更高版本,这样您就可以融合多列。

library(data.table)
setDT(df)
melt.data.table(df[, prod_id := .I], # product id = original row number
                measure.vars = list(grep('date_',names(df), value=TRUE), 
                                    grep('price_',names(df), value=TRUE) ),
                variable.name = 'sequence',
                value.name = c('date','price'),
                id.vars = 'prod_id') -> long_form

在这种情况下,你不会使用序列,所以要获得宽格式只是:

dcast.data.table(long_form[, !'sequence', with=FALSE], 
                 value.var = 'price', # optional (function guesses correctly)
                 prod_id ~  date) -> wide_form

3。 tidyr&amp; dplyr split-apply-combine(易于理解)

它并不需要reshape所做的心理体操(至少对我而言)。它是&#34; split-apply-combine&#34;的一个列式变体。范例

library(dplyr); library(tidyr)

# Create long-form time series data
# Split table into sequenced prices and dates, then combine on product and sequence
full_join(
  df %>%
    select(starts_with('date_')) %>%      #~~~~ Left side = date component ~~~~~~~~
    mutate(prod_id = 1:nrow(df)) %>%      #~ product id = original row number     ~
    gather(sequence, date, -prod_id) %>%  #~ long form = 1 row per prod per seq   ~
    mutate(sequence =                     #~~~ Cols: product_id, sequence, date ~~~ 
            sub('^date_(\\d+)$', '\\1', sequence) )  ,   
  df %>%
    select(starts_with('price_')) %>%     #~~~ Right side = price component ~~~~~~~
    mutate(prod_id = 1:nrow(df)) %>%      #~                                      ~
    gather(sequence, price, -prod_id) %>% #~        same idea                     ~
    mutate(sequence =                     #~~ Cols: product_id, sequence, price ~~~
             sub('^price_(\\d+)$', '\\1', sequence) ) 
) -> long_form

在这种情况下,你不需要序列,所以要简单地形成它:

long_form %>% select(-sequence) %>% spread(date, price) -> wide_form

正如上面其他人所指出的那样。