Applied Metaphors: Learning TRIZ, Complexity, Data/Stats/ML using Metaphors
  1. Teaching
  2. R for Artists and Managers
  3. Lab-12: Time is a Him!!
  • Teaching
    • Data Analytics for Managers and Creators
      • Tools
        • Introduction to R and RStudio
        • Introduction to Radiant
        • Introduction to Orange
      • Descriptive Analytics
        • Data
        • Summaries
        • Counts
        • Quantities
        • Groups
        • Densities
        • Groups and Densities
        • Change
        • Proportions
        • Parts of a Whole
        • Evolution and Flow
        • Ratings and Rankings
        • Surveys
        • Time
        • Space
        • Networks
        • Experiments
        • Miscellaneous Graphing Tools, and References
      • Statistical Inference
        • 🧭 Basics of Statistical Inference
        • 🎲 Samples, Populations, Statistics and Inference
        • Basics of Randomization Tests
        • 🃏 Inference for a Single Mean
        • 🃏 Inference for Two Independent Means
        • 🃏 Inference for Comparing Two Paired Means
        • Comparing Multiple Means with ANOVA
        • Inference for Correlation
        • 🃏 Testing a Single Proportion
        • 🃏 Inference Test for Two Proportions
      • Inferential Modelling
        • Modelling with Linear Regression
        • Modelling with Logistic Regression
        • 🕔 Modelling and Predicting Time Series
      • Predictive Modelling
        • 🐉 Intro to Orange
        • ML - Regression
        • ML - Classification
        • ML - Clustering
      • Prescriptive Modelling
        • 📐 Intro to Linear Programming
        • 💭 The Simplex Method - Intuitively
        • 📅 The Simplex Method - In Excel
      • Workflow
        • Facing the Abyss
        • I Publish, therefore I Am
      • Case Studies
        • Demo:Product Packaging and Elderly People
        • Ikea Furniture
        • Movie Profits
        • Gender at the Work Place
        • Heptathlon
        • School Scores
        • Children's Games
        • Valentine’s Day Spending
        • Women Live Longer?
        • Hearing Loss in Children
        • California Transit Payments
        • Seaweed Nutrients
        • Coffee Flavours
        • Legionnaire’s Disease in the USA
        • Antarctic Sea ice
        • William Farr's Observations on Cholera in London
    • R for Artists and Managers
      • 🕶 Lab-1: Science, Human Experience, Experiments, and Data
      • Lab-2: Down the R-abbit Hole…
      • Lab-3: Drink Me!
      • Lab-4: I say what I mean and I mean what I say
      • Lab-5: Twas brillig, and the slithy toves…
      • Lab-6: These Roses have been Painted !!
      • Lab-7: The Lobster Quadrille
      • Lab-8: Did you ever see such a thing as a drawing of a muchness?
      • Lab-9: If you please sir…which way to the Secret Garden?
      • Lab-10: An Invitation from the Queen…to play Croquet
      • Lab-11: The Queen of Hearts, She Made some Tarts
      • Lab-12: Time is a Him!!
      • Iteration: Learning to purrr
      • Lab-13: Old Tortoise Taught Us
      • Lab-14: You’re are Nothing but a Pack of Cards!!
    • ML for Artists and Managers
      • 🐉 Intro to Orange
      • ML - Regression
      • ML - Classification
      • ML - Clustering
      • 🕔 Modelling Time Series
    • TRIZ for Problem Solvers
      • I am Water
      • I am What I yam
      • Birds of Different Feathers
      • I Connect therefore I am
      • I Think, Therefore I am
      • The Art of Parallel Thinking
      • A Year of Metaphoric Thinking
      • TRIZ - Problems and Contradictions
      • TRIZ - The Unreasonable Effectiveness of Available Resources
      • TRIZ - The Ideal Final Result
      • TRIZ - A Contradictory Language
      • TRIZ - The Contradiction Matrix Workflow
      • TRIZ - The Laws of Evolution
      • TRIZ - Substance Field Analysis, and ARIZ
    • Math Models for Creative Coders
      • Maths Basics
        • Vectors
        • Matrix Algebra Whirlwind Tour
        • content/courses/MathModelsDesign/Modules/05-Maths/70-MultiDimensionGeometry/index.qmd
      • Tech
        • Tools and Installation
        • Adding Libraries to p5.js
        • Using Constructor Objects in p5.js
      • Geometry
        • Circles
        • Complex Numbers
        • Fractals
        • Affine Transformation Fractals
        • L-Systems
        • Kolams and Lusona
      • Media
        • Fourier Series
        • Additive Sound Synthesis
        • Making Noise Predictably
        • The Karplus-Strong Guitar Algorithm
      • AI
        • Working with Neural Nets
        • The Perceptron
        • The Multilayer Perceptron
        • MLPs and Backpropagation
        • Gradient Descent
      • Projects
        • Projects
    • Data Science with No Code
      • Data
      • Orange
      • Summaries
      • Counts
      • Quantity
      • 🕶 Happy Data are all Alike
      • Groups
      • Change
      • Rhythm
      • Proportions
      • Flow
      • Structure
      • Ranking
      • Space
      • Time
      • Networks
      • Surveys
      • Experiments
    • Tech for Creative Education
      • 🧭 Using Idyll
      • 🧭 Using Apparatus
      • 🧭 Using g9.js
    • Literary Jukebox: In Short, the World
      • Italy - Dino Buzzati
      • France - Guy de Maupassant
      • Japan - Hisaye Yamamoto
      • Peru - Ventura Garcia Calderon
      • Russia - Maxim Gorky
      • Egypt - Alifa Rifaat
      • Brazil - Clarice Lispector
      • England - V S Pritchett
      • Russia - Ivan Bunin
      • Czechia - Milan Kundera
      • Sweden - Lars Gustaffsson
      • Canada - John Cheever
      • Ireland - William Trevor
      • USA - Raymond Carver
      • Italy - Primo Levi
      • India - Ruth Prawer Jhabvala
      • USA - Carson McCullers
      • Zimbabwe - Petina Gappah
      • India - Bharati Mukherjee
      • USA - Lucia Berlin
      • USA - Grace Paley
      • England - Angela Carter
      • USA - Kurt Vonnegut
      • Spain-Merce Rodoreda
      • Israel - Ruth Calderon
      • Israel - Etgar Keret
  • Posts
  • Blogs and Talks

