Мы с вами пытаемся комплексно на протяжении нескольких праздничных недель вырабатывать плоскую социологическую попу и растущие не из неё ручки в процессе применения всех наших навыков (обработки данных в dplyr, рисования, статистических тестов и регрессий и т.д.) к тестовой задачке с более чем одной табличкой и более чем парой строчек задания. //ИЛМ
Внимание! Задание нельзя сделать за день перед сдачей на положительную оценку. Мы рассчитываем, в итоге, на 12 часов работы над ним в течение 2,5 недель минимум.
Этот дейтасет эмулирует реальную работу службы поддержки пользователей игровой компании. Наша задача, как приличных Data Engineers, за несколько итераций использовать наши знания в вытаскивании из сырого массива данных осмысленной информации и представить результаты так, чтобы заказчику, который хочет понять насколько эффективно работает его саппорт – насколько довольны его пользователи, стало ну сразу всё понятно.
Зоны работы, на которые нужно обратить внимание:
Сегодняшняя лабораторная знакомит вас с набором данных и заданием + вы можете успеть обсудить и начать применять интересные вам методы визуализации (и статистические тесты).
В результате первой недели работы отчёт должен содержать пункты Визуализация, Агрегация, Тесты. Если вам хочется влезть дальше, скорее всего, вы недостаточно детально подошли к этим пунктам. При активной работе на лабораторной и задавании вопросов, у вас должно уйти 3-4 часа на эту часть.
В результате второй недели работы мы ждем начала/продолжения статистических тестов/регрессии, работы со временем, (начала работы с тегами). Хорошим результатом 2 недели является переработка того, что что вы сделали в первой. 4-5 часов.
Третья неделя работы – Тэги, (Data Mining), финализация отчёта. 3-5 часов.
Пытайтесь оформлять код внятно, понятно для вас, мы будем его использовать дальше. Например, основные функции могут быть вынесены в script.R и вызываться из rmd-отчета с помощью source("script.R").
Задавайте вопросы. ЗАДАВАЙТЕ, пылесосить вышего бегемотика, ВОПРОСЫ.
Промежуточная сдача результатов составляет вашу текущую оценку за модуль (точнее, 3/4 от неё). Опоздание со сдачей этапа более чем на сутки – “0” за него. В него включаем и то, что мы пробовали, но исключили из окончательной версии – графики, подходы, модельки, не давшие результатов.
Финальный отчёт составляет 3/4 от оценки по контрольной работе за модуль. В нём будет оцениваться итоговый результат и прогресс между этапами (переделка итогового продукта). Это – то что вы показываете заказчику (которому нужен результат, а не стенания по поводу “мы делали до 12 часов”), сюда не включается отбраковка (но, в отличие от заказчика, мы её оцениваем по промежуточным отчётикам).
Мы просим каждого из вас воспринимать это не как казнь египетскую, а как возможность повторить, уточнить, выучить, систематизировать и показать персональный максимум после года прокрастинации, отговорок, самозащитных “ну да, я лох, что с меня взять”.
require(plyr)
## Loading required package: plyr
require(dplyr)
## Loading required package: dplyr
##
## Attaching package: 'dplyr'
##
## The following objects are masked from 'package:plyr':
##
## arrange, count, desc, failwith, id, mutate, rename, summarise,
## summarize
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
require(ggplot2)
## Loading required package: ggplot2
require(stringr)
## Loading required package: stringr
library(DT) #http://rstudio.github.io/DT/
db <- src_sqlite("/principal/materials/digitalmethods/player-support-data.sqlite3")
# TICKETS
tickets <- collect(tbl(db, "tickets"))
tickets$agent <- as.factor(tickets$agent)
tickets$game <- as.factor(tickets$game)
tickets$created_time <- as.POSIXct(strptime(tickets$created_time, format="%Y-%m-%d %H:%M:%S", tz = ""))
summary(tickets)
## ticket_id agent game
## Min. : 28 Jane : 305 Boom Beach :1294
## 1st Qu.:23988 Lucy : 301 Clash of Clans:1269
## Median :50371 Susan : 300 Hay Day :1271
## Mean :49833 Lisa : 299 NA's : 426
## 3rd Qu.:74926 Peter : 299
## Max. :99966 (Other):2573
## NA's : 183
## created_time
## Min. :2015-01-01 00:00:05
## 1st Qu.:2015-01-04 14:53:43
## Median :2015-01-07 22:12:48
## Mean :2015-01-07 23:38:43
## 3rd Qu.:2015-01-11 09:41:28
## Max. :2015-01-14 23:51:07
##
datatable(tickets, options = list(iDisplayLength = 5)) #http://rstudio.github.io/DT/
# TAGS
tags <- collect(tbl(db, "tags"))
tags$tag_type <- ifelse(str_detect(tags$tag, "[A-Z]{2}"), "lang", "desc")
lang_tags <- filter(tags, tag_type=='lang')
desc_tags <- filter(tags, tag_type=="desc")
summary(tags)
## ticket_id tag tag_type
## Min. : 28 Length:6578 Length:6578
## 1st Qu.:23580 Class :character Class :character
## Median :49304 Mode :character Mode :character
## Mean :49502
## 3rd Qu.:74607
## Max. :99966
datatable(tags, options = list(iDisplayLength = 5))
# AUDITS
audits <- collect(tbl(db, "audits"))
audits$updated_time <- as.POSIXct(strptime(audits$updated_time, format="%Y-%m-%d %H:%M:%S", tz = ""))
summary(audits)
## ticket_id status previous_status
## Min. : 28 Length:5269 Length:5269
## 1st Qu.:23980 Class :character Class :character
## Median :49938 Mode :character Mode :character
## Mean :49651
## 3rd Qu.:74820
## Max. :99966
## updated_time
## Min. :2015-01-01 02:44:59
## 1st Qu.:2015-01-05 13:53:32
## Median :2015-01-08 19:22:15
## Mean :2015-01-08 17:38:55
## 3rd Qu.:2015-01-11 23:32:11
## Max. :2015-01-14 23:58:44
datatable(audits, options = list(iDisplayLength = 5))
# inner_join
# return all rows from x where there are matching values in y, and all columns from x and y. If there are multiple matches between x and y, all combination of the matches are returned.
tickets_with_tags <- inner_join(tickets, tags, by="ticket_id")
# left_join
# return all rows from x, and all columns from x and y. Rows in x with no match in y will have NA values in the new columns. If there are multiple matches between x and y, all combinations of the matches are returned.
tickets_and_their_tags <- left_join(tickets, tags, by="ticket_id")
twt_sum <- tickets_with_tags %>%
group_by(tag_type, agent) %>%
summarise(tags_count=n())
ggplot(twt_sum) + geom_boxplot(aes(x=tag_type, y=tags_count))
tat_sum <- tickets_and_their_tags %>%
group_by(tag_type, agent) %>%
summarise(tags_count=n())
ggplot(tat_sum) + geom_boxplot(aes(x=tag_type, y=tags_count))
ru_games <- tickets_with_tags %>%
filter(created_time>='2015-01-01', created_time<'2015-01-08') %>%
filter(tag=="RU") %>%
group_by(agent, game) %>%
summarise(tickets_count=n())
ggplot(ru_games) + geom_boxplot(aes(x=game, y=tickets_count))
ru_games_for_test <- ru_games %>% filter(game %in% c("Clash of Clans", "Hay Day"))
ru_games_for_test$game <- factor(as.character(ru_games_for_test$game))
t.test(tickets_count ~ game, data= ru_games_for_test)
##
## Welch Two Sample t-test
##
## data: tickets_count by game
## t = 0.3873, df = 25.801, p-value = 0.7017
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.8177019 1.1971890
## sample estimates:
## mean in group Clash of Clans mean in group Hay Day
## 2.923077 2.733333
ggplot(tickets) +
geom_bar(aes(x=created_time, fill=game)) +
scale_fill_brewer(palette = "Accent")
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
ggplot(tickets) +
geom_bar(aes(x=created_time, fill=agent)) +
scale_fill_brewer(palette = "Paired")
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Paired is 12
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Paired is 12
## Returning the palette you asked for with that many colors
ggplot(tickets) +
geom_bar(aes(x=agent, fill=game)) +
scale_fill_brewer(palette = "Accent")
ggplot(audits) +
geom_bar(aes(x=updated_time, fill=status)) +
scale_fill_brewer(palette = "Set1")
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
ggplot(audits) +
geom_bar(aes(x=status, fill=previous_status)) +
scale_fill_brewer(palette = "Set1")