Данные

Принятые нормы

  • Столбцы - переменные (variables)
  • Строки - объекты (observations)
  • В каждой переменной только один тип данных
  • На месте пропущенных значений стоит специальный знак (в R принят NA)

При работе в Excel не должно быть никаких объединенных ячеек!

Два формата представления данных

  • Широкий формат: данные максимально структурированы, каждая строка может нести информацию о многих элементарных объектах

  • Длинный формат: данные минимально структурированы, каждая строка характеризует уникальный объект

Из длинного формата легко получить широкий.

Из широкого формата получить длинный заметно сложнее.

Широкий формат хорош для отчетов, представления обобщенных результатов

Длинный формат хорош для анализа

Визуализация данных с помощью пакета ggplot2

Oбъем легких

Данные взяты из работы
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)

Читаем данные

fev <- read_excel("data/fev.xls", 
                  sheet = "tidy_data", 
                  col_names = TRUE, 
                  na = "NA", 
                  skip = 1 )

Анализируем структуру данных

Имена переменных

names(fev)
## [1] "Age"    "FEV"    "Height" "Sex"    "Smoker"

Анализируем структуру данных

Содержание переменных

str(fev)
## Classes 'tbl_df', 'tbl' and 'data.frame':    654 obs. of  5 variables:
##  $ Age   : num  9 8 7 9 9 8 6 6 8 9 ...
##  $ FEV   : num  1.71 1.72 1.72 1.56 1.9 ...
##  $ Height: num  57 67.5 54.5 53 57 61 58 56 58.5 60 ...
##  $ Sex   : chr  "Female" "Female" "Female" "Male" ...
##  $ Smoker: chr  "Non" "Non" "Non" "Non" ...

Изменяем формат переменных

Необходимо заменить формат в переменных fev$Sex и fev$Smoker

fev$Sex <- factor(fev$Sex)
fev$Smoker <- factor(fev$Smoker)

функция factor() превращает числовые или текстовые данные в дискретные факторы

Пропущенные значения NA

Если необходимо убрать объекты, у которых что-то не измерено (NA), то надо произвести "очистку данных".

НО! не увлекайтесь, иногда можно "вычистить"" важную информацию

В каких строках содержится пропущенная информация?

fev[which(!complete.cases(fev)), ] 
## # A tibble: 2 <U+00D7> 5
##     Age   FEV Height    Sex Smoker
##   <dbl> <dbl>  <dbl> <fctr> <fctr>
## 1    16  4.50   72.0   Male     NA
## 2    NA  3.21   66.5 Female    Non

здесь используется сразу две функции: which(), в нее вложена complete.cases()
! - логическая операция "NOT"
[ , ] - оператор индексации на первом месте строка, на втором - столбец

Убираем из датафрейма неполные строки

fev <- fev[complete.cases(fev), ]

Визуализация данных (первый заход)

Задача: построить точечную диаграмму, где по оси OX отложен Age, а по оси OY отложен FEV

ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point()

убираем серый фон

ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + theme_bw()

убираем серый фон

ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + theme_classic()

убираем серый фон

ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point() + theme_minimal()

Устанавливаем понравившуюся тему, как основную.

theme_set(theme_bw()) 

далее все графики, производимые в данной сессии, будут использовать именно эту тему

ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point()

Изменяем подписи осей

ggplot(data = fev, aes(x = Age, y = FEV)) + 
  geom_point() + 
  labs(x = "Возраст", y = "Объем легких")

Создаем верхний заголовок рисунка

ggplot(data = fev, aes(x = Age, y = FEV)) + 
  geom_point() + 
  labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких")

Делаем заголовок центральным

ggplot(data = fev, aes(x = Age, y = FEV)) + 
  geom_point() + 
  labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5))

Меняем размер точек

Крупнее

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))

Меняем размер точек

Мельче

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))

Меняем цвет и форму точек

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))