On this page

  • Introduction
  • Introduction to Time Series: Data Formats
  • Creating time series
    • ts format data
    • tibble format data
    • tsibble format data
  • One more example
  • Decomposing Time Series
  • Conclusion
  • References
  1. Teaching
  2. R for Artists and Managers
  3. Lab-12: Time is a Him!!

Lab-12: Time is a Him!!

Time Series in R

Line Charts
Boxplot Charts
Heatmaps
Averaging
Predictions
Exponential Smoothing
ARIMA models
Forecasting
Author

Arvind Venkatadri

Published

February 14, 2022

Modified

June 12, 2025

Introduction

Time Series data are important in data visualization where events have a temporal dimension, such as with finance, transportation, music, telecommunications for example.

library(tidyverse)
library(mosaic)
library(ggformula)
##########################################
# Install core TimeSeries Packages
# library(ctv)
# ctv::install.views("TimeSeries", coreOnly = TRUE)
# To update core TimeSeries packages
# ctv::update.views("TimeSeries")
# Time Series Core Packages
##########################################
library(tsibble)
library(feasts) # Feature Extraction and Statistics for Time Series
library(fable) # Forecasting Models for Tidy Time Series
library(tseries) # Time Series Analysis and Computational Finance
library(forecast)
library(zoo)
##########################################
library(tsibbledata) # Time Series Demo Datasets
## New package from Mitchell Ohara-Wild in June 2025
library(ggtime)

Introduction to Time Series: Data Formats

There are multiple formats for time series data.

  • The base ts format: The stats::ts() function will convert a numeric vector into an R time series object. The format is ts(vector, start=, end=, frequency=) where start and end are the times of the first and last observation and frequency is the number of observations per unit time (1=annual, 4=quarterly, 12=monthly, etc.). Used by established packages like forecast
  • Tibble format: the simplest is of course the standard tibble / dataframe, with a time variable to indicate that the other variables vary with time. Used by more recent packages such as timetk & modeltime
  • The modern tsibble (time series tibble) format: this is a new format for time series analysis, and is used by the tidyverts set of packages (fable, feasts and others).
  • There is also a tsbox package from ROpenScience that allows easy inter-conversion between these ( and other! ) formats!

