class: middle, left, inverse, title-slide .title[ # Визуализация данных ] .author[ ### Вадим Хайтов, Марина Варфоломеева, Анастасия Лянгузова ] .date[ ### Осень 2024 ] --- ## Вы сможете - Представить данные в длинном формате с правильным обозначением перменных и пропущенных значений - Построить простейшие статистические графики с использованием функций из пакета ggplot2 - Настраивать параметры графиков --- class: middle, center, inverse # Данные --- ## Исходные данные часто приходится приводить в порядок На подготовку данных к анализу уходит до 80% времени. Существуют определенные правила предоставления данных. Данные, построенные в соответствии с этими требованиями, называются **tidy data**, или **опрятные данные**. --- ## Проблемы начинаются уже в электронных таблицах ![:scale 65%](images/Excel_sheet.jpg) --- ## Основные ошибки - Объединенные ячейки - Отсутствующие заголовки столбцов, вместо них стоят какие-то числа (или ничего не стоит) или слишком длинные имена заголовков - В одной ячейке находится сразу несколько значений - Разнородные данные в пределах одного столбца - Нет стандартного обозначения пропущенных значений - Разные группы значений кодируются цветовыми выделениями --- ## Принятые нормы - Столбцы - переменные (variables) - Строки - объекты (observations) - В каждой переменной только один тип данных - На месте пропущенных значений стоит специальный знак (в R принят `NA`) **При работе в Excel не должно быть никаких объединенных ячеек!** --- ## Управление данными В среде `R` создано несколько удобных пакетов для преобразования данных: - `reshape2` - `dplyr` - `tidyr` Мы постепенно научимся ими пользоваться --- ## Два формата представления данных - Широкий формат: данные максимально структурированы, каждая строка может нести информацию о многих элементарных объектах - Длинный формат: данные минимально структурированы, каждая строка характеризует уникальный объект Из длинного формата легко получить широкий. Из широкого формата получить длинный заметно сложнее. Широкий формат хорош для отчетов, представления обобщенных результатов Длинный формат хорош для анализа --- ## Учимся читать внешние данные ```r titanic <- read.table('data/Titanic.csv', sep = ';', header = TRUE) ``` --- ## В каком формате представлены данные? ```r head(titanic, 8) ``` ``` Class Sex Age Survived Freq 1 1st Male Child No 0 2 2nd Male Child No 0 3 3rd Male Child No 35 4 Crew Male Child No 0 5 1st Female Child No 0 6 2nd Female Child No 0 7 3rd Female Child No 17 8 Crew Female Child No 0 ``` --- ## Длинный формат данных ```r library(tidyr) long_titanic <- uncount(titanic, weights = Freq) head(long_titanic, 10) ``` ``` Class Sex Age Survived 1 3rd Male Child No 2 3rd Male Child No 3 3rd Male Child No 4 3rd Male Child No 5 3rd Male Child No 6 3rd Male Child No 7 3rd Male Child No 8 3rd Male Child No 9 3rd Male Child No 10 3rd Male Child No ``` --- ## Данные для визуализации Данные взяты из работы Tager, I. B., Weiss, S. T., Rosner, B., and Speizer, F. E. (1979). Effect of parental cigarette smoking on pulmonary function in children. American Journal of Epidemiology, 110, 15-26. Источник данных: [http://www.statsci.org/data/general/fev.html] Структура данных: `Age` --- Возраст `FEV` --- Объем легких при выдохе (литры) (forced expiratory volume) `Height` --- Рост (дюймы) `Sex` --- пол (Male or Female) `Smoker` --- некурящие (Non), курящие (Current) --- ## Читаем данные ```r library(readxl) fev <- read_excel("data/fev.xls", sheet = "tidy_data", col_names = TRUE, na = "NA", skip = 1 ) ``` --- ## Анализируем структуру данных Имена переменных ```r names(fev) ``` ``` [1] "Age" "FEV" "Height" "Sex" "Smoker" ``` --- ## Анализируем структуру данных Содержание переменных ```r str(fev) ``` ``` tibble [654 × 5] (S3: tbl_df/tbl/data.frame) $ Age : num [1:654] 9 8 7 9 9 8 6 6 8 9 ... $ FEV : num [1:654] 1.71 1.72 1.72 1.56 1.9 ... $ Height: num [1:654] 57 67.5 54.5 53 57 61 58 56 58.5 60 ... $ Sex : chr [1:654] "Female" "Female" "Female" "Male" ... $ Smoker: chr [1:654] "Non" "Non" "Non" "Non" ... ``` --- ## Изменяем формат переменных Необходимо заменить формат в переменных `fev$Sex` и `fev$Smoker` ```r fev$Sex <- factor(fev$Sex) fev$Smoker <- factor(fev$Smoker) ``` функция `factor()` превращает числовые или текстовые данные в дискретные факторы --- ## Пропущенные значения `NA` Если необходимо убрать объекты, у которых что-то не измерено (NA), то надо произвести "очистку данных". НО! не увлекайтесь, иногда можно "вычистить"" важную информацию В каких строках содержится пропущенная информация? ```r fev[which(!complete.cases(fev)), ] ``` ``` # A tibble: 2 × 5 Age FEV Height Sex Smoker <dbl> <dbl> <dbl> <fct> <fct> 1 16 4.50 72 Male <NA> 2 NA 3.21 66.5 Female Non ``` здесь используется сразу две функции: `which()`, в нее вложена `complete.cases()` ! - логическая операция "NOT" [ , ] - оператор индексации на первом месте строка, на втором - столбец --- ## Убираем из датафрейма неполные строки ```r fev <- fev[complete.cases(fev), ] ``` --- class: middle, center, inverse # Визуализация данных --- ## Три системы визуализации в R - Base Graphics - Lattice - ggplot2 --- ## Базовая графика Для какой-то простой и быстрой иллюстрации можно использовать базовую графику, не требующую загрузки каких-либо пакетов. ```r plot(fev$Age, fev$FEV, type = "p") ``` <img src="02_intro_ggplot2_files/figure-html/base-graph-1.png" style="display: block; margin: auto;" /> --- ## Немного более украшенный график Существуют дополнительные функции из пакетов, которые позволяют "надстраивать" и видоизменять график. Например, точечный график, построенный на основе базовой графики, можно модифицировать с помощью функции `scatterplot` из пакета `car`. ```r library(car) scatterplot(FEV ~ Age | Sex, data = fev) ``` <img src="02_intro_ggplot2_files/figure-html/scatterplot-1.png" style="display: block; margin: auto;" /> Мы дальше будем знакомиться постепенно с элементами базовой графики, но в целом это не так удобно и настраиваемо, как визуализация средствами пакета `ggplot2`. --- ## Система ggplot2 Название пакета происходит от слов "Grammar", "Graphics", "Plot". В основе подхода, реализованного в пакете, лежит идея **грамматики графиков** "Semiology of Graphics" (Bertin, 1983). Более позднее обобщение “The Grammar of Graphics” (Wilkinson, Anand and Grossman, 2005). --- ## Визуализация данных (первый заход) Задача: построить точечную диаграмму, где по оси OX отложен Age, а по оси OY отложен FEV ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-10-1.png" style="display: block; margin: auto;" /> --- ## Убираем серый фон ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + theme_bw() ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-11-1.png" style="display: block; margin: auto;" /> --- ## Убираем серый фон ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + theme_classic() ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-12-1.png" style="display: block; margin: auto;" /> --- ## Убираем серый фон ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + theme_minimal() ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-13-1.png" style="display: block; margin: auto;" /> --- ## Устанавливаем понравившуюся тему, как основную. ```r theme_set(theme_bw()) ``` далее все графики, производимые в данной сессии, будут использовать именно эту тему ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-15-1.png" style="display: block; margin: auto;" /> --- ## Изменяем подписи осей ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + labs(x = "Возраст", y = "Объем легких") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-16-1.png" style="display: block; margin: auto;" /> --- ## Создаем верхний заголовок рисунка ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-17-1.png" style="display: block; margin: auto;" /> --- ## Делаем заголовок центральным ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-18-1.png" style="display: block; margin: auto;" /> --- ## Меняем размер точек ### Крупнее ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(size = 3) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-19-1.png" style="display: block; margin: auto;" /> --- ### Мельче ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(size = 0.1) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-20-1.png" style="display: block; margin: auto;" /> --- ## Меняем цвет и форму точек ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(color = "blue") + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-21-1.png" style="display: block; margin: auto;" /> --- ## Меняем цвет и форму точек ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(shape = 22, color = "red", fill = "yellow", size = 2) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-22-1.png" style="display: block; margin: auto;" /> --- ## Сохраняем рисунок в файл Создаем рисунок ```r ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(shape = 22, color = "red", fill = "yellow", size = 2) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-23-1.png" style="display: block; margin: auto;" /> --- ## Сохраняем рисунок в файл Сохраняем текущий рисунок в файл ```r ggsave("MyPicture.wmf", plot = last_plot()) ``` --- ## Рисунок-переменная Рисунок можно, и это правильно, поместить в специальную переменную ```r Plot_1 <- ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(shape = 22, color = "red", fill = "yellow", size = 2) Plot_1 ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-25-1.png" style="display: block; margin: auto;" /> --- ## Далее эту переменную можно модифицировать ```r Plot_1 + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-26-1.png" style="display: block; margin: auto;" /> --- ## Далее эту переменную можно модифицировать ```r Plot_2 <- Plot_1 + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) ggsave("MyPicture_2.wmf", plot = Plot_2) ``` --- ## Способы сохранить картинки бывают разные ```r png('MyPicture2.png', width = 1000, height = 1000, units = 'px') Plot_1 # dev.off() ``` Есть также функции, позволяющие сохранить изображения в формате TIFF, JPEG, BMP, PDF... Соответственно, `tiff()`, `jpeg()`, `bmp()` и `pdf()` --- ## Эстетики (Aesthetics) В философии ggplot2 эстетики --- это та информация (данные), которую можно выразить графиком. Минимальные эстетики --- Положение на OX и положение на OY Однако наши данные содержат еще и информацию о поле (переменная `fev$Sex`). Если эти данные для нас важны, то мы должны эту информацию выразить на графике. --- ## Отражаем данные о поле с помощью цвета ```r Plot_1 <- ggplot(data = fev, aes(x = Age, y = FEV, color = Sex )) + geom_point(size = 2) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) Plot_1 ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-29-1.png" style="display: block; margin: auto;" /> --- ## Меняеем цвет на тот, который нам нравится ```r Plot_1 <- Plot_1 + scale_color_manual(values = c("pink", "blue")) Plot_1 ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-30-1.png" style="display: block; margin: auto;" /> --- ## Меняеем положение легенды ```r Plot_1 + theme(legend.position = "bottom") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-31-1.png" style="display: block; margin: auto;" /> --- ## Меняем положение легенды ```r Plot_1 + theme(legend.position = "left") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-32-1.png" style="display: block; margin: auto;" /> --- ## Меняем положение легенды ```r Plot_1 + theme(legend.position = c(0.1, 0.9)) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-33-1.png" style="display: block; margin: auto;" /> `c(0.1, 0.9)` координаты указываются в долях от сторон рисунка --- ## Отражаем данные о поле с помощью формы точек ```r Plot_1 <- ggplot(data = fev, aes(x = Age, y = FEV, shape = Sex, color = Sex )) + geom_point(size = 2) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) Plot_1 ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-34-1.png" style="display: block; margin: auto;" /> --- ## В нашем датафрейме есть еще и данные о курении Если мы хотим выразить графиком одновременно данные по полу и по курению, то мы должны задать две разные эстетики ```r Plot_1 <- ggplot(data = fev, aes(x = Age, y = FEV, shape = Sex, color = Smoker )) + geom_point(size = 2) + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5)) Plot_1 ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-35-1.png" style="display: block; margin: auto;" /> в этом трудно разобраться --- ## Используем фасетирование ```r Plot_1 + facet_wrap( ~ Smoker) #уже лучше ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-36-1.png" style="display: block; margin: auto;" /> --- ## Используем фасетирование ```r Plot_1 + facet_grid(Sex ~ Smoker) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-37-1.png" style="display: block; margin: auto;" /> --- ## Геомы (Geom) Геомы --- это геометрические объекты, которые отражают данные (точки, линии, столбцы, "усы" и т. д.). Задание: построить гистограмму, отражающую частотное распределение объема лёгких. Для решений этой задачи не годится применение точечных диаграмм. Нам нужен другой геом. --- ## geom_histogram() ```r ggplot(fev, aes(x = FEV)) + geom_histogram() ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-38-1.png" style="display: block; margin: auto;" /> --- ## Меням ширину класса Делаем более широкие классовые интервалы ```r ggplot(fev, aes(x = FEV)) + geom_histogram(binwidth = 1) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-39-1.png" style="display: block; margin: auto;" /> --- ## Меням ширину класса Делаем более узкие классовые интервалы ```r ggplot(fev, aes(x = FEV)) + geom_histogram(binwidth = 0.1) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-40-1.png" style="display: block; margin: auto;" /> --- ## Семейство функций `stat` Поскольку в основе построения гистограммы лежит статистическая процедура (определение частот), то все тоже самое можно сделать с помощью функций stat_... ```r ggplot(fev, aes(x = FEV)) + stat_bin(geom = "bar") #Аналогично! ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-41-1.png" style="display: block; margin: auto;" /> --- ## Меняем ширину класса ```r ggplot(fev, aes(x = FEV)) + stat_bin(geom = "bar", binwidth = 0.1) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-42-1.png" style="display: block; margin: auto;" /> Аналогично применению `geom_histogram(binwidth = 0.1)` --- ## Используем другой геом ### Частотное распределение можно выразить еще и линией ```r ggplot(fev, aes(x = FEV)) + stat_bin(geom = "line", size = 1, color = "red") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-43-1.png" style="display: block; margin: auto;" /> --- ## Используем другой геом ### А можно еще и закрашенной областью ```r ggplot(fev, aes(x = FEV)) + stat_bin(geom = "area", size = 1, color = "red") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-44-1.png" style="display: block; margin: auto;" /> --- ## Можно еще многими способами.... Например, так ```r ggplot(fev, aes(x = FEV)) + stat_density(geom = "area", size = 1, color = "red", fill = "blue") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-45-1.png" style="display: block; margin: auto;" /> --- ## Применяем фасетирование У нас есть еще и данные по полу, и мы можем отразить частотное распределение с помощью фасетирования. ```r ggplot(fev, aes(x = FEV)) + geom_histogram() + facet_wrap( ~ Sex) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-46-1.png" style="display: block; margin: auto;" /> --- ## Так удобнее сравнивать ```r ggplot(fev, aes(x = FEV)) + geom_histogram() + facet_wrap( ~ Sex, ncol = 1) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-47-1.png" style="display: block; margin: auto;" /> --- ## Отражаем частотное распределение с использованием данных по полу и курению ```r ggplot(fev, aes(x = FEV, fill = Smoker)) + geom_histogram() + facet_wrap( ~ Sex, ncol = 1) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-48-1.png" style="display: block; margin: auto;" /> Трудно читать --- ## Лучше так ```r ggplot(fev, aes(x = FEV, fill = Smoker)) + stat_density(geom = "area", size = 1, color = "red") + facet_wrap( ~ Sex, ncol = 1) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-49-1.png" style="display: block; margin: auto;" /> --- class: middle, center, inverse # Визуализация данных с использованием простейшей статистической обработки --- ## Задание: отразить срдний объем легких у разных возрастов ```r ggplot(fev, aes(x = Age, y = FEV)) + stat_summary(fun.y = "mean", geom = "line", size = 2) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-50-1.png" style="display: block; margin: auto;" /> --- ## Добавляем данные по полу ```r ggplot(fev, aes(x = Age, y = FEV, color = Sex)) + stat_summary(fun.y = "mean", geom = "line", size = 2) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-51-1.png" style="display: block; margin: auto;" /> --- ## Добавляем данные по курению ```r ggplot(fev, aes(x = Age, y = FEV, color = Sex)) + stat_summary(fun.y = "mean", geom = "line", size = 2) + facet_wrap( ~ Smoker) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-52-1.png" style="display: block; margin: auto;" /> --- ## Задание Постройте столбчатые диаграммы, отражающие средний рост у представителей разного пола. --- ## Решение ```r ggplot(fev, aes(x = Sex, y = Height, fill = Sex)) + stat_summary(fun.y = "mean", geom = "bar") ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-53-1.png" style="display: block; margin: auto;" /> --- ## С помощью функций ggplot можно сразу вписать простые линейные модели и увидеть характер связей ```r ggplot(fev, aes(x = Age, y = FEV, color = Smoker)) + geom_point() + geom_smooth(method = "lm") + facet_wrap( ~ Sex) ``` <img src="02_intro_ggplot2_files/figure-html/unnamed-chunk-54-1.png" style="display: block; margin: auto;" /> --- ## Тепловые карты Наши данные не совсем правильно таким образом визуализировать, но всё-таки можно. ```r ggplot(fev, aes(Age, FEV, fill = Height)) + geom_tile() ``` <img src="02_intro_ggplot2_files/figure-html/heatmaps-1.png" style="display: block; margin: auto;" /> --- ## Take home messages - Для анализа лучше подходит длинный формат - Данные должны быть оформлены в соответствии с определнными правилами - Пакет `ggplot2` позволяет построить практически любой график --- ## Что почитать - [Cookbook for R](http://www.cookbook-r.com/Graphs/) - [R for Data Science. Data visualisation](https://r4ds.had.co.nz/data-visualisation.html) - [Modern Data Visualization with R](https://rkabacoff.github.io/datavis/index.html)