5

I am very new to time series forecasting using Prophet in R. I am able to predict values for one single product using Prophet. Is there any way if i can use loop to generate forecast using Prophet for multiple products? The below code works absolutely fine for single product but i am trying to generate forecasts for multiple products

 library(prophet)
 df <- read.csv("Prophet.csv")
 df$Date<-as.Date(as.character(df$Date), format =  "%d-%m-%Y")
 colnames(df) <- c("ds", "y")
 m <- prophet(df)
 future <- make_future_dataframe(m, periods = 40)
 tail(future)
 forecast <- predict(m, future)
 write.csv(forecast[c('ds','yhat')],"Output_Prophet.csv")
 tail(forecast[c('ds', 'yhat', 'yhat_lower', 'yhat_upper')])

Sample Dataset:

enter image description here

merv
  • 67,214
  • 13
  • 180
  • 245
hari babu
  • 97
  • 1
  • 7
  • A reprex will help us give you an answer. https://reprex.tidyverse.org/articles/reprex-dos-and-donts.html – pedram Aug 29 '18 at 06:21

1 Answers1

6

This can be done by using lists and map functions from the purrr package.

Lets build some data:

library(tidyverse) # contains also the purrr package
set.seed(123)
tb1 <- tibble(
  ds = seq(as.Date("2018-01-01"), as.Date("2018-12-31"), by = "day"),
  y = sample(365)
)
tb2 <- tibble(
  ds = seq(as.Date("2018-01-01"), as.Date("2018-12-31"), by = "day"),
  y = sample(365)
)

ts_list <- list(tb1, tb2) # two separate time series
# using this construct you could add more of course

Build and prediction:

library(prophet)

m_list <- map(ts_list, prophet) # prophet call

future_list <- map(m_list, make_future_dataframe, periods = 40) # makes future obs

forecast_list <- map2(m_list, future_list, predict) # map2 because we have two inputs

# we can access everything we need like with any list object
head(forecast_list[[1]]$yhat) # forecasts for time series 1
[1] 179.5214 198.2375 182.7478 173.5096 163.1173 214.7773
head(forecast_list[[2]]$yhat) # forecast for time series 2
[1] 172.5096 155.8796 184.4423 133.0349 169.7688 135.2990

Update (just the input part, build and prediction part it's the same):

I created a new example based on OP request, basically you need to put everything again in a list object:

# suppose you have a data frame like this:
set.seed(123)
tb1 <- tibble(
  ds = seq(as.Date("2018-01-01"), as.Date("2018-12-31"), by = "day"),
  productA = sample(365),
  productB = sample(365)
)
head(tb1)
# A tibble: 6 x 3
  ds         productA productB
  <date>        <int>    <int>
1 2018-01-01      105      287
2 2018-01-02      287       71
3 2018-01-03      149        7
4 2018-01-04      320      148
5 2018-01-05      340      175
6 2018-01-06       17      152

# with some dplyr and base R you can trasform each time series in a data frame within a list
ts_list <- tb1 %>% 
  gather("type", "y", -ds) %>% 
  split(.$type)
# this just removes the type column that we don't need anymore
ts_list <- lapply(ts_list, function(x) { x["type"] <- NULL; x })

# now you can continue just like above..
RLave
  • 8,144
  • 3
  • 21
  • 37
  • Thanks RLave. Is it possible to use for loop to call more inputs? i have close to 50 items which need to be forecasted using Prophet?? – hari babu Aug 29 '18 at 06:58
  • Just put them in a list like I did, use a for loop to read them then you can follow what I did for 2 – RLave Aug 29 '18 at 07:04
  • Sorry RLave, i am facing some challenges in creating that loop to call more inputs. can you share sample code snippet here? I have pasted sample dataset above – hari babu Aug 29 '18 at 07:40
  • Do you have more than one excel file or just one with 50 columns? I'll update my anwer based on your sample dataset. – RLave Aug 29 '18 at 07:55
  • one excel sheet, with one column for date and other columns have sales for different products – hari babu Aug 29 '18 at 07:59
  • This is how i have used for ARIMA Data_ts <- ts(result[,],f=7) h <- 50 ns <- ncol(Data_ts) arimaforecast <- matrix(NA, nrow=h, ncol=ns) for (i in 1:ns){ arimaforecast[,i] <- forecast(auto.arima(Data_ts[,i]), h=h)$mean} – hari babu Aug 29 '18 at 08:03
  • 1
    @hari babu Updated the answer. Please note that you should always try to post an example of your data, rather than an image. – RLave Aug 29 '18 at 08:15
  • Now you can use `read.csv` to import your data, proceed with the second option I posted with the update, then you can use the Build and Prediction part. – RLave Aug 29 '18 at 08:18
  • Do you think this will be right step? or suggest improvements df <- read.csv("Prophet_2_List.csv") df$Date<-as.Date(as.character(df$Date), format = "%d-%m-%Y") ns <- ncol(df) tb1 <- tibble( ds = df$Date, for (i in 1:ns){ product[i] = df[,i] } ) – hari babu Aug 29 '18 at 08:44
  • No, after the `read.csv` and after you fix the date you should just continue with my code above (ONLY the part where I trasform it to a list). Remember to rename the column `Date` as `ds`. – RLave Aug 29 '18 at 08:52
  • in the above example, there are only two products for forecasting but in my case i have close to 50products in 50 columns for forecasting and 1 column for date. I need to use some of sort of loop to read all those 50 columns and store in tibble – hari babu Aug 29 '18 at 08:55
  • No you don't, 2 are just for example, it could be 100, the tibble part is just because I had to create some fake data to show how it works. If you import the data and have a data.frame with 50 columns you should proceed from the last part where I use `gather` and `split`. Just make sure that every name coincides. – RLave Aug 29 '18 at 08:58
  • Excellent answer. I am wondering what would be the case if we need to deal with unequal length of lists. To be specific, let's assume we have 50 obs instead of 60 for product B. In that case, you cannot use `tbl_df` as it require equal length of all lists. Any idea what to do in that case? @RLave – small_lebowski Feb 27 '19 at 14:58
  • 1
    @hmhsl as long as you work with list that should not be a problem, if you run into some problems you can ask a specific new question on SO. Of course if you have a `data.frame`, you can't have two products with different lengths, so you'd need to follow my first example where I start with two, and use `list()` – RLave Feb 27 '19 at 15:04