Меняем цвет и форму точек

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))

Сохраняем рисунок в файл

Создаем рисунок

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))

Сохраняем рисунок в файл

Сохраняем текущий рисунок в файл

ggsave("MyPicture.wmf", plot = last_plot())

Рисунок-переменная

Рисунок можно, и это правильно, поместить в специальную переменную

Plot_1 <- ggplot(data = fev, aes(x = Age, y = FEV)) + geom_point(shape = 22, color = "red", fill = "yellow", size = 2)

Plot_1

Далее эту переменную можно модифицировать

Plot_1 + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5))

Далее эту переменную можно модифицировать

Plot_2 <- Plot_1 + labs(x = "Возраст", y = "Объем легких", title = "Зависимость между \n возрастом и объемом легких") + theme(plot.title = element_text(hjust = 0.5))


ggsave("MyPicture_2.wmf", plot = Plot_2)

Эстетики (Aesthetics)

В философии ggplot эстетики - это та информация (данные), которую можно выразить графиком.

Минимальные эстетики - Положение на OX и положение на OY

Однако наши данные содержат еще и информацию о поле (переменная fev$Sex). Если эти данные для нас важны, то мы должны эту информацию выразить на графике

Отражаем данные о поле с помощью цвета

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

Меняеем цвет на тот, который нам нравится

Plot_1 <- Plot_1 + scale_color_manual(values = c("pink","blue"))
Plot_1

Меняеем положение легенды

Plot_1  + theme(legend.position =  "bottom")

Меняем положение легенды

Plot_1  + theme(legend.position =  "left")

Меняем положение легенды

Plot_1  + theme(legend.position =  c(0.1, 0.9)) 

c(0.1, 0.9) координаты указываются в долях от сторон рисунка

Отражаем данные о поле с помощью формы точек

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

В нашем датафрейме есть еще и данные о курении

Если мы хотим выразить графиком одновременно данные по полу и по курению, то мы должны задать две разные эстетики

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 

в этом трудно разобраться

Используем фасетирование

Plot_1 + facet_wrap( ~ Smoker) #уже лучше

Используем фасетирование

Plot_1 + facet_grid(Sex ~ Smoker)

Геомы (Geom)

Геомы - это геометрические объекты, которые отражают данные (точки, линии, столбцы, "усы" и т. д.)

Задание: построить гистограмму, отражающую частотное распределение объема легких

Для решений этой задачи не годится применение точечных диаграмм

Нам нужен другой геом

geom_histogram()

ggplot(fev, aes(x = FEV)) + geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Меням ширину класса

Делаем более широкие классовые интервалы

ggplot(fev, aes(x = FEV)) + geom_histogram(binwidth = 1)

Меням ширину класса

Делаем более узкие классовые интервалы

ggplot(fev, aes(x = FEV)) + geom_histogram(binwidth = 0.1)

Семейство Функций stat

Поскольку в основе построения гистограммы лежит статистическая процедура (определение частот), то все тоже самое можно сделать с помощью функций stat_…

ggplot(fev, aes(x = FEV)) + stat_bin(geom = "bar") #Аналогично!

Меняем ширину класса

ggplot(fev, aes(x = FEV)) + stat_bin(geom = "bar", binwidth = 0.1)

Аналогично применению geom_histogram(binwidth = 0.1)

Используем другой геом

Частотное распределение можно выразить еще и линией

ggplot(fev, aes(x = FEV)) + stat_bin(geom = "line", size = 1, color = "red")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Используем другой геом

А можно еще и закрашенной областью

ggplot(fev, aes(x = FEV)) + stat_bin(geom = "area", size = 1, color = "red")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Можно еще многими способами….

Например, так

ggplot(fev, aes(x = FEV)) + stat_density(geom = "area", size = 1, color = "red", fill = "blue")

Применяем фасетирование

Но у нас есть еще и данные по полу

Мы можем отразить частотное распределение с помощью фасетирования

