Статьи

R: Снятие даты выхода проектов GitHub

Продолжая рассказ моего блога о смещении дат выпуска Neo4j, я подумал, что было бы еще интереснее составить график дат выпуска некоторых проектов github.

Теоретически даты выпуска должны быть доступны через github API, но те немногие, на которые я смотрел, не возвращали никаких данных, поэтому я собрал их вместе.

Мы снова будем использовать rvest, и я сначала написал следующую функцию для извлечения версий и дат выпуска с одной страницы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
library(dplyr)
library(rvest)
  
process_page = function(releases, session) {
  rows = session %>% html_nodes("ul.release-timeline-tags li")
  
  for(row in rows) {
    date = row %>% html_node("span.date")
    version = row %>% html_node("div.tag-info a")
  
    if(!is.null(version) && !is.null(date)) {
      date = date %>% html_text() %>% str_trim()
      version = version %>% html_text() %>% str_trim()
      releases = rbind(releases, data.frame(date = date, version = version))
    
  }
  return(releases)
}

Давайте попробуем это на странице релиза Cassandra и посмотрим, к чему это приведет:

01
02
03
04
05
06
07
08
09
10
11
12
13
> r = process_page(data.frame(), html_session("https://github.com/apache/cassandra/releases"))
> r
           date               version
1  Jun 22, 2015       cassandra-2.1.7
2  Jun 22, 2015      cassandra-2.0.16
3   Jun 8, 2015       cassandra-2.1.6
4   Jun 8, 2015   cassandra-2.2.0-rc1
5  May 19, 2015 cassandra-2.2.0-beta1
6  May 18, 2015      cassandra-2.0.15
7  Apr 29, 2015       cassandra-2.1.5
8   Apr 1, 2015      cassandra-2.0.14
9   Apr 1, 2015       cassandra-2.1.4
10 Mar 16, 2015      cassandra-2.0.13

Это работает довольно хорошо, но это только одна страница! Чтобы получить все страницы, мы можем использовать функцию follow_link для перехода по ссылке «Далее», пока не останется страниц для обработки.

Для этого мы получим следующую функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
find_all_releases = function(starting_page) {
  s = html_session(starting_page)
  releases = data.frame()
  
  next_page = TRUE
  while(next_page) {
    possibleError = tryCatch({ 
      releases = process_page(releases, s)
      s = s %>% follow_link("Next")
    }, error = function(e) { e })
  
    if(inherits(possibleError, "error")){
      next_page = FALSE
    }
  }
  return(releases)
}

Давайте попробуем это, начиная со страницы Кассандры:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
> cassandra = find_all_releases("https://github.com/apache/cassandra/releases")
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-2.0.13
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-2.0.10
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-2.0.8
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-1.2.13
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-2.0.0-rc1
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-1.2.3
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-1.2.0-beta2
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-1.0.10
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-1.0.6
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-1.0.0-rc2
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-0.7.7
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-0.7.4
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-0.7.0-rc3
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-0.6.4
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-0.5.0-rc3
Navigating to https://github.com/apache/cassandra/releases?after=cassandra-0.4.0-final
  
> cassandra %>% sample_n(10)
            date               version
151 Mar 13, 2010   cassandra-0.5.0-rc2
25   Jul 3, 2014      cassandra-1.2.18
51  Jul 27, 2013       cassandra-1.2.8
21  Aug 19, 2014   cassandra-2.1.0-rc6
73  Sep 24, 2012 cassandra-1.2.0-beta1
158 Mar 13, 2010   cassandra-0.4.0-rc2
113 May 20, 2011     cassandra-0.7.6-2
15  Oct 24, 2014       cassandra-2.1.1
103 Sep 15, 2011 cassandra-1.0.0-beta1
93  Nov 29, 2011       cassandra-1.0.4

Я хочу построить график, когда разные выпуски произошли вовремя, и для этого нам нужно создать дополнительный столбец, содержащий «серию выпусков», которую мы можем сделать с помощью следующего преобразования:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
series = function(version) {
  parts = strsplit(as.character(version), "\\."
  return(unlist(lapply(parts, function(p) paste(p %>% unlist %>% head(2), collapse = ".")))) 
}
  
bySeries = cassandra %>%
  mutate(date2 = mdy(date), series = series(version),
         short_version = gsub("cassandra-", "", version),
         short_series = series(short_version))
  
> bySeries %>% sample_n(10)
            date               version      date2        series short_version short_series
3    Jun 8, 2015       cassandra-2.1.6 2015-06-08 cassandra-2.1         2.1.6          2.1
161 Mar 13, 2010 cassandra-0.4.0-beta1 2010-03-13 cassandra-0.4   0.4.0-beta1          0.4
62  Feb 15, 2013      cassandra-1.1.10 2013-02-15 cassandra-1.1        1.1.10          1.1
153 Mar 13, 2010 cassandra-0.5.0-beta2 2010-03-13 cassandra-0.5   0.5.0-beta2          0.5
37   Feb 7, 2014       cassandra-2.0.5 2014-02-07 cassandra-2.0         2.0.5          2.0
36   Feb 7, 2014      cassandra-1.2.15 2014-02-07 cassandra-1.2        1.2.15          1.2
29   Jun 2, 2014   cassandra-2.1.0-rc1 2014-06-02 cassandra-2.1     2.1.0-rc1          2.1
21  Aug 19, 2014   cassandra-2.1.0-rc6 2014-08-19 cassandra-2.1     2.1.0-rc6          2.1
123 Feb 16, 2011       cassandra-0.7.2 2011-02-16 cassandra-0.7         0.7.2          0.7
135  Nov 1, 2010 cassandra-0.7.0-beta3 2010-11-01 cassandra-0.7   0.7.0-beta3          0.7

Теперь давайте подготовим эти выпуски и посмотрим, что мы получим:

1
2
3
4
ggplot(aes(x = date2, y = short_series),
       data = bySeries %>% filter(!grepl("beta|rc", short_version))) +    
  geom_text(aes(label=short_version),hjust=0.5, vjust=0.5, size = 4, angle = 90) +
  theme_bw()

2015-06-23_22-59-19

Интересная вещь, которую мы можем видеть из этой визуализации, — это то, что перекрывают различные серии версий. В большинстве случаев перекрываются только две серии версий, но серии 1.2, 2.0 и 2.1 перекрываются, что необычно.

В этом графике мы исключили все бета и RC версии. Давайте вернем их и покажем последние 3 версии:

1
2
3
4
ggplot(aes(x = date2, y = short_series),
       data = bySeries %>% filter(grepl("2\\.[012]\\.|1\\.2\\.", short_version))) +    
  geom_text(aes(label=short_version),hjust=0.5, vjust=0.5, size = 4, angle = 90) +
  theme_bw()

2015-06-23_23-08-04

Из этого графика ясно, что серии 2.0 и 2.1 имеют недавние выпуски, поэтому, вероятно, будут также три перекрывающиеся версии, когда будут выпущены серии 2.2.

График все еще немного загроможден, хотя и меньше, чем раньше. Я не уверен в лучшем способе визуализации данных этого типа, поэтому, если у вас есть какие-либо идеи, дайте мне знать!

Ссылка: R: Уточнение дат выпуска проектов github от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма .