<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/from-webscraping-data-to-releasing-it-as-an-r-package-to-share-with-the-world-a-full-tutorial-with-data-from-nethack/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.brodrigues.co/blog/2018-11-01-nethack/"> Econometrics and Free Software</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">If someone told me a decade ago (back before I'd ever heard the term &quot;roguelike&quot;) what I'd be doing today, I would have trouble believing this…</p>
<p>Yet here we are. <a rel="nofollow" href="https://t.co/N6Hh6A4tWl" target="_blank">pic.twitter.com/N6Hh6A4tWl</a></p>
<p>— Josh Ge (@GridSageGames) <a rel="nofollow" href="https://twitter.com/GridSageGames/status/1009664438683648001?ref_src=twsrc%5Etfw" target="_blank">June 21, 2018</a></p></blockquote>
<p></p>
<div>
<h2>Abstract</h2>
<p>In this post, I am going to show you how you can scrape tables from a website, and then create a package<br>
with the tidied data to share with the world. The data I am going to scrape comes from a NetHack<br>
public server (<a rel="nofollow" href="https://alt.org/nethack/" target="_blank">link</a>). The data I discuss in this blog post is<br>
available in the <code>{nethack}</code> package I created and I will walk you through the process of releasing<br>
your package on CRAN. However, <code>{nethack}</code> is too large to be on CRAN (75 mb, while the maximum<br>
allowed is 5mb), so you can install it to play around with the data from github:</p>
<pre><code>devtools::install_github(&quot;b-rodrigues/nethack&quot;)</code></pre>
<p>And to use it:</p>
<pre><code>library(nethack)
data(&quot;nethack&quot;)</code></pre>
<p>The data contains information on games played from 2001 to 2018; 322485 rows and 14 columns. I<br>
will analyze the data in a future blog post. This post focuses on getting and then sharing the<br>
data. By the way, all the content from the public server I scrape is under the CC BY 4.0 license.</p>
<p>I built the package by using the very useful <code>{devtools}</code> package.</p>
</div>
<div>
<h2>Introduction</h2>
<p>NetHack is a game released in 1987 that is still being played and developed today.<br>
NetHack is a roguelike game, meaning that is has procedurally generated dungeons and permadeath.<br>
If you die, you have to start over, and because the dungeons are procedurally generated, this means<br>
that you cannot learn the layout of the dungeons you explore or know when ennemies are going<br>
to attack or even what ennemies are going to attack. Ennemies are not the only thing that you have<br>
to be careful about; you can die from a lot of different events, as you will see in this post.<br>
Objects that you find, such as a silver ring, might be helpful in a run, but be cursed in the next run.</p>
<p>The latest version of the game, 3.6.1, was released on April 27th 2018, and this is how it looks like:</p>
<p><img src="https://i1.wp.com/upload.wikimedia.org/wikipedia/commons/f/ff/Nethack.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The graphics are… bare-bones to say the least. The game runs inside a terminal emulator and is<br>
available for any platform. The goal of NetHack is to explore a dungeon and go down every<br>
level until you find the Amulet of Yendor. Once you find this Amulet, you have to go all the way<br>
back upstairs, enter and fight your way through the Elemental Planes, enter the final Astral Plane,<br>
and then finally offer the Amulet of Yendor to your god to finish the game. Needless to say,<br>
NetHack is very difficult and players can go years without ever finishing the game.</p>
<p>When you start an new game, you have to create a character, which can have several attributes.<br>
You have to choose a race (human, elf, orc, etc), a role (tourist, samurai, mage, etc) and an<br>
alignment (neutral, law, chaos) and these choices impact your base stats.</p>
<p>If you can’t get past the ASCII graphics, you might want to try<br>
<a rel="nofollow" href="https://pathos.azurewebsites.net/" target="_blank">Pathos</a>, which is NetHack with touch screen support<br>
(on smartphones) and tile graphics:</p>
<p><img src="https://i1.wp.com/d2.alternativeto.net/dist/s/pathos-nethack-codex_729533_full.jpg?resize=456%2C456&ssl=1" data-recalc-dims="1"></p>
<p>You can install NetHack on your computer or you can play online on a pulbic server, such as<br>
this <a rel="nofollow" href="https://alt.org/nethack/" target="_blank">one</a>. There are several advantages when playing on a pubic server;<br>
the player does not have to install anyhing, and we data enthusiasts have access to a mine of<br>
information! For example, you can view the following <a rel="nofollow" href="https://alt.org/nethack/gamesday.php?date=20181025" target="_blank">table</a><br>
which contains data on all the games played on October 25th 2018. These tables start in the year 2001,<br>
and I am going to scrape the info from these tables, which will allow me to answer several questions.<br>
For instance, what is the floor most players die on? What kills most players?<br>
What role do players choose more often? I will explore this questions in a future blog post, but for<br>
now I will focus on scraping the data and realeasing it as a package to CRAN.</p>
</div>
<div>
<h2>Scraping the data</h2>
<p>To scrape the data I wrote a big function that does several things:</p>
<pre><code>library(&quot;tidyverse&quot;)
library(&quot;rvest&quot;)


scrape_one_day &lt;- function(link){

    convert_to_seconds &lt;- function(time_string){
        time_numeric &lt;- time_string %>%
            str_split(&quot;:&quot;, simplify = TRUE) %>%
            as.numeric
     
     time_in_seconds &lt;- time_numeric * c(3600, 60, 1)
     
     if(is.na(time_in_seconds)){
         time_in_seconds &lt;- 61
     } else {
         time_in_seconds &lt;- sum(time_in_seconds)
     }
     return(time_in_seconds)
    }

    Sys.sleep(1)

    date &lt;- str_extract(link, &quot;\\d{8}&quot;)

    read_lines_slow &lt;- function(...){
        Sys.sleep(1)
        read_lines(...)
    }
    
    page &lt;- read_html(link)

        # Get links
    dumplogs &lt;- page %>% 
        html_nodes(xpath = '//*[(@id = &quot;perday&quot;)]//td') %>%
        html_children() %>%
        html_attr(&quot;href&quot;) %>%
        keep(str_detect(., &quot;dumplog&quot;))

    # Get table
    table &lt;- page %>%
        html_node(xpath = '//*[(@id = &quot;perday&quot;)]') %>%
        html_table(fill = TRUE)

    if(is_empty(dumplogs)){
        print(&quot;dumplogs empty&quot;)
        dumplogs &lt;- rep(NA, nrow(table))
    } else {
        dumplogs &lt;- dumplogs
    }
    
    final &lt;- table %>%
        janitor::clean_names() %>%
        mutate(dumplog_links = dumplogs)

    print(paste0(&quot;cleaning data of date &quot;, date))
    
    clean_final &lt;- final %>%
        select(-x) %>%
        rename(role = x_2,
               race = x_3,
               gender = x_4,
               alignment = x_5) %>%
        mutate(time_in_seconds = map(time, convert_to_seconds)) %>%
        filter(!(death %in% c(&quot;quit&quot;, &quot;escaped&quot;)), time_in_seconds > 60) %>%
        mutate(dumplog = map(dumplog_links, ~possibly(read_lines_slow, otherwise = NA)(.))) %>%
        mutate(time_in_seconds = ifelse(time_in_seconds == 61, NA, time_in_seconds))

    saveRDS(clean_final, paste0(&quot;datasets/data_&quot;, date, &quot;.rds&quot;))

}</code></pre>
<p>Let’s go through each part. The first part is a function that converts strings like “02:21:76” to<br>
seconds:</p>
<pre><code>convert_to_seconds &lt;- function(time_string){
    time_numeric &lt;- time_string %>%
        str_split(&quot;:&quot;, simplify = TRUE) %>%
        as.numeric
 
time_in_seconds &lt;- time_numeric * c(3600, 60, 1)
 
if(is.na(time_in_seconds)){
  time_in_seconds &lt;- 61
  } else {
    time_in_seconds &lt;- sum(time_in_seconds)
    }
return(time_in_seconds)
}</code></pre>
<p>I will use this function on the column that gives the length of the run. However,<br>
before March 2008 this column is always empty, this is why I have the <code>if()...else()</code> statement at<br>
the end; if the time in seconds is <code>NA</code>, then I make it 61 seconds. I do this because I want to keep<br>
runs longer than 60 seconds, something I use <code>filter()</code> for later. But when filtering, if the condition<br>
returns <code>NA</code> (which happens when you do <code>NA > 60</code>) then you get an error, and the function fails.</p>
<p>The website links I am going to scrape all have the date of the day the runs took place. I am going to<br>
keep this date because I will need to name the datasets I am going to write to disk:</p>
<pre><code>date &lt;- str_extract(link, &quot;\\d{8}&quot;)</code></pre>
<p>Next, I define this function:</p>
<pre><code>read_lines_slow &lt;- function(...){
    Sys.sleep(1)
    read_lines(...)
}</code></pre>
<p>It is a wrapper around the <code>readr::read_lines()</code> with a call to <code>Sys.sleep(1)</code>. I will be scraping<br>
a lot of pages, so letting one second pass between each page will not overload the servers so much.</p>
<p>I then read the link with <code>read_html()</code> and start by getting the links of the dumplogs:</p>
<pre><code>page &lt;- read_html(link)

# Get links
dumplogs &lt;- page %>% 
    html_nodes(xpath = '//*[(@id = &quot;perday&quot;)]//td') %>%
    html_children() %>%
    html_attr(&quot;href&quot;) %>%
    keep(str_detect(., &quot;dumplog&quot;))</code></pre>
<p>You might be wondering what are dumplogs. Take a look at this screenshot:</p>
<pre><code>knitr::include_graphics(&quot;/img/dumplogs.png&quot;)</code></pre>
<p><img src="https://i0.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/dumplogs.png?w=456" data-recalc-dims="1"></p>
<p>When you click on those <code>d</code>‘s, you land on a page like this <a rel="nofollow" href="http://archive.is/wljb3" target="_blank">one</a> (I<br>
archived it to be sure that this link will not die). These logs contain a lot of info that I want<br>
to keep. To find the right ’xpath’ to scrape the links, &quot;’//<em><span>[(@id = &quot;perday&quot;)]</span>//td’&quot;, I used<br>
the </em>SelectorGadget* extension for Chrome. First I chose the table:</p>
<pre><code>knitr::include_graphics(&quot;/img/selectorgadget1.png&quot;)</code></pre>
<p><img src="https://i1.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/selectorgadget1.png?w=456" data-recalc-dims="1"></p>
<p>and then the links I am interested in:</p>
<pre><code>knitr::include_graphics(&quot;/img/selectorgadget2.png&quot;)</code></pre>
<p><img src="https://i0.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/selectorgadget2.png?w=456" data-recalc-dims="1"></p>
<p>Putting them together, I get the right “xpath”. But just as with the time of the run, dumplogs are<br>
only available after a certain date. So in case the <code>dumplogs</code> column is empty, I relpace it with <code>NA</code>.</p>
<pre><code>if(is_empty(dumplogs)){
    print(&quot;dumplogs empty&quot;)
    dumplogs &lt;- rep(NA, nrow(table))
} else {
    dumplogs &lt;- dumplogs
}</code></pre>
<p>The rest is quite simple:</p>
<pre><code># Get table
table &lt;- page %>%
    html_node(xpath = '//*[(@id = &quot;perday&quot;)]') %>%
    html_table(fill = TRUE)
               
final &lt;- table %>%
    janitor::clean_names() %>%
    mutate(dumplog_links = dumplogs)
           
print(paste0(&quot;cleaning data of date &quot;, date))</code></pre>
<p>I scrape the table, and then join the dumplog links to the table inside a new column called “dumplog_links”.</p>
<p>Because what follows is a long process, I print a message to let me know the progress of the scraping.</p>
<p>Now the last part:</p>
<pre><code>clean_final &lt;- final %>%
    select(-x) %>%
    rename(role = x_2,
           race = x_3,
           gender = x_4,
           alignment = x_5) %>%
    mutate(time_in_seconds = map(time, convert_to_seconds)) %>%
    filter(!(death %in% c(&quot;quit&quot;, &quot;escaped&quot;)), time_in_seconds > 60) %>%
    mutate(dumplog = map(dumplog_links, ~possibly(read_lines_slow, otherwise = NA)(.))) %>%
    mutate(time_in_seconds = ifelse(time_in_seconds == 61, NA, time_in_seconds))</code></pre>
<p>I first remove and remane columns. Then I convert the “time” column into seconds and also remove<br>
runs that lasted less than 60 seconds or that ended either in “quit” (the player left the game)<br>
or “escaped” (the player left the dungeon and the game ended immediately). There are a lot of runs<br>
like that and they’re not interesting. Finally, and this is what takes long, I create a new<br>
list-column where each element is the contents of the dumplog for that run. I wrap <code>read_lines_slow()</code><br>
around <code>purrr::possibly()</code> because dumplogs are missing for certains runs and when I try to read<br>
them I get an 404 error back. Getting such an error stops the whole process, so with <code>purrr::possibly()</code><br>
I can specify that in that case I want <code>NA</code> back. Basically, a function wrapped inside <code>purrr::possibly()</code><br>
never fails! Finally, if a game lasts for 61 seconds, I convert it back to <code>NA</code> (remember this was<br>
used to avoid having problems with the <code>filter()</code> function).</p>
<p>Finally, I export what I scraped to disk:</p>
<pre><code>saveRDS(clean_final, paste0(&quot;datasets/data_&quot;, date, &quot;.rds&quot;))</code></pre>
<p>This is where I use the date; to name the data. This is really important because scraping takes<br>
a very long time, so if I don’t write the progress to disk as it goes, I might lose hours of work<br>
if my internet goes down, or if computer freezes or whatever.</p>
<p>In the lines below I build the links that I am going to scrape. They’re all of the form:<br>
<code>https://alt.org/nethack/gamesday.php?date=YYYYMMDD</code> so it’s quite easy to create a list of<br>
dates to scrape, for example, for the year 2017:</p>
<pre><code>link &lt;- &quot;https://alt.org/nethack/gamesday.php?date=&quot;

dates &lt;- seq(as.Date(&quot;2017/01/01&quot;), as.Date(&quot;2017/12/31&quot;), by = &quot;day&quot;) %>%
    str_remove_all(&quot;-&quot;)

links &lt;- paste0(link, dates)</code></pre>
<p>Now I can easily scrape the data. To make extra sure that I will not have problems during the<br>
scraping process, for example if on a given day no games were played (and thus there is no table<br>
to scrape, which would result in an error) , I use the same trick as above by using <code>purrr::possibly()</code>:</p>
<pre><code>map(links, ~possibly(scrape_one_day, otherwise = NULL)(.))</code></pre>
<p>The scraping process took a very long time. I scraped all the data by letting my computer run for<br>
three days!</p>
<p>After this long process, I import all the <code>.rds</code> files into R:</p>
<pre><code>path_to_data &lt;- Sys.glob(&quot;datasets/*.rds&quot;)
nethack_data &lt;- map(path_to_data, readRDS)</code></pre>
<p>and take a look at one of them:</p>
<pre><code>nethack_data[[5812]] %>% 
  View()</code></pre>
<p>Let’s convert the “score” column to integer. For this, I will need to convert strings that look<br>
like “12,232” to integers. I’ll write a short function to do this:</p>
<pre><code>to_numeric &lt;- function(string){
  str_remove_all(string, &quot;,&quot;) %>%
    as.numeric
}</code></pre>
<pre><code>nethack_data &lt;- nethack_data %>%
  map(~mutate(., score = to_numeric(score)))</code></pre>
<p>Let’s merge the data into a single data frame:</p>
<pre><code>nethack_data &lt;- bind_rows(nethack_data)</code></pre>
<p>Now that I have a nice data frame, I will remove some columns and start the process of making a<br>
packages. I remove the columns that I created and that are now useless (such as the <code>dumplog_links</code><br>
column).</p>
<pre><code>nethack_data &lt;- nethack_data %>%
  select(rank, score, name, time, turns, lev_max, hp_max, role, race, gender, alignment, death,
         date, dumplog)</code></pre>
<p>Export this to <code>.rds</code> format, as it will be needed later:</p>
<pre><code>saveRDS(nethack_data, &quot;nethack_data.rds&quot;)</code></pre>
</div>
<div>
<h2>Making a package to share your data with the world</h2>
<p>As stated in the beginning of this post, I will walk you through the process of creating and<br>
releasing your package on CRAN. However, the data I scraped was too large to be made available<br>
as a CRAN package. But you can still get the data from Github (link is in the abstract at the<br>
beginning of the post).</p>
<p>Making a data package is a great way to learn how to make packages, because it is relatively easy<br>
to do (for example, you do not need to write unit tests). First, let’s start a new project<br>
in RStudio:</p>
<p><img src="https://i0.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/r_package1.png?w=456" data-recalc-dims="1"></p>
<p>Then select “R package”:</p>
<p><img src="https://i0.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/r_package2.png?w=456" data-recalc-dims="1"></p>
<p>Then name your package, create a git repository and then click on “Create Project”:</p>
<p><img src="https://i2.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/r_package3.png?w=456" data-recalc-dims="1"></p>
<p>RStudio wil open the <code>hello.R</code> script which you can now modify. You got to learn from the best, so<br>
I suggest that you modify <code>hello.R</code> by taking inspiration from the <code>babynames</code> package made by Hadley<br>
Wickham which you can find <a rel="nofollow" href="https://github.com/hadley/babynames/blob/master/R/data.R" target="_blank">here</a>.<br>
You do not need the first two lines, and can focus on lines 4 to 13. Then, rename the script to<br>
<code>data.R</code>. This is how <code>{nethack}'s</code> looks like:</p>
<pre><code>#' NetHack runs data.
#'
#' Data on NetHack runs scraped from https://alt.org/nethack/gamesday.php
#'
#' @format A data frame with 14 variables: \code{rank}, \code{score},
#'   \code{name}, \code{time}, \code{turns}, \code{lev_max}, \code{hp_max}, \code{role}, \code{race},
#'   \code{gender}, \code{alignment}, \code{death}, \code{date} and \code{dumplog}
#' \describe{
#' \item{rank}{The rank of the player on that day}
#' \item{score}{The score the player achieved on that run}
#' \item{name}{The name of the player}
#' \item{time}{The time the player took to finish the game}
#' \item{turns}{The number of turns the player played before finishing the game}
#' \item{lev_max}{The maximum character level the player achieved}
#' \item{hp_max}{The maximum character health points the player achieved}
#' \item{role}{The role the player chose to play as}
#' \item{race}{The race the player chose to play as}
#' \item{gender}{The gender the playr chose to play as}
#' \item{alignement}{The alignement the playr chose to play as}
#' \item{death}{The reason of death of the character}
#' \item{date}{The date the game took place}
#' \item{dumplog}{The log of the end game; this is a list column}
#' }
&quot;nethack&quot;</code></pre>
<p>The comments are special, the “#” is followed by a <code>'</code>; these are special comments that will be<br>
parsed by <code>roxygen2::roxygenise()</code> and converted to documentation files.</p>
<p>Next is the <code>DESCRIPTION</code> file. Here is how <code>{nethack}</code>’s looks like:</p>
<pre><code>Package: nethack
Type: Package
Title: Data from the Video Game NetHack
Version: 0.1.0
Authors@R: person(&quot;Bruno André&quot;, &quot;Rodrigues Coelho&quot;, email = &quot;bruno@brodrigues.co&quot;,
                  role = c(&quot;aut&quot;, &quot;cre&quot;))
Description: Data from NetHack runs played between 2001 to 2018 on 
    , a NetHack public server.
Depends: R (>= 2.10)
License: CC BY 4.0
Encoding: UTF-8
LazyData: true
RoxygenNote: 6.1.0</code></pre>
<p>Adapt yours accordingly. I chose the license <code>CC BY 4.0</code> because this was the licence under which<br>
the original data was published. It is also a good idea to add a <em>Vignette</em>:</p>
<pre><code>devtools::use_vignette(&quot;the_nethack_package&quot;)</code></pre>
<p>Vignettes are very useful documentation with more details and examples.</p>
<p>It is also good practice to add the script that was used to scrape the data. Such scripts go into<br>
<code>data-raw/</code>. Create this folder with:</p>
<pre><code>devtools::use_data_raw()</code></pre>
<p>This creates the <code>data-raw/</code> folder where I save the script that scrapes the data. Now is time to<br>
put the data in the package. Start by importing the data:</p>
<pre><code>nethack &lt;- readRDS(&quot;nethack_data.rds&quot;)</code></pre>
<p>To add the data to your package, you can use the following command:</p>
<pre><code>devtools::use_data(nethack, compress = &quot;xz&quot;)</code></pre>
<p>This will create the <code>data/</code> folder and put the data in there in the <code>.rda</code> format. I use the “compress”<br>
option to make the data smaller. You can now create the documentation by running:</p>
<pre><code>roxygen2::roxygenise()</code></pre>
<p>Pay attention to the log messages: you might need to remove files (for example the documentation<br>
<code>hello.R</code>, under the folder <code>man/</code>).</p>
<p>Now you can finaly run <code>R CMD Check</code> by clicking the <code>Check</code> button on the “Build” pane:</p>
<p><img src="https://i2.wp.com/www.brodrigues.co/blog/2018-11-01-nethack/img/r_package_check.png?w=456" data-recalc-dims="1"></p>
<p>This will extensively check the package for <code>ERRORS</code>, <code>WARNINGS</code> and <code>NOTES</code>. You need to make sure<br>
that the check passes without any <code>ERRORS</code> or <code>WARNINGS</code> and try as much as possible to remove all<br>
<code>NOTES</code> too. If you cannot remove a <code>NOTE</code>, for example in my case the following:</p>
<pre><code>checking installed package size ... NOTE
  installed size is 169.7Mb
  sub-directories of 1Mb or more:
    data  169.6Mb
R CMD check results
0 errors | 0 warnings  | 1 note </code></pre>
<p>You should document it in a new file called <code>cran-comments.md</code>:</p>
<pre><code>## Test environments
* local openSUSE Tumbleweed install, R 3.5.1
* win-builder (devel and release)

## R CMD check results
There were no ERRORs or WARNINGs.

There was 1 NOTE:

    *   installed size is 169.7Mb
sub-directories of 1Mb or more:
    data  169.6Mb

The dataset contains 17 years of NetHack games played, hence the size. This package will not be updated often (max once a year).</code></pre>
<p>Once you have eliminated all errors and warnings, you are almost ready to go.</p>
<p>You need now to test the package on different platforms. This depends a bit on the system you run,<br>
for me, because I run openSUSE (a GNU+Linux distribution) I have to test on Windows. This can be done<br>
with:</p>
<pre><code> devtools::build_win(version = &quot;R-release&quot;)</code></pre>
<p>and:</p>
<pre><code> devtools::build_win(version = &quot;R-devel&quot;)</code></pre>
<p>Explain that you have tested your package on several platforms in the <code>cran-comments.md</code> file.</p>
<p>Finally you can add a <code>README.md</code> and a <code>NEWS.md</code> file and start the process of publishing the<br>
package on CRAN:</p>
<pre><code>devtools:release()</code></pre>
<p>If you want many more details than what you can find in this blog post, I urge you to read<br>
“R Packages” by Hadley Wickham, which you can read for free <a rel="nofollow" href="http://r-pkgs.had.co.nz/" target="_blank">here</a>.</p>
<p>If you found this blog post useful, you might want to follow me on <a rel="nofollow" href="https://www.twitter.com/brodriguesco" target="_blank">twitter</a> for blog post updates.</p>
</div>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.brodrigues.co/blog/2018-11-01-nethack/"> Econometrics and Free Software</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/0jaf_XL58Vg" height="1"></a></div>