суббота, 20 июня 2020 г.

R : графика ggplot2

В среде R представлены 3 разные системы построения графиков. Изначально в эту систему была заложена так называемая базовая графика, base graphics, позже появилась система lattice, которая позволяет комбинировать несколько графиков в виде такого комбинированного рисунка, и позже появилась система ggplot2, которую будем рассматривать в этой статье.

Система ggplot2 получила своё название от трёх слов - Grammar, Graphics, Plot..
Он построен на концепции грамматики графика, представленная Уилкинсоном в 1999 году, и эта грамматика графики была реализована в R пакет Хэдли Уикхем в 2005 году. График в рамках пакета ggplot2 представляется как конструктор, состоящий из отдельных частей, которые можно соединять произвольным образом, чтобы достичь желаемого эффекта.
Основные кирпичики графического конструктора (первые три их них являются обязательными составляющими):
  1. data - data.frame, содержащий данные для представления.
  2. aes() - задает связь между данными и их представлением, определяет какие переменные отображаются на осях, какие переменные отвечают за цвет и форму данных, представленных на графике.
  3. geom_ - группа функций, отвечающих за то что, вы непосредственно видите на графике (точки, гистограммы, линии, текст и т.п.).
  4. scale_ - группа функций, соотносящих реальные данные с их графическим представлением. Это может быть цвет, форма, размер, диапазон осей координат и т.п.
  5. stat_ - группа функций, добавляющих на график различные статистические показатели, например, такие как, среднее значение по группе, линейная или иная аппроксимация данных и т.п.
  6. coord_ - группа функций, которая задает систему координат для представления данных на плоскости. Это могут быть обычные картезианские координаты, полярные координаты, или географические координаты для представления соответствующих данных.
  7. facet_ - группа функций, которые позволяют группировать графики по заданному параметру и представлять результаты в виде набора графиков (сетки из графиков).
  8. theme - группа функций, позволяющих менять оформление графика, например размер и цвет шрифта координатных осей и делений на них, фон графика и всего рисунка и т.п.

Для демонстрации приемов работы с графикой загрузим датафрейм с дневными продажи футболок в розничном магазине одежды


df <- read_excel("ShopSaleTS.xlsx")

head(df)

# A tibble: 6 x 7
  Date                          Gender    Category ProdCode       Size     Sale    Price
  <dttm>              <          chr>       <chr>    <chr>     <      chr>   <dbl> <dbl>
1 2019-06-01 00:00:00 Female     T-shirt  TSSQ55265      S          1        999
2 2019-06-01 00:00:00 Male         T-shirt  TSSQ54736     M         1        849
3 2019-06-01 00:00:00 Female     T-shirt  TSSQ60427      L         1        3999
4 2019-06-01 00:00:00 Male         T-shirt  TSSQ45158      S         1        1899
5 2019-06-01 00:00:00 Female     T-shirt  TSSQ45162     XS       1        1899
6 2019-06-01 00:00:00 Female     T-shirt  TSSQ51697     XL       1        999

str(df)

Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 1300 obs. of  7 variables:
 $ Date    : POSIXct, format: "2019-06-01" "2019-06-01" "2019-06-01" ...
 $ Gender  : chr  "Female" "Male" "Female" "Male" ...
 $ Category: chr  "T-shirt" "T-shirt" "T-shirt" "T-shirt" ...
 $ ProdCode: chr  "TSSQ55265" "TSSQ54736" "TSSQ60427" "TSSQ45158" ...
 $ Size    : chr  "S" "M" "L" "S" ...
 $ Sale    : num  1 1 1 1 1 1 1 1 1 1 ...

 $ Price   : num  999 849 3999 1899 1899 ...


Сделаем некоторые преобразования переменных, переведем переменные пол и размер в факторные переменные 

df<- mutate(df,Date=as.Date(Date),
            Gender=factor(Gender,order = TRUE, levels=c('Female','Male')),
            Size=factor(Size,order = TRUE,
            levels=c('XS','S','M','L','XL','XXL','3XL','4XL','5XL')))