Creating time series

In this first example, we will use simple ts data, and then do another with a tibble dataset, and then a third example with an tsibble formatted dataset.

ts format data

There are a few datasets in base R that are in ts format already.

AirPassengers
     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
1949 112 118 132 129 121 135 148 148 136 119 104 118
1950 115 126 141 135 125 149 170 170 158 133 114 140
1951 145 150 178 163 172 178 199 199 184 162 146 166
1952 171 180 193 181 183 218 230 242 209 191 172 194
1953 196 196 236 235 229 243 264 272 237 211 180 201
1954 204 188 235 227 234 264 302 293 259 229 203 229
1955 242 233 267 269 270 315 364 347 312 274 237 278
1956 284 277 317 313 318 374 413 405 355 306 271 306
1957 315 301 356 348 355 422 465 467 404 347 305 336
1958 340 318 362 348 363 435 491 505 404 359 310 337
1959 360 342 406 396 420 472 548 559 463 407 362 405
1960 417 391 419 461 472 535 622 606 508 461 390 432
str(AirPassengers)
 Time-Series [1:144] from 1949 to 1961: 112 118 132 129 121 135 148 148 136 119 ...

This can be easily plotted using base R:

plot(AirPassengers)

Let us take data that is “time oriented” but not in ts format, and convert it to ts: the syntax of ts() is:

Syntax: objectName <- ts(data, start, end, frequency) where  - data represents the data vector - start represents the first observation in time series
- end represents the last observation in time series
- frequency represents number of observations per unit time. For example, frequency=1 for monthly data.

We will pick simple numerical vector data ( i.e. not a timeseries ) ChickWeight:

ChickWeight %>% head()
ABCDEFGHIJ0123456789
 
 
weight
<dbl>
Time
<dbl>
Chick
<ord>
Diet
<fct>
142011
251211
359411
464611
576811
6931011
6 rows
ChickWeight_ts <- ts(ChickWeight$weight, frequency = 2)
plot(ChickWeight_ts)

CautionThe ts format

The ts format is not recommended for new analysis since it does not permit inclusion of multiple time series in one dataset, nor other categorical variables for grouping etc.

tibble format data

Some “time-oriented” datasets are available in tibble form. Let us try to plot one, the walmart_sales_weekly dataset from the timetk package:

data(walmart_sales_weekly, package = "timetk")
walmart_sales_weekly
ABCDEFGHIJ0123456789
id
<fct>
Store
<dbl>
Dept
<dbl>
Date
<date>
Weekly_Sales
<dbl>
IsHoliday
<lgl>
Type
<chr>
Size
<dbl>
Temperature
<dbl>
Fuel_Price
<dbl>
1_1112010-02-0524924.50FALSEA15131542.312.572
1_1112010-02-1246039.49TRUEA15131538.512.548
1_1112010-02-1941595.55FALSEA15131539.932.514
1_1112010-02-2619403.54FALSEA15131546.632.561
1_1112010-03-0521827.90FALSEA15131546.502.625
1_1112010-03-1221043.39FALSEA15131557.792.667
1_1112010-03-1922136.64FALSEA15131554.582.720
1_1112010-03-2626229.21FALSEA15131551.452.732
1_1112010-04-0257258.43FALSEA15131562.272.719
1_1112010-04-0942960.91FALSEA15131565.862.770
Next
123456
...
101
Previous
1-10 of 1,001 rows | 1-10 of 17 columns

This dataset is a tibble with a Date column. The Dept column is clearly a categorical column that allows us to distinguish separate time series, i.e. one for each value of Dept. We will convert that to a factor( it is an double precision number ) and then plot the data using this column on the Date on the x-axis:

