Недавно я наткнулся на отличную статью, написанную Стианом Хаклевым, в которой он описывает то, что ему хотелось бы, чтобы ему сказали, прежде чем начинать с R , одна из которых заключается в том, чтобы очистить все данные в коде, который я решил попробовать.
Моя цель — оставить необработанные данные полностью неизменными и выполнить все преобразования в коде, которые можно запустить в любой момент.
Пока я пишу сценарии, я часто прыгаю, выборочно выполняя отдельные строки или блоки кода, выполняя команды для проверки данных в REPL (чтение-оценка-печать-цикл, где каждая команда выполняется, как только вы введите enter, на картинке выше это панель справа) и т. д.
Но я стараюсь убедиться, что когда я закончу, скрипт сам по себе будет работать.
Я подумал, что с набором данных Google Trends будет интересно поэкспериментировать, так как он дает вам CSV, содержащий несколько разных фрагментов данных, которые меня интересуют только с течением времени.
Не очень легко автоматизировать загрузку CSV-файла, поэтому я сделал это вручную и автоматизировал все с этого момента.
Первым шагом было чтение файла CSV и изучение некоторых строк, чтобы увидеть, что в нем содержится:
> library(dplyr)
> googleTrends = read.csv("/Users/markneedham/Downloads/report.csv", row.names=NULL)
> googleTrends %>% head()
## row.names Web.Search.interest..neo4j
## 1 Worldwide; 2004 - present
## 2 Interest over time
## 3 Week neo4j
## 4 2004-01-04 - 2004-01-10 0
## 5 2004-01-11 - 2004-01-17 0
## 6 2004-01-18 - 2004-01-24 0
> googleTrends %>% sample_n(10)
## row.names Web.Search.interest..neo4j
## 109 2006-01-08 - 2006-01-14 0
## 113 2006-02-05 - 2006-02-11 0
## 267 2009-01-18 - 2009-01-24 0
## 199 2007-09-30 - 2007-10-06 0
## 522 2013-12-08 - 2013-12-14 88
## 265 2009-01-04 - 2009-01-10 0
## 285 2009-05-24 - 2009-05-30 0
## 318 2010-01-10 - 2010-01-16 0
## 495 2013-06-02 - 2013-06-08 79
## 28 2004-06-20 - 2004-06-26 0
> googleTrends %>% tail()
## row.names Web.Search.interest..neo4j
## 658 neo4j example Breakout
## 659 neo4j graph database Breakout
## 660 neo4j java Breakout
## 661 neo4j node Breakout
## 662 neo4j rest Breakout
## 663 neo4j tutorial Breakout
Мы хотим сохранить только те строки, которые содержат (неделя, проценты) пары, поэтому первое, что мы сделаем, это переименуем столбцы:
names(googleTrends) = c("week", "score")
Теперь мы хотим удалить строки, которые не содержат пар (неделя, процент). Самый простой способ сделать это — найти строки, которые не содержат значений даты в столбце «неделя».
Сначала нам нужно разделить даты начала и окончания в этом столбце с помощью функции strsplit .
Я обнаружил, что гораздо проще применить функцию к каждой строке отдельно, чем передавать список значений, поэтому я создал фиктивный столбец с номером строки, чтобы я мог это сделать (уловка, которую показал мне Антониос ):
> googleTrends %>%
mutate(ind = row_number()) %>%
group_by(ind) %>%
mutate(dates = strsplit(week, " - "),
start = dates[[1]][1] %>% strptime("%Y-%m-%d") %>% as.character(),
end = dates[[1]][2] %>% strptime("%Y-%m-%d") %>% as.character()) %>%
head()
## Source: local data frame [6 x 6]
## Groups: ind
##
## week score ind dates start end
## 1 Worldwide; 2004 - present 1 1 <chr[2]> NA NA
## 2 Interest over time 1 2 <chr[1]> NA NA
## 3 Week 90 3 <chr[1]> NA NA
## 4 2004-01-04 - 2004-01-10 3 4 <chr[2]> 2004-01-04 2004-01-10
## 5 2004-01-11 - 2004-01-17 3 5 <chr[2]> 2004-01-11 2004-01-17
## 6 2004-01-18 - 2004-01-24 3 6 <chr[2]> 2004-01-18 2004-01-24
Теперь нам нужно избавиться от строк, которые имеют значение NA для «start» или «end»:
> googleTrends %>%
mutate(ind = row_number()) %>%
group_by(ind) %>%
mutate(dates = strsplit(week, " - "),
start = dates[[1]][1] %>% strptime("%Y-%m-%d") %>% as.character(),
end = dates[[1]][2] %>% strptime("%Y-%m-%d") %>% as.character()) %>%
filter(!is.na(start) | !is.na(end)) %>%
head()
## Source: local data frame [6 x 6]
## Groups: ind
##
## week score ind dates start end
## 1 2004-01-04 - 2004-01-10 3 4 <chr[2]> 2004-01-04 2004-01-10
## 2 2004-01-11 - 2004-01-17 3 5 <chr[2]> 2004-01-11 2004-01-17
## 3 2004-01-18 - 2004-01-24 3 6 <chr[2]> 2004-01-18 2004-01-24
## 4 2004-01-25 - 2004-01-31 3 7 <chr[2]> 2004-01-25 2004-01-31
## 5 2004-02-01 - 2004-02-07 3 8 <chr[2]> 2004-02-01 2004-02-07
## 6 2004-02-08 - 2004-02-14 3 9 <chr[2]> 2004-02-08 2004-02-14
Далее мы избавимся от «недели», «инд» и «даты», так как они нам больше не понадобятся:
> cleanGoogleTrends = googleTrends %>%
mutate(ind = row_number()) %>%
group_by(ind) %>%
mutate(dates = strsplit(week, " - "),
start = dates[[1]][1] %>% strptime("%Y-%m-%d") %>% as.character(),
end = dates[[1]][2] %>% strptime("%Y-%m-%d") %>% as.character()) %>%
filter(!is.na(start) | !is.na(end)) %>%
ungroup() %>%
select(-c(ind, dates, week))
> cleanGoogleTrends %>% head()
## Source: local data frame [6 x 3]
##
## score start end
## 1 3 2004-01-04 2004-01-10
## 2 3 2004-01-11 2004-01-17
## 3 3 2004-01-18 2004-01-24
## 4 3 2004-01-25 2004-01-31
## 5 3 2004-02-01 2004-02-07
## 6 3 2004-02-08 2004-02-14
> cleanGoogleTrends %>% sample_n(10)
## Source: local data frame [10 x 3]
##
## score start end
## 1 8 2010-09-26 2010-10-02
## 2 73 2013-11-17 2013-11-23
## 3 52 2012-07-01 2012-07-07
## 4 3 2005-06-19 2005-06-25
## 5 3 2004-12-12 2004-12-18
## 6 3 2009-09-06 2009-09-12
## 7 71 2014-09-14 2014-09-20
## 8 3 2004-12-26 2005-01-01
## 9 62 2013-03-03 2013-03-09
## 10 3 2006-03-19 2006-03-25
> cleanGoogleTrends %>% tail()
## Source: local data frame [6 x 3]
##
## score start end
## 1 80 2014-10-19 2014-10-25
## 2 80 2014-10-26 2014-11-01
## 3 84 2014-11-02 2014-11-08
## 4 81 2014-11-09 2014-11-15
## 5 83 2014-11-16 2014-11-22
## 6 2 2014-11-23 2014-11-29
Хорошо, теперь мы готовы к сюжету. Это была моя первая попытка:
> library(ggplot2)
> ggplot(aes(x = start, y = score), data = cleanGoogleTrends) +
geom_line(size = 0.5)
## geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?
Как видите, не слишком удачно! Первая ошибка, которую я сделал, не говорит ggplot, что столбец ‘start’ является датой, и поэтому он может использовать этот порядок при построении графика:
> cleanGoogleTrends = cleanGoogleTrends %>% mutate(start = as.Date(start))
> ggplot(aes(x = start, y = score), data = cleanGoogleTrends) +
geom_line(size = 0.5)
Моя следующая ошибка заключается в том, что «оценка» не рассматривается как непрерывная переменная, и поэтому мы получаем очень странную диаграмму. Мы можем видеть это, если мы вызываем функцию класса :
> class(cleanGoogleTrends$score) ## [1] "factor"
Давайте исправим это и построим график снова:
> cleanGoogleTrends = cleanGoogleTrends %>% mutate(score = as.numeric(score))
> ggplot(aes(x = start, y = score), data = cleanGoogleTrends) +
geom_line(size = 0.5)
Это намного лучше, но в баллах по неделям довольно много шума, который мы можем немного сгладить, построив вместо этого скользящее среднее за последние 4 недели :
> library(zoo)
> cleanGoogleTrends = cleanGoogleTrends %>%
mutate(rolling = rollmean(score, 4, fill = NA, align=c("right")),
start = as.Date(start))
> ggplot(aes(x = start, y = rolling), data = cleanGoogleTrends) +
geom_line(size = 0.5)
Вот полный код, если вы хотите воспроизвести:
library(dplyr)
library(zoo)
library(ggplot2)
googleTrends = read.csv("/Users/markneedham/Downloads/report.csv", row.names=NULL)
names(googleTrends) = c("week", "score")
cleanGoogleTrends = googleTrends %>%
mutate(ind = row_number()) %>%
group_by(ind) %>%
mutate(dates = strsplit(week, " - "),
start = dates[[1]][1] %>% strptime("%Y-%m-%d") %>% as.character(),
end = dates[[1]][2] %>% strptime("%Y-%m-%d") %>% as.character()) %>%
filter(!is.na(start) | !is.na(end)) %>%
ungroup() %>%
select(-c(ind, dates, week)) %>%
mutate(start = as.Date(start),
score = as.numeric(score),
rolling = rollmean(score, 4, fill = NA, align=c("right")))
ggplot(aes(x = start, y = rolling), data = cleanGoogleTrends) +
geom_line(size = 0.5)
Мой следующий шаг — сопоставить оценки Google Trends с моим набором данных о встречах, чтобы увидеть, есть ли какие-нибудь интересные корреляции.
Кроме того, я использовал knitr при составлении этого поста — он отлично работает для проверки того, что вы включили все шаги и что он действительно работает!