str(df)

Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 1300 obs. of  7 variables:
 $ Date    : Date, format: "2019-06-01" "2019-06-01" "2019-06-01" ...
 $ Gender  : Ord.factor w/ 2 levels "Female"<"Male": 1 2 1 2 1 1 2 2 2 2 ...
 $ Category: chr  "T-shirt" "T-shirt" "T-shirt" "T-shirt" ...
 $ ProdCode: chr  "TSSQ55265" "TSSQ54736" "TSSQ60427" "TSSQ45158" ...
 $ Size    : Ord.factor w/ 9 levels "XS"<"S"<"M"<"L"<..: 2 3 4 2 1 5 6 6 3 3 ...
 $ Sale    : num  1 1 1 1 1 1 1 1 1 1 ...
 $ Price   : num  999 849 3999 1899 1899 ...



Одномерная визуализация числовой переменной

Гистограмма

При построении гистограммы отобрал самые необходимые с моей точки зрения настройки

binsize <- diff(range(df$Price))/10      #ширина шага

ggplot(df, aes(x = Price)) +
  #fill - цвет заливки, colour - цвет границы, boundary - выравнивание границ классов
  geom_histogram(binwidth = binsize, fill = "white", colour = "black",boundary=50)+
  coord_cartesian(ylim = c(0,350))+ #Диапазон по оси y
  xlab("Price T-Shirt") + #Название оси x
  ylab("Sales")+ #Название оси y
  ggtitle("T-shirt sales in price ranges","June 2019") + #Заголовок из двух строк
  theme(plot.title = element_text(hjust = 0.5)) #Заголовок по центру


Разделим гистограмму по полу на две гистограммы

ggplot(df, aes(x = Price)) +
  #fill - цвет заливки, colour - цвет границы, boundary - выравнивание границ классов
  geom_histogram(binwidth = binsize, fill = "white", colour = "black",boundary=50)+
  coord_cartesian(ylim = c(0,350))+ #Диапазон по оси y
  xlab("Price T-Shirt") + #Название оси x
  ylab("Sales")+ #Название оси y
  ggtitle("T-shirt sales in price ranges","June 2019") + #Заголовок из двух строк
  theme(plot.title = element_text(hjust = 0.5)) + #Заголовок по центру
  facet_grid(Gender ~ .) #Делим на две гистограммы по полу







На одной гистограмме разделим данные по полу по цвету и добавим на гистограмму средние цены продаж по полу


mean_price <- df %>% 
  group_by(Gender) %>% 
  summarise(avg_price = mean(Price))


ggplot(df, aes(x = Price, fill = Gender)) +
  #fill - цвет заливки, colour - цвет границы, boundary - выравнивание границ классов
  geom_histogram(binwidth = binsize, colour = "black",
                 boundary=50,position = "identity", alpha = 0.4)+
  coord_cartesian(ylim = c(0,200))+ #Диапазон по оси y
  xlab("Price T-Shirt") + #Название оси x
  ylab("Sales")+ #Название оси y
  ggtitle("T-shirt sales in price ranges","June 2019") + #Заголовок из двух строк
  theme(plot.title = element_text(hjust = 0.5)) + #Заголовок по центру
  geom_vline(
    data = mean_price,
    aes(xintercept = avg_price, colour = Gender),
    linetype = "dashed",
    size = 1
  ) #Добавляем средние цены продажи по полу



Boxplot


Этот тип графика также вывожу с основными настройками и с обозначение средних значений цен по мужским и женским футболкам


ggplot(df, aes(x=Gender,y = Price,fill=Gender)) +
  geom_boxplot(outlier.color = "red", outlier.size = 5) + #Выделяем выбросы
  geom_hline(data = mean_price,
  aes(yintercept = avg_price, colour = Gender),
  linetype = "dashed",
  size = 1) + #Добавляем средние значения цен по полу
  scale_fill_manual(values = c("#FFCCCC","#99CCFF"))+ #Задаем свой набор цветов заливки
  scale_color_manual(values = c("red", "black")) #Задаем свой набор цветов линий средних значений




Можно разделить по полу и размерам

ggplot(df, aes(x=interaction(Gender,Size),y = Price,fill=Gender)) +
  geom_boxplot()+
  theme(axis.text.x = element_text(angle=45,size=10))+  #Задаем размер и угол наклона обозначений по оси x
  scale_fill_manual(values = c("#FFCCCC","#99CCFF"))





Вывод графика в форме Violin хорош тем, что он показывает плотность вероятности данных при различных значениях. Это дает представление о форме распределения данных





Одномерное исследование категориальной переменной

Когда мы исследуем категориальную переменную, мы можем взглянуть на две вещи, либо частоты категорий или пропорции. Визуализация категориальной переменной может быть выполнена двумя способами: либо гистограммой, либо столбчатой диаграммой. По сути, это одно и то же. Просто информация представлена ​​в другом формате. Далее будем работать со столбчатой диаграммой. Посмотрим распределение женских футболок по размерам