walmart_sales_weekly %>%
  # convert Dept number to a **categorical factor**
  mutate(Dept = forcats::as_factor(Dept)) %>%
  gf_point(Weekly_Sales ~ Date,
    group = ~Dept,
    colour = ~Dept, data = .
  ) %>%
  gf_line() %>%
  gf_theme(theme_minimal())

For more analysis and forecasting etc., it is useful to convert this tibble into a tsibble:

walmart_tsibble <- as_tsibble(walmart_sales_weekly,
  index = Date,
  key = c(id, Dept)
)
walmart_tsibble
ABCDEFGHIJ0123456789
id
<fct>
Store
<dbl>
Dept
<dbl>
Date
<date>
Weekly_Sales
<dbl>
IsHoliday
<lgl>
Type
<chr>
Size
<dbl>
Temperature
<dbl>
Fuel_Price
<dbl>
1_1112010-02-0524924.50FALSEA15131542.312.572
1_1112010-02-1246039.49TRUEA15131538.512.548
1_1112010-02-1941595.55FALSEA15131539.932.514
1_1112010-02-2619403.54FALSEA15131546.632.561
1_1112010-03-0521827.90FALSEA15131546.502.625
1_1112010-03-1221043.39FALSEA15131557.792.667
1_1112010-03-1922136.64FALSEA15131554.582.720
1_1112010-03-2626229.21FALSEA15131551.452.732
1_1112010-04-0257258.43FALSEA15131562.272.719
1_1112010-04-0942960.91FALSEA15131565.862.770
Next
123456
...
101
Previous
1-10 of 1,001 rows | 1-10 of 17 columns

The 7D states the data is weekly. There is a Date column and all the other numerical variables are time-varying quantities. The categorical variables such as id, and Dept allow us to identify separate time series in the data, and these have 7 combinations hence are 7 time series in this data, as indicated.

Let us plot Weekly_Sales, colouring the time series by Dept:

walmart_tsibble %>%
  gf_line(Weekly_Sales ~ Date,
    colour = ~ as_factor(Dept), data = .
  ) %>%
  gf_point() %>%
  gf_theme(theme_minimal()) %>%
  labs(title = "Weekly Sales by Dept at Walmart")
[[1]]

$title
[1] "Weekly Sales by Dept at Walmart"

attr(,"class")
[1] "labels"
Figure 1: Walmart Time Series

We can also do a quick autoplot that seems to offer less control and is also not interactive.

walmart_tsibble %>%
  dplyr::group_by(Dept) %>%
  autoplot(Weekly_Sales) %>%
  gf_theme(theme_minimal())

tsibble format data

In the packages tsibbledata and fpp3 we have a good choice of tsibble format data. Let us pick one:

hh_budget
ABCDEFGHIJ0123456789
Country
<chr>
Year
<dbl>
Debt
<dbl>
DI
<dbl>
Expenditure
<dbl>
Savings
<dbl>
Wealth
<dbl>
Unemployment
<dbl>
Australia199595.689993.719545333.404311255.2389216314.93448.472281
Australia199699.530783.984478372.971741266.4716693314.55598.506114
Australia1997107.540202.516344834.949124553.7399359323.23578.362488
Australia1998114.633204.023754335.731540831.2875994339.31397.677429
Australia1999121.099803.840197504.257828770.6377422354.43826.873791
Australia2000126.425403.769813753.180303491.9904011350.27956.285546
Australia2001132.010504.364266313.097705203.2373997347.80536.742173
Australia2002149.094400.021820404.03171701-1.1518200348.73796.368911
Australia2003159.249506.056591815.03899495-0.4134631359.90075.928420
Australia2004169.584805.526820174.544933680.6568372378.56535.396734
Next
123456
...
9
Previous
1-10 of 88 rows

There are 4 keys ( id variables ) here, one for each country. Six other quantitative columns are the individual series. Let us plot (some of) the timeseries:

ggplot2::theme_set(theme_classic())
hh_budget %>%
  gf_path(Debt ~ Year,
    colour = ~Country,
    title = "Debt over Time"
  )
##
hh_budget %>%
  gf_path(Savings ~ Year,
    colour = ~Country,
    title = "Savings over Time"
  )
##
hh_budget %>%
  gf_path(Expenditure ~ Year,
    colour = ~Country,
    title = "Expenditure over Time"
  )
