We already installed R, RStudio, and the packages we need for this
course (tidyverse, a package for financial analysis,
plotly for interactive visualization, and the packages
needed for PDF output). tidyverse only needs to be
installed once — after that, we just need to load it with
library() at the top of the file so it’s available
throughout.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.1 ✔ readr 2.2.0
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.3 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Code can be run directly in the console, but anything run there disappears once the R session ends. Writing code in a file (an R script, or here in an R Markdown file) keeps a permanent, shareable record. R Markdown lets us mix text and analysis in the same document.
1 + 2
## [1] 3
If you hit an error, copy the error message and search it on Google
(Stack Overflow is usually the best source). You can also look up a
function’s documentation by placing your cursor on the function name and
pressing F1, or by using package::function (e.g.
ggplot2::geom_point) to see suggestions from a specific
package.
Chapter 2 is a short overview chapter that introduces the data science project workflow (import -> tidy -> transform/visualize/model [iterative] -> communicate). No code chunk needed here — just read the chapter.
library(tidyverse)
mpg Data FrameThe mpg dataset comes bundled with ggplot2
(part of the tidyverse). Each row is a car model; each
column is a variable describing that model (engine size, highway
mileage, class, etc.).
mpg
## # A tibble: 234 × 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto… f 18 29 p comp…
## 2 audi a4 1.8 1999 4 manu… f 21 29 p comp…
## 3 audi a4 2 2008 4 manu… f 20 31 p comp…
## 4 audi a4 2 2008 4 auto… f 21 30 p comp…
## 5 audi a4 2.8 1999 6 auto… f 16 26 p comp…
## 6 audi a4 2.8 1999 6 manu… f 18 26 p comp…
## 7 audi a4 3.1 2008 6 auto… f 18 27 p comp…
## 8 audi a4 quattro 1.8 1999 4 manu… 4 18 26 p comp…
## 9 audi a4 quattro 1.8 1999 4 auto… 4 16 25 p comp…
## 10 audi a4 quattro 2 2008 4 manu… 4 20 28 p comp…
## # ℹ 224 more rows
We build a plot by starting with ggplot(data = ...),
adding a geom layer with +, and mapping variables to
aesthetics (axes, color, etc.) inside aes().
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy))
There’s a clear negative relationship: cars with bigger engines
(displ) tend to get worse highway mileage
(hwy). A few points don’t fit the trend — worth
investigating further.
We can map a third variable to an additional aesthetic, like color, to see if it explains those outliers.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = class))
Coloring by class shows the outliers are 2-seater sports
cars — big engines, but better mileage than other cars with similarly
sized engines.
Common problem: if nothing happens when you run the
code, check that the + is at the end of the line,
not the start of the next one.
Instead of mapping a categorical variable to color, we can split the
plot into small multiples — one panel per category — with
facet_wrap().
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_wrap(~class, nrow = 2)
You can also facet on the combination of two variables with
facet_grid():
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(drv ~ cyl)
A geom is the visual object used to represent the data. The same data/mappings can be drawn as points or as a smooth trend line, or both at once.
# Points only
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy))
# Smooth line only
ggplot(data = mpg) +
geom_smooth(mapping = aes(x = displ, y = hwy))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
# Both geoms in the same plot
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
geom_smooth(mapping = aes(x = displ, y = hwy))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Note: not every aesthetic works with every geom —
e.g. linetype works for geom_smooth() but not
geom_point(), since points don’t have lines.
Bar charts are useful for categorical variables with a limited number
of values. Here we switch to the diamonds dataset (also
from ggplot2) and look at diamond cut and
clarity.
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut))
Adding fill = clarity stacks a second categorical
variable within each bar:
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity))
The position argument controls how those stacked
segments are arranged. Try each of the following:
# "identity": default-like stacking
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity), position = "identity")
# "fill": rescales each bar to 100%, useful for comparing proportions across categories
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity), position = "fill")
# "dodge": places overlapping bars side-by-side
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity), position = "dodge")
Scatterplot adjustment: the mpg
scatterplot only shows ~126 distinct points even though there are 234
rows, because many points overlap. position = "jitter" adds
a small amount of random noise so overlapping points become visible.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy), position = "jitter")
# coord_flip(): swaps the x and y axes
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
geom_boxplot() +
coord_flip()
# coord_quickmap(): sets the correct aspect ratio for maps
# (shown here conceptually — requires map data, e.g. from the maps package)
# coord_polar(): uses polar coordinates
bar <- ggplot(data = diamonds) +
geom_bar(
mapping = aes(x = cut, fill = cut),
show.legend = FALSE,
width = 1
) +
theme(aspect.ratio = 1) +
labs(x = NULL, y = NULL)
bar + coord_polar()
Every ggplot2 plot follows the same template:
ggplot(data = <DATA>) +
<GEOM_FUNCTION>(
mapping = aes(<MAPPINGS>),
stat = <STAT>,
position = <POSITION>
) +
<COORDINATE_FUNCTION> +
<FACET_FUNCTION>
We start with a dataset, add a geom
(with its mappings), optionally adjust the
statistical transformation and
position, then layer on a coordinate
system and facets as needed — all combined
with +.