ggplot(data = df %>% filter(Gender =='Female'), mapping = aes(x= Size)) + 
         geom_bar() +
         geom_text(aes(label = ..count..), stat = "count", vjust = 1.5,colour = "white")



Выведем диаграмму в процентах


ggplot(data = df %>% filter(Gender =='Female'), mapping = aes(x= Size)) + 
             geom_bar(aes(y=..count../sum(..count..))) +
             scale_y_continuous(labels = scales::percent_format())



Выведем распределение по полу

ggplot(data = df , mapping = aes(x= Gender,fill=Gender)) +
           geom_bar(position="dodge") +
           scale_fill_manual(values =c("#FF3399","#3399FF"))


Распределение по полу и по размерам

ggplot(data = df , mapping = aes(x= Size,fill=Gender)) +
             geom_bar(position="dodge") +

             scale_fill_manual(values =c("#FF3399","#3399FF"))






Визуализация взаимосвязи между двумя числовыми переменными

Для примера взаимосвязи между двумя непрерывными переменными рассмотрим новый датафрейм - стоимость аренды магазина в зависимости от его месячной проходимости. Понятно, что проходимость, это не единственный параметр, определяющий стоимость аренды, но стоит предположить, что он тем не менее, является определяющим.


df <- read_excel("ShopRent.xlsx")
df$City <- as.factor(df$City)
head(df)

# A tibble: 6 x 3
  City  Visit  Rent
  <fct> <dbl> <dbl>
1 City5  3380  2672
2 City2  5448  4183
3 City3  1903  1598
4 City6  4496  3550
5 City6  4599  3665
6 City6  1399  1279

str(df)


Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 100 obs. of  3 variables:
 $ City : Factor w/ 6 levels "City1","City2",..: 5 2 3 6 6 6 1 1 4 2 ...
 $ Visit: num  3380 5448 1903 4496 4599 ...
 $ Rent : num  2672 4183 1598 3550 3665 ...

В датафрейме находятся 100 наблюдений, представляющих посещаемость (Visit) и стоимость аренды в условных единицах (Rent) в 100 магазинах, расположенных в шести городах. Попробуем графически определить, если зависимость между арендой и посещаемостью.
Для выявления связи между двумя непрерывными числовыми переменными используется диаграмма рассеяния, в пакете ggplot2 для этого используется функция geom_point, которую мы прибавляем к базовому слою. 


ggplot(df, aes(x = Visit, y = Rent, colour = City)) +

  geom_point()







Как видим по графику, зависимость определенно есть. Можем проверить с помощью теста на корреляцию. Для этих целей мы воспользуемся функцией cor.test(). Синтаксис этой функции очень прост. Этой функции надо передать имя первого из сопряженных векторов и имя второго из сопряженных векторов. Дальше необходимо указать метод вычисления коэффициента корреляции, то есть тип коэффициента корреляции. В качестве метода вычисления коэффициента корреляции, то есть типа коэффициента корреляции, будем использовать пирсоновский коэффициент корреляции, то есть обычную линейную корреляцию. 

cor.test(x=df$Visit,y=df$Rent,method = "pearson")

Pearson's product-moment correlation

data:  df$Visit and df$Rent
t = 14.28, df = 98, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7458058 0.8767278
sample estimates:
      cor 
0.8218337 

По результатам теста мы видим, что между посещаемостью и арендной платой существует статистически значимая положительная корреляция.  Поэтому  попробуем построим линию регрессии с доверительной зоной при помощи пакета ggplot. Для этого  добавим на график geom_smooth. Smooth — сглаживать. Это geom, который строит разного вида зависимости. В данном случае мы используем метод «Линейная модель». geom_smooth сразу построит нам и линию регрессии, и ее доверительную зону. 

ggplot(df, aes(x = Visit, y = Rent)) +
   geom_point()+
   geom_smooth(method="lm")

Визуализация отношений между двумя категориальными переменными

У нас есть данные о дневных продажах мужских и женских футболок. 

df1 <- read_excel("ShopSaleTS.xlsx")

df1<- mutate(df1,Date=as.Date(Date),
            Gender=factor(Gender,order = TRUE, levels=c('Female','Male')),
            Wday = factor(wday(Date,week_start =1)))


head(df1)