##
hh_budget %>%
  gf_path(Wealth ~ Year,
    colour = ~Country,
    title = "Wealth over Time"
  )

One more example

Often we have data in table form, that is time-oriented, with a date like column, and we need to convert it into a tsibble for analysis:

prison <- readr::read_csv("https://OTexts.com/fpp3/extrafiles/prison_population.csv")
glimpse(prison)
Rows: 3,072
Columns: 6
$ Date       <date> 2005-03-01, 2005-03-01, 2005-03-01, 2005-03-01, 2005-03-01…
$ State      <chr> "ACT", "ACT", "ACT", "ACT", "ACT", "ACT", "ACT", "ACT", "NS…
$ Gender     <chr> "Female", "Female", "Female", "Female", "Male", "Male", "Ma…
$ Legal      <chr> "Remanded", "Remanded", "Sentenced", "Sentenced", "Remanded…
$ Indigenous <chr> "ATSI", "Non-ATSI", "ATSI", "Non-ATSI", "ATSI", "Non-ATSI",…
$ Count      <dbl> 0, 2, 0, 5, 7, 58, 5, 101, 51, 131, 145, 323, 355, 1617, 12…

We have a Date column for the time index, and we have unique key variables like State, Gender, Legal and Indigenous. Count is the value that is variable over time. It also appears that the data is quarterly, since mosaic::inspect reports the max_diff in the Date column as 92. .

Run mosaic::inspect(prison) in your Console
prison_tsibble <- prison %>%
  mutate(quarter = yearquarter(Date)) %>%
  select(-Date) %>% # Remove the Date column now that we have quarters
  as_tsibble(index = quarter, key = c(State, Gender, Legal, Indigenous))

prison_tsibble
ABCDEFGHIJ0123456789
State
<chr>
Gender
<chr>
Legal
<chr>
Indigenous
<chr>
Count
<dbl>
quarter
<qtr>
ACTFemaleRemandedATSI02005 Q1
ACTFemaleRemandedATSI12005 Q2
ACTFemaleRemandedATSI02005 Q3
ACTFemaleRemandedATSI02005 Q4
ACTFemaleRemandedATSI12006 Q1
ACTFemaleRemandedATSI12006 Q2
ACTFemaleRemandedATSI12006 Q3
ACTFemaleRemandedATSI02006 Q4
ACTFemaleRemandedATSI02007 Q1
ACTFemaleRemandedATSI12007 Q2
Next
123456
...
308
Previous
1-10 of 3,072 rows

(Here, ATSI stands for Aboriginal or Torres Strait Islander.). We have 64 time series here, organized quarterly.

Let us examine the key variables:

prison_tsibble %>% distinct(Indigenous)
ABCDEFGHIJ0123456789
Indigenous
<chr>
ATSI
Non-ATSI
2 rows
prison_tsibble %>% distinct(State)
ABCDEFGHIJ0123456789
State
<chr>
ACT
NSW
NT
QLD
SA
TAS
VIC
WA
8 rows

So we can plot the time series, faceted / coloured by State:

prison_tsibble %>%
  tsibble::index_by() %>%
  group_by(Indigenous, State) %>%
  # filter(State == "NSW") %>%
  summarise(Total = sum(Count)) %>%
  gf_point(Total ~ quarter,
    colour = ~Indigenous,
    shape = ~Indigenous
  ) %>%
  gf_line() %>%
  # Note that the y-axes are all. different!!
  gf_facet_wrap(vars(State), scale = "free_y") %>%
  gf_theme(theme_minimal())

Hmm…looks like New South Wales(NSW) as something different going on compared to the rest of the states in Aus. Because of the large cities there…

Decomposing Time Series

We can decompose the Weekly_Sales into components representing trends, seasonal events that repeat, and irregular noise. Since each Dept could have a different set of trends, we will do this first for one Dept, say Dept #95:

walmart_decomposed_season <- walmart_tsibble %>%
  dplyr::filter(Dept == "95") %>% # filter for Dept 95
  #
  # feasts depends upon fabletools.
  #
  fabletools::model(
    season = STL(Weekly_Sales ~ season(window = "periodic"))
  )
walmart_decomposed_season %>% fabletools::components()
ABCDEFGHIJ0123456789
id
<fct>
Dept
<dbl>
.model
<chr>
Date
<date>
Weekly_Sales
<dbl>
trend
<dbl>
season_year
<dbl>
remainder
<dbl>
season_adjust
<dbl>
1_9595season2010-02-05106690.06113713.4-6508.1600-515.21431113198.22
1_9595season2010-02-12111390.36113802.0-729.1725-1682.49225112119.53
1_9595season2010-02-19107952.07113890.6-729.1726-5209.37273108681.24
1_9595season2010-02-26103652.58113979.2-729.1726-9597.45320104381.75
1_9595season2010-03-05112807.75114067.8-5470.68854210.64214118278.44
1_9595season2010-03-12112048.41114156.4-5470.68853362.71165117519.10
1_9595season2010-03-19117716.13114245.0-5470.68858941.84115123186.82
1_9595season2010-03-26113117.35114333.6-11414.647810198.42988124532.00
1_9595season2010-04-02111466.37114422.2-11414.64788458.85933122881.02
1_9595season2010-04-09116770.82114509.5-11414.647713675.94797128185.47
Next
123456
...
15
Previous
1-10 of 143 rows
###
walmart_decomposed_ets <- walmart_tsibble %>%
  dplyr::filter(Dept == "95") %>% # filter for Dept 95
  #
  # feasts depends upon fabletools.
  #
  fabletools::model(
    ets = ETS(box_cox(Weekly_Sales, 0.3))
  )
###
walmart_decomposed_ets %>% fabletools::components()
ABCDEFGHIJ0123456789
id
<fct>
Dept
<dbl>
.model
<chr>
Date
<date>
box_cox(Weekly_Sales, 0.3)
<dbl>
level
<dbl>
remainder
<dbl>
1_9595ets2010-01-29NA104.9244NA
1_9595ets2010-02-05104.14377104.6896-0.780651335
1_9595ets2010-02-12105.54288104.94630.853307155
1_9595ets2010-02-19104.52359104.8191-0.422680545
1_9595ets2010-02-26103.21650104.3370-1.602619221
1_9595ets2010-03-05105.95667104.82421.619652467
1_9595ets2010-03-12105.73545105.09840.911201935
1_9595ets2010-03-19107.36206105.77932.263701564
1_9595ets2010-03-26106.04656105.85970.267232522
1_9595ets2010-04-02105.56517105.7711-0.294553642
Next
123456
...
15
Previous
1-10 of 144 rows
###
walmart_decomposed_arima <- walmart_tsibble %>%
  dplyr::filter(Dept == "95") %>% # filter for Dept 95
  fabletools::model(arima = ARIMA(log(Weekly_Sales)))
walmart_decomposed_arima %>% broom::tidy()
ABCDEFGHIJ0123456789
id
<fct>
Dept
<dbl>
.model
<chr>
term
<chr>
estimate
<dbl>
std.error
<dbl>
statistic
<dbl>
p.value
<dbl>
1_9595arimaar1-0.14832060.12573909-1.1795902.401357e-01
1_9595arimaar2-0.82865850.03745076-22.1266137.264053e-48
1_9595arimaar3-0.38560240.10496648-3.6735763.380457e-04
1_9595arimama1-0.46419330.11752561-3.9497211.227609e-04
1_9595arimama20.67589160.083344198.1096432.153610e-13
5 rows
walmart_decomposed_season %>%
  components() %>%
  autoplot() +
  labs(title = "Seasonal Variations in Weekly Sales, Dept #95")

walmart_decomposed_ets %>%
  components() %>%
  autoplot() +
  labs(title = "ETS Variations in Weekly Sales, Dept #95")

Conclusion

TBW

References

  1. Forecasting: Principles and Practice (3rd ed) Rob J Hyndman and George Athanasopoulos
Back to top
Lab-11: The Queen of Hearts, She Made some Tarts
Iteration: Learning to purrr

License: CC BY-SA 2.0

Website made with ❤️ and Quarto, by Arvind V.

Hosted by Netlify .