Единицей данных в нашем случае будет таблица или в объектах R - dataframe. В этой статье рассмотрим основные методы работы с данными, представленными в виде таблицы. Для примера используем дневные продажи розничного магазина одежды. Загружаем данные и смотрим на его содержание и структуру.
shop <- read_excel("ShopSale06.xlsx")
head(shop)
Добавим в него колонку дня недели
shop$Wday <- wday(shop$Date, label = T)
str(shop$Wday)
Ord.factor w/ 7 levels "Вс"<"Пн"<"Вт"<..: 7 7 7 7 7 7 7 7 7 7 ...
Функция filter позволяет нам отбирать данные по значениям строк, а select - по названиям столбцов.
Отбираем продажи по воскресеньям и понедельникам
head(filter(shop, Wday=='Вс' | Wday=='Пн'))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-02 00:00:00 SQ52607 Мужской Брюки Лето 1 Вс
2 2019-06-02 00:00:00 SQ53860 Унисекс Аксессуары Универсал 1 Вс
3 2019-06-02 00:00:00 SQ60373 Мужской Куртка Демисезонный 1 Вс
4 2019-06-02 00:00:00 SQ60385 Мужской Куртка Демисезонный 1 Вс
5 2019-06-02 00:00:00 SQ60393 Мужской Шорты Лето 1 Вс
6 2019-06-02 00:00:00 SQ60402 Мужской Футболка Лето 1 Вс
Отбираем продажи брюк или курток
head(filter(shop, Category=='Брюки' | Category=='Куртка'))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-01 00:00:00 SQ49786 Мужской Брюки Лето 1 Сб
2 2019-06-01 00:00:00 SQ57751 Женский Брюки Универсал 1 Сб
3 2019-06-01 00:00:00 SQ57759 Мужской Брюки Универсал 1 Сб
4 2019-06-01 00:00:00 SQ058698 Мужской Брюки Универсал 1 Сб
5 2019-06-01 00:00:00 SQ60703 Мужской Брюки Универсал 1 Сб
6 2019-06-01 00:00:00 SQ60712 Мужской Брюки Универсал 1 Сб
Отбираем продажи в штуках от 2 до 3
head(filter(shop, Amt>=2 & Amt<=3))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-01 00:00:00 SQ61091 Мужской Брюки Универсал 2 Сб
2 2019-06-01 00:00:00 SQ61181 Женский Шорты Лето 2 Сб
3 2019-06-02 00:00:00 SQ49034 Мужской Шорты Лето 2 Вс
4 2019-06-02 00:00:00 SQ60850 Мужской Рубашка Лето 2 Вс
5 2019-06-02 00:00:00 SQ60996 Мужской Рубашка Лето 2 Вс
6 2019-06-02 00:00:00 SQ61156 Женский Футболка Лето 2 Вс
Отбираем брюки с продажами от двух единиц
head(filter(shop, Amt>=2 & Category=='Брюки'))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-01 00:00:00 SQ61091 Мужской Брюки Универсал 2 Сб
2 2019-06-02 00:00:00 SQ58169 Мужской Брюки Лето 2 Вс
3 2019-06-08 00:00:00 SQ59159 Мужской Брюки Универсал 2 Сб
4 2019-06-08 00:00:00 SQ59692 Женский Брюки Лето 2 Сб
5 2019-06-09 00:00:00 SQ52607 Мужской Брюки Лето 2 Вс
6 2019-06-09 00:00:00 SQ57759 Мужской Брюки Универсал 2 Вс
Отбираем колонки с полом, категорией и продажами
head(select(shop,Gender,Category,Amt))
Операторы %>% и %in%
Оператор %>% задает конвейерное выполнение функций, например нужно отобрать продажи брюк и вывести только три колонки
shop %>%
filter(Category=='Брюки') %>%
select(Gender,Category,Amt)
# A tibble: 198 x 3
Gender Category Amt
<chr> <chr> <dbl>
1 Мужской Брюки 1
2 Женский Брюки 1
3 Мужской Брюки 1
4 Мужской Брюки 1
5 Мужской Брюки 1
6 Мужской Брюки 1
7 Женский Брюки 1
8 Мужской Брюки 1
9 Мужской Брюки 2
10 Мужской Брюки 1
# ... with 188 more rows
Оператор %in% это оператор проверки на включение, его удобно использовать в фильтрах, например отбор продаж брюк и футболок больше двух единиц
shop %>%
filter(Amt>=2 & Category %in% c('Брюки','Футболка')) %>%
select(Gender,Category,Amt)
Создание новых переменных с помощью функции
Mutate
Часто возникает необходимость создать новую колонку по значениям в других колонках, например мы хотим ввести колонку рабочий / выходной, чтобы потом можно было легче группировать продажи по рабочим и выходным дням. Для этого используется функция mutate
shop <- shop %>%
mutate(WH = ifelse(Wday %in% c('Сб','Вс'),1,0))
head(shop[,c('Wday','WH')])
# A tibble: 6 x 2
Wday WH
<ord> <dbl>
1 Сб 1
2 Сб 1
3 Сб 1
4 Сб 1
5 Сб 1
6 Сб 1
shop <- read_excel("ShopSale06.xlsx")
head(shop)
# A tibble: 6 x 6
Date Code Gender Category Season Amt
<dttm> <chr> <chr> <chr> < chr> <dbl>
1 2019-06-01 00:00:00 SQ52420 Женский Шорты Лето 1
2 2019-06-01 00:00:00 SQ54655 Мужской Шорты Лето 1
3 2019-06-01 00:00:00 SQ60070 Унисекс Аксессуары Универсал 1
4 2019-06-01 00:00:00 SQ60453 Женский Рубашка Универсал 1
5 2019-06-01 00:00:00 SQ49034 Мужской Шорты Лето 1
6 2019-06-01 00:00:00 SQ49786 Мужской Брюки Лето 1
str(shop)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 1411 obs. of 6 variables:
$ Date : POSIXct, format: "2019-06-01" "2019-06-01" "2019-06-01" ...
$ Code : chr "SQ52420" "SQ54655" "SQ60070" "SQ60453" ...
$ Gender : chr "Женский" "Мужской" "Унисекс" "Женский" ...
$ Category: chr "Шорты" "Шорты" "Аксессуары" "Рубашка" ...
$ Season : chr "Лето" "Лето" "Универсал" "Универсал" ...
$ Amt : num 1 1 1 1 1 1 1 1 1 1 ...
Добавим в него колонку дня недели
shop$Wday <- wday(shop$Date, label = T)
str(shop$Wday)
Ord.factor w/ 7 levels "Вс"<"Пн"<"Вт"<..: 7 7 7 7 7 7 7 7 7 7 ...
Функции фильтра и выбора
Функция filter позволяет нам отбирать данные по значениям строк, а select - по названиям столбцов.
Отбираем продажи по воскресеньям и понедельникам
head(filter(shop, Wday=='Вс' | Wday=='Пн'))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-02 00:00:00 SQ52607 Мужской Брюки Лето 1 Вс
2 2019-06-02 00:00:00 SQ53860 Унисекс Аксессуары Универсал 1 Вс
3 2019-06-02 00:00:00 SQ60373 Мужской Куртка Демисезонный 1 Вс
4 2019-06-02 00:00:00 SQ60385 Мужской Куртка Демисезонный 1 Вс
5 2019-06-02 00:00:00 SQ60393 Мужской Шорты Лето 1 Вс
6 2019-06-02 00:00:00 SQ60402 Мужской Футболка Лето 1 Вс
Отбираем продажи брюк или курток
head(filter(shop, Category=='Брюки' | Category=='Куртка'))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-01 00:00:00 SQ49786 Мужской Брюки Лето 1 Сб
2 2019-06-01 00:00:00 SQ57751 Женский Брюки Универсал 1 Сб
3 2019-06-01 00:00:00 SQ57759 Мужской Брюки Универсал 1 Сб
4 2019-06-01 00:00:00 SQ058698 Мужской Брюки Универсал 1 Сб
5 2019-06-01 00:00:00 SQ60703 Мужской Брюки Универсал 1 Сб
6 2019-06-01 00:00:00 SQ60712 Мужской Брюки Универсал 1 Сб
Отбираем продажи в штуках от 2 до 3
head(filter(shop, Amt>=2 & Amt<=3))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-01 00:00:00 SQ61091 Мужской Брюки Универсал 2 Сб
2 2019-06-01 00:00:00 SQ61181 Женский Шорты Лето 2 Сб
3 2019-06-02 00:00:00 SQ49034 Мужской Шорты Лето 2 Вс
4 2019-06-02 00:00:00 SQ60850 Мужской Рубашка Лето 2 Вс
5 2019-06-02 00:00:00 SQ60996 Мужской Рубашка Лето 2 Вс
6 2019-06-02 00:00:00 SQ61156 Женский Футболка Лето 2 Вс
Отбираем брюки с продажами от двух единиц
head(filter(shop, Amt>=2 & Category=='Брюки'))
# A tibble: 6 x 7
Date Code Gender Category Season Amt Wday
<dttm> <chr> <chr> <chr> <chr> <dbl> <ord>
1 2019-06-01 00:00:00 SQ61091 Мужской Брюки Универсал 2 Сб
2 2019-06-02 00:00:00 SQ58169 Мужской Брюки Лето 2 Вс
3 2019-06-08 00:00:00 SQ59159 Мужской Брюки Универсал 2 Сб
4 2019-06-08 00:00:00 SQ59692 Женский Брюки Лето 2 Сб
5 2019-06-09 00:00:00 SQ52607 Мужской Брюки Лето 2 Вс
6 2019-06-09 00:00:00 SQ57759 Мужской Брюки Универсал 2 Вс
Отбираем колонки с полом, категорией и продажами
head(select(shop,Gender,Category,Amt))
# A tibble: 6 x 3
Gender Category Amt
<chr> <chr> <dbl>
1 Женский Шорты 1
2 Мужской Шорты 1
3 Унисекс Аксессуары 1
4 Женский Рубашка 1
5 Мужской Шорты 1
6 Мужской Брюки 1
Операторы %>% и %in%
Оператор %>% задает конвейерное выполнение функций, например нужно отобрать продажи брюк и вывести только три колонки
shop %>%
filter(Category=='Брюки') %>%
select(Gender,Category,Amt)
# A tibble: 198 x 3
Gender Category Amt
<chr> <chr> <dbl>
1 Мужской Брюки 1
2 Женский Брюки 1
3 Мужской Брюки 1
4 Мужской Брюки 1
5 Мужской Брюки 1
6 Мужской Брюки 1
7 Женский Брюки 1
8 Мужской Брюки 1
9 Мужской Брюки 2
10 Мужской Брюки 1
# ... with 188 more rows
Оператор %in% это оператор проверки на включение, его удобно использовать в фильтрах, например отбор продаж брюк и футболок больше двух единиц
shop %>%
filter(Amt>=2 & Category %in% c('Брюки','Футболка')) %>%
select(Gender,Category,Amt)
# A tibble: 41 x 3
Gender Category Amt
<chr> <chr> <dbl>
1 Мужской Брюки 2
2 Женский Футболка 2
3 Мужской Футболка 2
4 Мужской Брюки 2
5 Мужской Футболка 2
6 Женский Футболка 2
7 Мужской Футболка 2
8 Мужской Брюки 2
9 Женский Брюки 2
10 Мужской Брюки 2
# ... with 31 more rows
Создание новых переменных с помощью функции
Mutate
Часто возникает необходимость создать новую колонку по значениям в других колонках, например мы хотим ввести колонку рабочий / выходной, чтобы потом можно было легче группировать продажи по рабочим и выходным дням. Для этого используется функция mutate
shop <- shop %>%
mutate(WH = ifelse(Wday %in% c('Сб','Вс'),1,0))
head(shop[,c('Wday','WH')])
# A tibble: 6 x 2
Wday WH
<ord> <dbl>
1 Сб 1
2 Сб 1
3 Сб 1
4 Сб 1
5 Сб 1
6 Сб 1
Агрегирование данных с использованием функций Summarize и
Group_By
Функции summarize и group_by дают возможность агрегировать данные, например с помощью summarize выведем суммарные продажи и средние продажи на артикул
shop %>%
summarise(sum_amt = sum(Amt,na.rm=T), avg_amt = mean(Amt,na.rm=T))
# A tibble: 1 x 2
sum_amt avg_amt
<dbl> <dbl>
1 1681 1.20
А в связке с функцией group_by можно выводить агрегированную информацию в разрезе определенных группировок. Например выведем суммарные и средние продажи по рабочим и выходным дням
shop %>%
group_by(WH) %>%
summarise(sum_amt = sum(Amt,na.rm=T),
avg_amt = mean(Amt,na.rm=T))
# A tibble: 2 x 3
WH sum_amt avg_amt
<dbl> <dbl> <dbl>
1 0 896 1.18
2 1 785 1.22
Можно делать и более сложные группировки, например суммарные и средние продажи в разрезе пола и категории
shop %>%
group_by(Gender,Category) %>%
summarise(sum_amt = sum(Amt,na.rm=T),
avg_amt = mean(Amt,na.rm=T))
# A tibble: 17 x 4
# Groups: Gender [3]
Gender Category sum_amt avg_amt
<chr> <chr> <dbl> <dbl>
1 Женский Аксессуары 119 1.42
2 Женский Брюки 67 1.08
3 Женский Куртка 22 1.05
4 Женский Платье 25 1.09
5 Женский Рубашка 29 1
6 Женский Толстовка 22 1
7 Женский Футболка 224 1.04
8 Женский Шорты 46 1.12
9 Женский Юбка 7 1
10 Мужской Аксессуары 418 1.79
11 Мужской Брюки 145 1.08
12 Мужской Куртка 25 0.926
13 Мужской Рубашка 77 1.12
14 Мужской Толстовка 10 1.11
15 Мужской Футболка 297 1.04
16 Мужской Шорты 106 1.09
17 Унисекс Аксессуары 42 1
Обработка пропущенных значений
Довольно часто в данных встречаются пропущенные значения, особенно это характерно для дневного количества посетителей в розничном магазине. Рассмотрим работу с пропущенными значениями на конкретном примере. Загружаем датафрейм и смотрим его содержание и структуру
shop <- read_excel("ShopDay2019.xlsx")
head(shop)
# A tibble: 6 x 6
ds month wday wh visit visit_na
<dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-01-01 00:00:00 1 2 1 159 159
2 2019-01-02 00:00:00 1 3 1 677 677
3 2019-01-03 00:00:00 1 4 1 643 643
4 2019-01-04 00:00:00 1 5 1 614 614
5 2019-01-05 00:00:00 1 6 1 561 561
6 2019-01-06 00:00:00 1 7 1 558 558
str(shop)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 365 obs. of 6 variables:
$ ds : POSIXct, format: "2019-01-01" "2019-01-02" "2019-01-03" ...
$ month : num 1 1 1 1 1 1 1 1 1 1 ...
$ wday : num 2 3 4 5 6 7 1 2 3 4 ...
$ wh : num 1 1 1 1 1 1 1 1 0 0 ...
$ visit : num 159 677 643 614 561 558 497 462 231 241 ...
$ visit_na: num 159 677 643 614 561 558 497 462 231 241 ...
Перед нами данные о дневной посещаемости магазина одежды :
ds - дата
month - месяц
wday - день недели
wh - рабочий день - 0 , выходной - 1
visit - дневное количество посетителей изначальное
visit_na - дневное количество посетителей с искусственно сделанными пропусками
Проверим, есть ли в датафрейме пропущенные значения
sum(is.na(shop))
[1] 16
round(mape_na,3)
[1] 0.051 0.047
При замене на среднее значение ошибка составила 5.1%, при замене на медианное значение ошибка получилась 4.7%, то есть можно сделать вывод о предпочтительности медианного значения, как менее зависимого от возможных выбросов.
Длинный и широкий формат данных
Одни и те же данные могут быть представлены в широком или длинном формате. Широкий формат - каждая строка содержит информацию о нескольких наблюдениях. Длинный формат - каждая строка содержит информацию о единственном наблюдении. Широкий формат удобнее для чтения и презентации данных в табличном виде, но сложнее для обработки. Длинный формат не удобен для чтения, но значительно удобнее для обработки и визуализации.
Рассмотрим конкретный пример - дневные продажи в розничном магазине одежды
shop_wide <- read_excel("ShopSaleWide.xlsx")
head(shop_wide)
# A tibble: 6 x 11
Дата Пол Аксессуары Брюки Куртка Платье Рубашка Толстовка Футболка Шорты Юбка
<dttm> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-06-01 Женский 3 3 NA 3 5 1 6 5 1
2 2019-06-01 Мужской 4 12 2 NA 3 NA 11 5 NA
3 2019-06-01 Унисекс 1 NA NA NA NA NA NA NA NA
4 2019-06-02 Женский 3 1 1 1 NA 1 10 NA NA
5 2019-06-02 Мужской 7 10 2 NA 10 2 10 4 NA
6 2019-06-02 Унисекс 2 NA NA NA NA NA NA NA NA
shop_long <- shop_wide %>%
pivot_longer(cols = `Аксессуары`:`Юбка`,
names_to = "Категория",
values_to = "Продажи",
values_drop_na = TRUE)
head(shop_long)
shop <- read_excel("ShopDay2019.xlsx")
head(shop)
# A tibble: 6 x 6
ds month wday wh visit visit_na
<dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-01-01 00:00:00 1 2 1 159 159
2 2019-01-02 00:00:00 1 3 1 677 677
3 2019-01-03 00:00:00 1 4 1 643 643
4 2019-01-04 00:00:00 1 5 1 614 614
5 2019-01-05 00:00:00 1 6 1 561 561
6 2019-01-06 00:00:00 1 7 1 558 558
str(shop)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 365 obs. of 6 variables:
$ ds : POSIXct, format: "2019-01-01" "2019-01-02" "2019-01-03" ...
$ month : num 1 1 1 1 1 1 1 1 1 1 ...
$ wday : num 2 3 4 5 6 7 1 2 3 4 ...
$ wh : num 1 1 1 1 1 1 1 1 0 0 ...
$ visit : num 159 677 643 614 561 558 497 462 231 241 ...
$ visit_na: num 159 677 643 614 561 558 497 462 231 241 ...
Перед нами данные о дневной посещаемости магазина одежды :
ds - дата
month - месяц
wday - день недели
wh - рабочий день - 0 , выходной - 1
visit - дневное количество посетителей изначальное
visit_na - дневное количество посетителей с искусственно сделанными пропусками
Проверим, есть ли в датафрейме пропущенные значения
sum(is.na(shop))
[1] 16
В какой колонке они находятся
colSums(is.na(shop))
ds month wday wh visit visit_na
0 0 0 0 0 16
С помощью функций из пакетов VIM и Amelia можно визуализировать присутствие пропущенных значений
library(VIM)
aggr(shop, numbers=TRUE)
library(Amelia)
missmap(shop)
Получилась очень эффектная и понятная демонстрация. Дальше существует два варианта действий, либо удалить дни с пропущенными значениями, что крайне нежелательно, либо заменить некоторым значением, например средним или медианным значениями посещаемости в данном месяце в зависимости от дня недели, мы будем рассматривать деление на выходные или рабочие дни. Для начала сохраним вектор индексов строк с пропущенными значениями :
shop_na <- is.na(shop$visit_na)
shop[shop_na,]
# A tibble: 16 x 6
ds month wday wh visit visit_na
<dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-01-20 00:00:00 1 7 1 556 NA
2 2019-02-20 00:00:00 2 3 0 135 NA
3 2019-03-05 00:00:00 3 2 0 179 NA
4 2019-03-23 00:00:00 3 6 1 423 NA
5 2019-04-06 00:00:00 4 6 1 408 NA
6 2019-05-24 00:00:00 5 5 0 199 NA
7 2019-06-07 00:00:00 6 5 0 211 NA
8 2019-06-09 00:00:00 6 7 1 349 NA
9 2019-07-05 00:00:00 7 5 0 217 NA
10 2019-08-28 00:00:00 8 3 0 229 NA
11 2019-09-20 00:00:00 9 5 0 238 NA
12 2019-10-25 00:00:00 10 5 0 275 NA
13 2019-11-07 00:00:00 11 4 0 249 NA
14 2019-11-23 00:00:00 11 6 1 627 NA
15 2019-11-28 00:00:00 11 4 0 248 NA
16 2019-12-17 00:00:00 12 2 0 222 NA
Создадим датафрейм со средними и медианными значениями посетителей по месяцам и рабочим и выходным дням
visit_wh <- shop %>%
group_by(month,wh) %>%
summarise(avg_visit = mean(visit_na,na.rm=T),
med_visit = median(visit_na,na.rm=T))
group_by(month,wh) %>%
summarise(avg_visit = mean(visit_na,na.rm=T),
med_visit = median(visit_na,na.rm=T))
visit_wh
# A tibble: 24 x 4
# Groups: month [12]
month wh avg_visit med_visit
<dbl> <dbl> <dbl> <dbl>
1 1 0 237. 231
2 1 1 536. 559
3 2 0 140. 136
4 2 1 328. 328.
5 3 0 181. 179
6 3 1 424. 432.
7 4 0 173. 172
8 4 1 415. 421
9 5 0 177. 177
10 5 1 381. 419
# ... with 14 more rows
# Groups: month [12]
month wh avg_visit med_visit
<dbl> <dbl> <dbl> <dbl>
1 1 0 237. 231
2 1 1 536. 559
3 2 0 140. 136
4 2 1 328. 328.
5 3 0 181. 179
6 3 1 424. 432.
7 4 0 173. 172
8 4 1 415. 421
9 5 0 177. 177
10 5 1 381. 419
# ... with 14 more rows
Добавим в наш датафрейм две колонки, в которых вместо пропущенных значений будут средние и медианные значения
shop$visit_na_mean <- shop$visit_na
shop$visit_na_median <- shop$visit_na
shop[shop_na,c(1,6:8)]
# A tibble: 16 x 5
ds visit visit_na visit_na_mean visit_na_median
<dttm> <dbl> <dbl> <dbl> <dbl>
1 2019-01-20 00:00:00 556 NA NA NA
2 2019-02-20 00:00:00 135 NA NA NA
3 2019-03-05 00:00:00 179 NA NA NA
4 2019-03-23 00:00:00 423 NA NA NA
5 2019-04-06 00:00:00 408 NA NA NA
6 2019-05-24 00:00:00 199 NA NA NA
7 2019-06-07 00:00:00 211 NA NA NA
8 2019-06-09 00:00:00 349 NA NA NA
9 2019-07-05 00:00:00 217 NA NA NA
10 2019-08-28 00:00:00 229 NA NA NA
11 2019-09-20 00:00:00 238 NA NA NA
12 2019-10-25 00:00:00 275 NA NA NA
13 2019-11-07 00:00:00 249 NA NA NA
14 2019-11-23 00:00:00 627 NA NA NA
15 2019-11-28 00:00:00 248 NA NA NA
16 2019-12-17 00:00:00 222 NA NA NA
И с помощью вложенного цикла заменим пропущенные значения
for(i in which(is.na(shop$visit_na))){
Посмотрим на результат замены
for(j in 1:nrow(visit_wh)){
if(shop$month[i]==visit_wh$month[j] &
shop$wh[i]==visit_wh$wh[j] ){
shop$visit_na_mean[i] <- visit_wh$avg_visit[j]
shop$visit_na_median[i] <- visit_wh$med_visit[j]
break
}
}
}
shop[shop_na,c(1,5:8)]
# A tibble: 16 x 5
ds visit visit_na visit_na_mean visit_na_median
<dttm> <dbl> <dbl> <dbl> <dbl>
1 2019-01-20 00:00:00 556 NA 536. 559
2 2019-02-20 00:00:00 135 NA 140. 136
3 2019-03-05 00:00:00 179 NA 181. 179
4 2019-03-23 00:00:00 423 NA 424. 432.
5 2019-04-06 00:00:00 408 NA 415. 421
6 2019-05-24 00:00:00 199 NA 177. 177
7 2019-06-07 00:00:00 211 NA 205. 206
8 2019-06-09 00:00:00 349 NA 348. 346
9 2019-07-05 00:00:00 217 NA 210. 212
10 2019-08-28 00:00:00 229 NA 229. 230
11 2019-09-20 00:00:00 238 NA 193. 187
12 2019-10-25 00:00:00 275 NA 224. 217
13 2019-11-07 00:00:00 249 NA 257. 242.
14 2019-11-23 00:00:00 627 NA 644. 637
15 2019-11-28 00:00:00 248 NA 257. 242.
16 2019-12-17 00:00:00 222 NA 235. 228
ds visit visit_na visit_na_mean visit_na_median
<dttm> <dbl> <dbl> <dbl> <dbl>
1 2019-01-20 00:00:00 556 NA 536. 559
2 2019-02-20 00:00:00 135 NA 140. 136
3 2019-03-05 00:00:00 179 NA 181. 179
4 2019-03-23 00:00:00 423 NA 424. 432.
5 2019-04-06 00:00:00 408 NA 415. 421
6 2019-05-24 00:00:00 199 NA 177. 177
7 2019-06-07 00:00:00 211 NA 205. 206
8 2019-06-09 00:00:00 349 NA 348. 346
9 2019-07-05 00:00:00 217 NA 210. 212
10 2019-08-28 00:00:00 229 NA 229. 230
11 2019-09-20 00:00:00 238 NA 193. 187
12 2019-10-25 00:00:00 275 NA 224. 217
13 2019-11-07 00:00:00 249 NA 257. 242.
14 2019-11-23 00:00:00 627 NA 644. 637
15 2019-11-28 00:00:00 248 NA 257. 242.
16 2019-12-17 00:00:00 222 NA 235. 228
Как видим, результат получился удовлетворительный, восстановленные значения довольно близки к фактическим. Оценим среднюю абсолютную ошибку в процентах MAPE при замене средним и медианой
mape_na <- c(mean(abs(shop[shop_na,]$visit - shop[shop_na,]$visit_na_mean) /
shop[shop_na,]$visit),
mean(abs(shop[shop_na,]$visit - shop[shop_na,]$visit_na_median) /
shop[shop_na,]$visit))
round(mape_na,3)
[1] 0.051 0.047
При замене на среднее значение ошибка составила 5.1%, при замене на медианное значение ошибка получилась 4.7%, то есть можно сделать вывод о предпочтительности медианного значения, как менее зависимого от возможных выбросов.
Длинный и широкий формат данных
Пакет tidyr есть две функции предназначенных для трансформации таблиц:
pivot_longer()
— функция, преобразующая данные из широкого формата в длинный; pivot_wider()
— функция, преобразующая данные из длинного формата в широкий. Операция обратная той, которую осуществляет функция pivot_longer()
.shop_wide <- read_excel("ShopSaleWide.xlsx")
head(shop_wide)
# A tibble: 6 x 11
Дата Пол Аксессуары Брюки Куртка Платье Рубашка Толстовка Футболка Шорты Юбка
<dttm> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-06-01 Женский 3 3 NA 3 5 1 6 5 1
2 2019-06-01 Мужской 4 12 2 NA 3 NA 11 5 NA
3 2019-06-01 Унисекс 1 NA NA NA NA NA NA NA NA
4 2019-06-02 Женский 3 1 1 1 NA 1 10 NA NA
5 2019-06-02 Мужской 7 10 2 NA 10 2 10 4 NA
6 2019-06-02 Унисекс 2 NA NA NA NA NA NA NA NA
Как видим, это типичный пример широких данных, в каждой строке находится несколько наблюдений. Преобразуем эту таблицу в длинный формат с помощью функции pivot_longer
pivot_longer(cols = `Аксессуары`:`Юбка`,
names_to = "Категория",
values_to = "Продажи",
values_drop_na = TRUE)
head(shop_long)
# A tibble: 6 x 4
Дата Пол Категория Продажи
<dttm> <chr> <chr> <dbl>
1 2019-06-01 Женский Аксессуары 3
2 2019-06-01 Женский Брюки 3
3 2019-06-01 Женский Платье 3
4 2019-06-01 Женский Рубашка 5
5 2019-06-01 Женский Толстовка 1
6 2019-06-01 Женский Футболка 6
Дата Пол Категория Продажи
<dttm> <chr> <chr> <dbl>
1 2019-06-01 Женский Аксессуары 3
2 2019-06-01 Женский Брюки 3
3 2019-06-01 Женский Платье 3
4 2019-06-01 Женский Рубашка 5
5 2019-06-01 Женский Толстовка 1
6 2019-06-01 Женский Футболка 6
Аргументы функции
pivot_longer()
- Первый аргумент cols, описывает, какие столбцы необходимо объединить.
- Аргумент names_to дает имя переменной, которая будет создана из имён столбцов, которые мы объединили.
- values_to дает имя переменной, которая будет создана из данных, хранящихся в значениях ячеек объединённых столбцов.
- values_drop_na убирает строки с пропущенными значениями
Теперь вернем данные к исходному состоянию с помощью функции pivot_wider
shop_wide_new <- shop_long %>%
pivot_wider(id_cols = c(Дата,Пол, Категория),
names_from = Категория,
values_from = Продажи,
values_fill = list(Продажи = 0))
# A tibble: 6 x 11
Дата Пол Аксессуары Брюки Платье Рубашка Толстовка Футболка Шорты Юбка Куртка
<dttm> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-06-01 Женский 3 3 3 5 1 6 5 1 0
2 2019-06-01 Мужской 4 12 0 3 0 11 5 0 2
3 2019-06-01 Унисекс 1 0 0 0 0 0 0 0 0
4 2019-06-02 Женский 3 1 1 0 1 10 0 0 1
5 2019-06-02 Мужской 7 10 0 10 2 10 4 0 2
6 2019-06-02 Унисекс 2 0 0 0 0 0 0 0 0
pivot_wider(id_cols = c(Дата,Пол, Категория),
names_from = Категория,
values_from = Продажи,
values_fill = list(Продажи = 0))
# A tibble: 6 x 11
Дата Пол Аксессуары Брюки Платье Рубашка Толстовка Футболка Шорты Юбка Куртка
<dttm> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2019-06-01 Женский 3 3 3 5 1 6 5 1 0
2 2019-06-01 Мужской 4 12 0 3 0 11 5 0 2
3 2019-06-01 Унисекс 1 0 0 0 0 0 0 0 0
4 2019-06-02 Женский 3 1 1 0 1 10 0 0 1
5 2019-06-02 Мужской 7 10 0 10 2 10 4 0 2
6 2019-06-02 Унисекс 2 0 0 0 0 0 0 0 0
Аргументы функции pivot_wider()
- Первый аргумент id_cols, задает, какие столбцы не будут изменяться
- Аргумент names_from дает имя переменной, из которой будут получены названия новых столбцов
- values_from дает имя переменной, из которой будут получены значения для новых столбцов
- values_fill заменяет пропущенные значения на заданные значения, в данном случае на ноль
Комментариев нет:
Отправить комментарий