# A tibble: 6 x 8
  Date           Gender Category ProdCode      Size   Sale Price   Wday 
  <date>         <ord>  <chr>    <chr>              <chr> <dbl> <dbl>  <fct>
1 2019-06-01 Female T-shirt  TSSQ55265      S         1       999       6    
2 2019-06-01 Male     T-shirt  TSSQ54736      M         1      849        6    
3 2019-06-01 Female T-shirt  TSSQ60427      L         1     3999       6    
4 2019-06-01 Male     T-shirt  TSSQ45158      S         1     1899       6    
5 2019-06-01 Female T-shirt  TSSQ45162     XS        1    1899       6    
6 2019-06-01 Female T-shirt  TSSQ51697     XL        1      999       6    


И мы хотим увидеть, сколько продаж существует для комбинация каждого пола и дня недели. Для этого создадим кросс-таблицу. 

cross_tab <- xtabs(~Gender+Wday, data=df1)

cross_tab

        Wday
Gender     1   2   3   4   5   6   7
  Female  83  51  62  42  52 121 101
  Male    80  79  99  67  76 241 146

 Можно просто использовать эту кросс-таблицу, чтобы увидеть, как соотносятся продажи мужских и женских футболок по дням недели.Но если мы хотим визуализацию, то проделаем еще несколько преобразований. 
Пусть название строк - это пол, дни недели - это названия столбцов. С помощью функции expand.grid создаем столбцы, которые представляют собой комбинации пола и дня недели. Получаем датафрейм с двумя переменные, переменную один и переменную два. Переменная один - переменная пол, два - день недели. В качестве третьей переменной вставляем количество продаж.

Gender <- rownames(cross_tab)
Weekday <- colnames(cross_tab)

df2 <- expand.grid(Gender,Weekday)
Count <- as.vector(cross_tab)
df2$Count <- Count
head(df2)

    Var1     Var2  Count
1 Female    1      83
2   Male      1      80
3 Female    2      51
4   Male       2     79
5 Female    3      62
6   Male       3     99


Теперь наши данные готовы к визуализации. 

ggplot(data =df2 , aes(x= factor(Var1), y = factor(Var2), size = Count))+
    geom_point(col = "red") + labs(x = "gender", y="wday")



Такой же график можно было сделать сразу из исходного датафрейма используя функцию geom_count.

ggplot(data = df1, aes(x= Gender, y = Wday))+
  geom_count(color = "red")





Многомерные диаграммы

Были рассмотрены  одномерные и двумерные распределения, где была одна и две переменные соответственно. Но часто бывает потребность оценить распределение по большему количеству переменных и таким образом мы переходи в область многомерных распределений и многомерных диаграмм. Вернемся к наши данным по продажам мужских и женских футболок. В этих данных можно обнаружить три измерения - пол, размер и цена. Попробуем разобраться в том, есть ли зависимости между ними. Например что происходит с ценой футболок по мере увеличения размера, стоит предположить, что цена будет расти, но насколько отличается эластичность цены по отношению к размеру в зависимости от пола. Вернемся к нашему датафрейму

head(df1)

# A tibble: 6 x 8
  Date           Gender Category ProdCode      Size   Sale Price   Wday 
  <date>         <ord>  <chr>    <chr>              <chr> <dbl> <dbl>  <fct>
1 2019-06-01 Female T-shirt  TSSQ55265      S         1       999       6    
2 2019-06-01 Male     T-shirt  TSSQ54736      M         1      849        6    
3 2019-06-01 Female T-shirt  TSSQ60427      L         1     3999       6    
4 2019-06-01 Male     T-shirt  TSSQ45158      S         1     1899       6    
5 2019-06-01 Female T-shirt  TSSQ45162     XS        1    1899       6    
6 2019-06-01 Female T-shirt  TSSQ51697     XL        1      999       6    

Построим диаграмму без деления по полу с линией регрессии

ggplot(data = df1, mapping = aes(x= as.numeric(df1$Size), y = Price))+ 
  geom_point() + geom_smooth(method="lm", se= FALSE)



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

ggplot(data = df1, mapping = aes(x= as.numeric(df1$Size), y = Price,col = Gender))+ 
       geom_point() + geom_smooth(method="lm", se= FALSE)+
       scale_color_manual(values=c("#FF3399","#3399FF"))



Видно, что есть небольшое различие в эластичности в зависимости от пола, по мужским футболкам рост наблюдается чуть более крутой.

































































































Комментариев нет:

Отправить комментарий