Wizualizacja danych z biblioteką ggplot2
- Wykresy zmiennej ilościowej
- Wykresy zmiennej jakościowej
- Wykresy dwóch zmiennych ilościowych
- Wykresy dwóch zmiennych jakościowych
- Wykresy zmiennej ilościowej vs zmiennej jakościowej
- Wykresy bąbelkowe (3x Challenge)
- Kilka wykresów na jednym panelu (2x Challenge).
Przydatne materiały:
- ggplot2
cheatsheet
- A.
Kassambara - Guide to Create Beautiful Graphics in R. - Hadley Wickham “ggplot2”
Dane pochodzą ze strony https://flixgem.com/ (wersja zbioru danych z dnia 12 marca 2021). Dane zawierają informacje na temat 9425 filmów i seriali dostępnych na Netlix.
Wizualizacja danych z ggplot2
theme_set(theme_bw())
Podstawowe zasady tworzenia wykresów z ggplot2:
- do funkcji ggplot() podajemy ramkę danych oraz opcjonalnie
osie x, y i parametry shape, color,
fill, group
- dodajemy wykresy za pomocą funkcji zaczynających się geom_
lub stat_
- modyfikujemy wykresy dodając legendy, tytuły, znaczniki na osiach
etc.
Do szybkich analiz można skorzystać z funkcji qplot(), która automatycznie dobiera typ wykresu do rodzaju danych.
Wykresy zmiennej ilościowej
dane %>%
filter(Languages=="Polish") %>%
ggplot(aes(x = IMDb.Score)) +
geom_histogram(
aes(fill = Series.or.Movie)
,bins = 10
,color = 'black'
) +
labs(title = 'Polskie filmy i seriale')
ggplot(dane, aes(x=IMDb.Score, fill=Series.or.Movie)) +
geom_density(alpha=.25) +
labs(title = 'Gęstość rozkładu ocen')
Wykresy zmiennej jakościowej
dane %>%
filter(Runtime != '') %>%
ggplot(aes(Runtime)) +
geom_bar(aes(fill = Runtime))+
scale_x_discrete(
limits = c('< 30 minutes'
,'30-60 mins'
,'1-2 hour'
,'> 2 hrs')
,labels = function(x) str_wrap(x, width = 8)
) +
theme(
legend.position = 'none'
,axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)
) +
scale_fill_manual(values = brewer.pal(4, 'Accent'))
Wykresy dwóch zmiennych ilościowych
ggplot(dane, aes(x = IMDb.Score, y = IMDb.Votes)) +
geom_point(aes(color = Series.or.Movie)) +
geom_smooth(
method = 'loess'
,se = FALSE
) +
theme(legend.position = c(0.2, 0.8))
Wykresy dwóch zmiennych jakościowych
dane %>%
filter(Runtime != '') %>%
ggplot(aes(x = Series.or.Movie, y = Runtime)) +
geom_jitter(aes(color = Runtime)) +
theme(legend.position = 'none') +
scale_y_discrete(
limits = c('< 30 minutes'
,'30-60 mins'
,'1-2 hour'
,'> 2 hrs')
) +
labs(x = '', y = '')
Wykresy zmiennej ilościowej vs zmiennej jakościowej
medians = dane %>%
group_by(Series.or.Movie) %>%
summarize(m = median(IMDb.Score, na.rm = TRUE))
ggplot(dane, aes(x = Series.or.Movie, y = IMDb.Score)) +
geom_boxplot(
aes(fill = Series.or.Movie)
,outlier.alpha = 0.25
) +
geom_text(
data = medians
,aes(x = Series.or.Movie, y = m, label = m)
,color = 'blue'
,hjust = 7
) +
stat_boxplot(geom ='errorbar', position = 'dodge') +
stat_summary(
aes(ymax = ..y.., ymin = ..y..)
,fun = mean
,geom = 'errorbar'
,width = .75
,linetype = 'solid'
,position = 'dodge'
,color = 'white'
,size = 1
) +
theme(legend.position = 'none')
Wykresy bąbelkowe
gatunki <- dane %>%
select(Genre) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
gatunki <- data.frame(
Gatunek = gatunki$.
,`Count` = gatunki$Freq
,`IMDb Score Average` = NA
,`IMDb Votes Average` = NA
)
for (i in 1:nrow(gatunki)) {
gatunki$IMDb.Score.Average[i] <- dane %>%
filter(str_detect(Genre, gatunki$Gatunek[i] %>%
as.character() %>% eval())) %>%
select(IMDb.Score) %>% unlist() %>% mean(na.rm = TRUE)
gatunki$IMDb.Votes.Average[i] <- dane %>%
filter(str_detect(Genre, gatunki$Gatunek[i] %>%
as.character() %>% eval())) %>%
select(IMDb.Votes) %>% unlist() %>% mean(na.rm = TRUE)
}
ggplot(gatunki, aes(IMDb.Score.Average, IMDb.Votes.Average, label = Gatunek)) +
geom_point(aes(color = Gatunek, size = Count)) +
geom_text_repel() +
theme(legend.position = 'none')
Kilka wykresów na jednym panelu
dane %>%
filter(Runtime != '') %>%
ggplot(aes(x = IMDb.Score)) +
geom_histogram(
aes(fill = Series.or.Movie)
,bins = 50
,color = 'black'
) +
# facet_grid(.~ Series.or.Movie) +
# facet_grid(Series.or.Movie ~ .) +
# facet_grid(Runtime ~ Series.or.Movie, scales = 'free') +
# facet_wrap(vars(Series.or.Movie), ncol = 2) +
facet_wrap(vars(Series.or.Movie), nrow = 2) +
# facet_wrap(vars(Series.or.Movie, Runtime), nrow = 2, scales = 'free') +
theme(legend.position = 'none')
Zadanie domowe
Korzystając z paczki danych “germancredit” dotyczącą oceny kredytowej (creditability) wybranych klientów pewnego banku wykreśl zmienną ilościową (np. wysokość kredytu); zmienną jakościową (ryzyko); ilościową wg jakościowej (np. wiek wg ryzyka); 2 ilościowe (wiek wg wysokości kredytu) oraz wykres bąbelkowy wg własnego pomysłu + przedstaw kilka wykresów na 1 panelu.
data("germancredit")
attach(germancredit)
# http://archive.ics.uci.edu/ml/datasets/Statlog+(German+Credit+Data)
Wykres 1 zmiennej ilościowej -
ggplot(germancredit, aes(x=duration.in.month, fill=creditability)) +
geom_density(alpha=.5) +
labs(title = 'Gęstość rozkładu długości kredytu')
Wykres jednej zmiennej jakościowej - własność mieszkania:
germancredit %>%
filter(housing != '') %>%
ggplot(aes(housing)) +
geom_bar(aes(fill = housing))+
scale_x_discrete(
limits = c('rent','own','for free')
,labels = function(x) str_wrap(x, width = 8)
) +
theme(
legend.position = 'none'
,axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)
) +
scale_fill_manual(values = brewer.pal(4, 'Accent'))
Wykres zmiennej ilościowej wg jakościowej - wiek wg ryzyka:
medians = germancredit %>%
group_by(creditability) %>%
summarize(m = median(age.in.years, na.rm = TRUE))
ggplot(germancredit, aes(x = creditability, y = age.in.years)) +
geom_boxplot(
aes(fill = creditability)
,outlier.alpha = 0.25
) +
geom_text(
data = medians
,aes(x = creditability, y = m, label = m)
,color = 'blue'
,hjust = 7
) +
stat_boxplot(geom ='errorbar', position = 'dodge') +
stat_summary(
aes(ymax = ..y.., ymin = ..y..)
,fun = mean
,geom = 'errorbar'
,width = .75
,linetype = 'solid'
,position = 'dodge'
,color = 'white'
,size = 1
) +
theme(legend.position = 'none')
Wykres dwóch zmiennych ilościowych -
ggplot(germancredit, aes(x = credit.amount, y = duration.in.month)) +
geom_point(aes(color = creditability)) +
geom_smooth(
method = 'lm'
,se = FALSE
) +
theme(legend.position = c(0.2, 0.8))
## `geom_smooth()` using formula = 'y ~ x'
Wykres bąbelkowy -
options(scipen=999)
cele <- germancredit %>%
select(purpose) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
cele <- data.frame(
Cel = cele$.
,`Count` = cele$Freq
,`duration.in.month.average` = NA
,`credit.amount.average` = NA
)
for (i in 1:nrow(cele)) {
cele$duration.in.month.average[i] <- germancredit %>%
filter(str_detect(purpose, cele$Cel[i] %>%
as.character() %>% eval())) %>%
select(duration.in.month) %>% unlist() %>% mean(na.rm = TRUE)
cele$credit.amount.average[i] <- germancredit %>%
filter(str_detect(purpose, cele$Cel[i] %>%
as.character() %>% eval())) %>%
select(credit.amount) %>% unlist() %>% mean(na.rm = TRUE)
}
ggplot(cele, aes(duration.in.month.average, credit.amount.average, label = Cel)) +
geom_point(aes(color = Cel, size = Count)) +
geom_text_repel() +
theme(legend.position = 'none')
## Warning: Removed 2 rows containing missing values (`geom_point()`).
## Warning: Removed 2 rows containing missing values (`geom_text_repel()`).
Kilka wykresów na jednym panelu
germancredit %>%
filter(age.in.years != '') %>%
ggplot(aes(x = duration.in.month)) +
geom_histogram(
aes(fill = creditability)
,bins = 50
,color = 'black'
) +
facet_grid(creditability ~ .) +
theme(legend.position = 'none')
Zadania dodatkowe - dla chętnych:
CHALLENGE 1: Stwórz wykres pokazujący aktorów grających w najpopularniejszych produkcjach.
actorrs <- dane %>%
select(Actors) %>%
top_n(100) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
actorrs <- data.frame(
Aktor = actorrs$.
,`Count` = actorrs$Freq
,`IMDB Score Average` = NA
,`IMDB Votes Average` = NA
)
for (i in 1:nrow(actorrs)) {
actorrs$IMDB.Score.Average[i] <- dane %>%
filter(str_detect(Actors, actorrs$Aktor[i] %>%
as.character() %>% eval())) %>%
select(IMDb.Score) %>% unlist() %>% mean(na.rm = TRUE)
actorrs$IMDB.Votes.Average[i] <- dane %>%
filter(str_detect(Actors, actorrs$Aktor[i] %>%
as.character() %>% eval())) %>%
select(IMDb.Votes) %>% unlist() %>% mean(na.rm = TRUE)
}
ggplot(actorrs, aes(IMDB.Score.Average, IMDB.Votes.Average, label = Aktor)) +
geom_point(aes(color = Aktor, size = Count)) +
geom_text_repel() +
theme(legend.position = 'none')
CHALLENGE 2: Stwórz wykres pokazujący w jakich latach powstawały najpopularniejsze produkcje.
lata <- dane %>%
select(Release.Date) %>%
top_n(100) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
lata <- data.frame(
Rok = lata$.
,`Count` = lata$Freq
,`IMDB Score Average` = NA
,`IMDB Votes Average` = NA
)
for (i in 1:nrow(lata)) {
lata$IMDB.Score.Average[i] <- dane %>%
filter(str_detect(Release.Date, lata$Rok[i] %>%
as.character() %>% eval())) %>%
select(IMDb.Score) %>% unlist() %>% mean(na.rm = TRUE)
lata$IMDB.Votes.Average[i] <- dane %>%
filter(str_detect(Release.Date, lata$Rok[i] %>%
as.character() %>% eval())) %>%
select(IMDb.Votes) %>% unlist() %>% mean(na.rm = TRUE)
}
ggplot(lata, aes(IMDB.Score.Average, IMDB.Votes.Average, label = Rok)) +
geom_point(aes(color = Rok, size = Count)) +
geom_text_repel() +
theme(legend.position = 'none')
CHALLENGE 3: Jakie są najpopularniejsze języki dostępne na Netflixie? Podpowiedź: wykres kolumnowy.
dane%>% pull(Languages) %>% paste0(collapse = ', ') %>%
str_extract_all('[A-Za-z]+') %>% unlist() %>% table() %>%
as.data.frame()%>% rename(Jezyk = ".", Ilosc = Freq)%>% arrange(-Ilosc)%>%
head(10)%>% ggplot(aes(x=Jezyk,y=Ilosc))+
geom_col(aes(fill=Jezyk))+
labs(title = "Top 10 najpopularniejszych języków")+
geom_text(aes(label = Ilosc), vjust = 1.5)
CHALLENGE 4: Dla filmów i seriali stwórz wykresy ocen z poszczególnych portali (Hidden Gem, IMDb, Rotten Tomatoes, Metacritic). Podpowiedź: warto odpiwotować dane do formatu long.
p1 = ggplot(dane, aes(x = IMDb.Score, y = IMDb.Votes, color = Series.or.Movie)) +
geom_point() +
theme(legend.position = c(0.3, 0.8))
p2 = ggplot(gatunki, aes(IMDb.Score.Average, IMDb.Votes.Average, label = Gatunek)) +
geom_point(aes(color = Gatunek, size = Count)) +
geom_text_repel() +
theme(legend.position = 'none')
grid.arrange(p1, p2, ncol = 2)
CHALLENGE 5: Jakie wytwórnie filmowe produkują najwięcej i jak się to zmieniało na przestrzeni ostatnich lat?
LATA <- dane %>%
mutate(Release = Release.Date %>% as.Date(format = '%m/%d/%Y')) %>%
mutate(release_year = format(Release, format = "%Y"))
Wyt.2k20<- LATA %>%
filter(release_year == 2020) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k20) <- c('Wytwórnia', 'Liczba')
Wyt.2k20<- Wyt.2k20%>%
arrange(desc(Liczba))
POP_2020 <- Wyt.2k20[1:5,]
Wyt.2k19 <- LATA %>%
filter(release_year == 2019) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k19) <- c('Wytwórnia', 'Liczba')
Wyt.2k19 <- Wyt.2k19 %>%
arrange(desc(Liczba))
POP_2019 <- Wyt.2k19[1:5,]
Wyt.2k18 <- LATA %>%
filter(release_year == 2018) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k18) <- c('Wytwórnia', 'Liczba')
Wyt.2k18 <- Wyt.2k18 %>%
arrange(desc(Liczba))
POP_2018 <- Wyt.2k18[1:5,]
Wyt.2k17 <- LATA %>%
filter(release_year == 2017) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k17) <- c('Wytwórnia', 'Liczba')
Wyt.2k17 <- Wyt.2k17 %>%
arrange(desc(Liczba))
POP_2017 <- Wyt.2k17[1:5,]
Wyt.2k16 <- LATA %>%
filter(release_year == 2016) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k16) <- c('Wytwórnia', 'Liczba')
Wyt.2k16 <- Wyt.2k16 %>%
arrange(desc(Liczba))
POP_2016 <- Wyt.2k16[1:5,]
Wyt.2k15 <- LATA %>%
filter(release_year == 2015) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k15) <- c('Wytwórnia', 'Liczba')
Wyt.2k15 <- Wyt.2k15 %>%
arrange(desc(Liczba))
POP_2015 <- Wyt.2k15[1:5,]
Wyt.2k14 <- LATA %>%
filter(release_year == 2014) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k14) <- c('Wytwórnia', 'Liczba')
Wyt.2k14 <- Wyt.2k14 %>%
arrange(desc(Liczba))
POP_2014 <- Wyt.2k14[1:5,]
Wyt.2k13 <- LATA %>%
filter(release_year == 2013) %>%
select(Production.House) %>%
unlist() %>%
strsplit(',') %>%
unlist() %>%
trimws() %>%
table() %>%
as.data.frame()
colnames(Wyt.2k13) <- c('Wytwórnia', 'Liczba')
Wyt.2k13 <- Wyt.2k13 %>%
arrange(desc(Liczba))
POP_2013 <- Wyt.2k13[1:5,]
w1 <- ggplot(POP_2020, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2020') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w2 <- ggplot(POP_2019, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2019') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w3 <- ggplot(POP_2018, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2018') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w4 <- ggplot(POP_2017, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2017') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w5 <- ggplot(POP_2016, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2016') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w6 <- ggplot(POP_2015, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2015') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w7 <- ggplot(POP_2014, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2014') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
w8 <- ggplot(POP_2013, aes(x = reorder(Wytwórnia, -Liczba), y = Liczba)) +
geom_col() +
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
scale_fill_manual(values = brewer.pal(4, 'Dark2')) +
labs(title = 'Top 2013') +
xlab('Wytwórnia') +
ylab('Liczba filmów')
grid.arrange(w1, w2, w3, w4, w5, w6, w7, w8, ncol = 4, nrow = 2)