ggplot(fev, aes(x = FEV)) + geom_histogram() + facet_wrap( ~ Sex)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Так удобнее сравнивать

ggplot(fev, aes(x = FEV)) + geom_histogram() + facet_wrap( ~ Sex, ncol = 1) 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Отражаем частотное распределение с использованием данных по полу и курению

ggplot(fev, aes(x = FEV, fill = Smoker)) + geom_histogram() + facet_wrap( ~ Sex, ncol = 1) 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Трудно читать

Лучше так

ggplot(fev, aes(x = FEV, fill = Smoker)) + stat_density(geom = "area", size = 1, color = "red") + facet_wrap( ~ Sex, ncol = 1)

Визуализация данных с использованием простейшей статистической обработки

Задание: отразить срдний объем легких у разных возрастов

ggplot(fev, aes(x = Age, y = FEV)) + 
  stat_summary(fun.y = "mean", geom = "line", size = 2)

Добавляем данные по полу

ggplot(fev, aes(x = Age, y = FEV, color = Sex)) + 
  stat_summary(fun.y = "mean", geom = "line", size = 2)

Добавляем данные по курению

ggplot(fev, aes(x = Age, y = FEV, color = Sex)) + 
  stat_summary(fun.y = "mean", geom = "line", size = 2) + 
  facet_wrap( ~ Smoker)

Задание:

Постройте столбчатые диаграммы, отражающие средний рост у представителей разного пола

Решение

ggplot(fev, aes(x = Sex, y = Height, fill = Sex)) + 
  stat_summary(fun.y = "mean", geom = "bar") 

С помощью функций ggplot можно сразу вписать простые линейные модели и увидеть характер связей

ggplot(fev, aes(x = Age, y = FEV, color = Smoker)) + 
  geom_point() + 
  geom_smooth(method = "lm") +  
  facet_wrap( ~ Sex)

Разведочный графический анализ

Задачи разведочного анализа:

  • выявление отскакивающих значений
  • Выявление характера связей между переменными

dotplot - диаграмма, позволяющая увидеть отскакивающие переменные

ggplot(fev, aes(x = Age, y = 1:nrow(fev))) + geom_point()

dotplot - диаграмма, позволяющая увидеть отскакивающие переменные

ggplot(fev, aes(x = Height, y = 1:nrow(fev))) + geom_point()

Отскакивающих значений нет

dotplot - диаграмма, позволяющая увидеть отскакивающие переменные

ggplot(fev, aes(x = Height, y = 1:nrow(fev))) + geom_point()

Отскакивающих значений нет

dotplot - диаграмма, позволяющая увидеть отскакивающие переменные

ggplot(fev, aes(x = FEV, y = 1:nrow(fev))) + geom_point()

Отскакивающих значений нет

Искусственно создадим отскакивающую величину

fev1 <- fev
n <- sample(1:nrow(fev), 1) #Случайный номер объекта
fev1$FEV[n] <- fev1$FEV[n] * 10 # не там поставили запятую
ggplot(fev1, aes(x = FEV, y = 1:nrow(fev))) + geom_point()

Характер связи

ggplot(fev, aes(x = Age, y = Height)) + geom_point() + geom_smooth(se = FALSE)
## `geom_smooth()` using method = 'loess'

Явно читается нелинейность

Характер связи

ggplot(fev, aes(y = FEV, x = Height)) + geom_point() + geom_smooth(se = FALSE)
## `geom_smooth()` using method = 'loess'

Явно читается нелинейность

Характер связи

ggplot(fev, aes(y = FEV, x = Age)) + geom_point() + geom_smooth(se = FALSE)
## `geom_smooth()` using method = 'loess'

Явно читается нелинейность

Take home messages

  • Для анализа лучше подходит длинный формат
  • Данные должны быть оформлены в соответствии с определнными правилами
  • Пакет ggplot2 позволяет построить практически любой график