<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="http://www.r-bloggers.com/exploring-global-internet-performance-data-using-r/"></div></div><div><a data-url="http://www.r-bloggers.com/exploring-global-internet-performance-data-using-r/" data-counturl="http://www.r-bloggers.com/exploring-global-internet-performance-data-using-r/" data-count="horizontal" data-text="Exploring Global Internet Performance Data Using R" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://blog.revolutionanalytics.com/2016/06/exploring-global-internet-performance-data-using-r.html"> Revolutions</a></strong>, and kindly contributed to <a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers)</a> </div>
<div>
<p>by Lourdes O. Montenegro</p>
<p><em><span>Lourdes O. Montenegro is a PhD candidate at the Lee Kuan Yew School of Public Policy, National University of Singapore. Her research interests cover the intersection of applied data science, technology, economics and public policy.</span></em></p>
<p>Many of us now find it hard to live without a good quality internet connection. As a result, there is growing interest in characterizing and comparing internet performance metrics. For example, when planning to switch internet service providers or considering a move to a new city or country, internet users may want to research in advance what to expect in terms of download speed or latency. Cloud companies may want to provision adequately for different markets with varying levels of internet quality. And governments may want to benchmark their communications infrastructure and invest accordingly. Whatever the purpose, a consortium of research, industry and public interest organizations called <a target="_blank" href="http://www.measurementlab.net/">Measurement Lab</a> has made available the largest open and verifiable internet performance dataset in the planet. With the help of a combination of packages, R users can easily query, explore and visualize this large dataset at no cost.</p>
<p>In the example that follows, we use the <em>bigrquery</em> package to query and download results from the Network Diagnostic Tool (NDT) used by the U.S. FCC. The <em>bigrquery</em> package provides an interface to Google BigQuery which hosts NDT results along with several other Measurement Lab (M-Lab) datasets. However, R users will need to first set-up a BigQuery account and join the M-Lab mailing list to authenticate. <a target="_blank" href="http://www.measurementlab.net/data/bq/quickstart/">Detailed instructions</a> are provided on the M-Lab website. Once done, SQL-like queries can be run from within R. The results are saved as a dataframe on which further analysis can be performed. Aside from the convenience of working within the R environment, the <em>bigrquery</em> package has another advantage: the only limitation to the size of the query results that can be saved for further exploration is the amount of available RAM. In contrast, the BigQuery web interface only allows export to .csv format of query results which are at or below 16,000 rows.</p>
<p>The following R script gives us the average download speed (in Mbps) per country in 2015.<a name="_ftnref1" target="_blank" href="http://blog.revolutionanalytics.com/2016/06/exploring-global-internet-performance-data-using-r.html#_ftn1">[1]</a> The SQL-like query can be modified to return other internet performance metrics that may be of interest to the R user such as upload speed, round-trip time (latency) and packet re-transmission rates.</p>
<div>
<div>
<pre><span># Querying average download speed per country in 2015</span>
<a target="_blank" href="http://inside-r.org/r-doc/base/require"><span>require</span></a><span>(</span>bigrquery<span>)</span>
downquery_template &lt;- <span>&quot;SELECT
connection_spec.client_geolocation.country_code AS country, AVG(8 * web100_log_entry.snap.HCThruOctetsAcked/ (web100_log_entry.snap.SndLimTimeRwin +
web100_log_entry.snap.SndLimTimeCwnd + web100_log_entry.snap.SndLimTimeSnd)) AS downloadThroughput,
COUNT(DISTINCT test_id) AS tests,
FROM
plx.google:m_lab.ndt.all
WHERE
IS_EXPLICITLY_DEFINED(web100_log_entry.connection_spec.remote_ip)
AND IS_EXPLICITLY_DEFINED(web100_log_entry.connection_spec.local_ip)
AND IS_EXPLICITLY_DEFINED(web100_log_entry.snap.HCThruOctetsAcked)
AND IS_EXPLICITLY_DEFINED(web100_log_entry.snap.SndLimTimeRwin)
AND IS_EXPLICITLY_DEFINED(web100_log_entry.snap.SndLimTimeCwnd)
AND IS_EXPLICITLY_DEFINED(web100_log_entry.snap.SndLimTimeSnd)
AND project = 0
AND IS_EXPLICITLY_DEFINED(connection_spec.data_direction)
AND connection_spec.data_direction = 1
AND web100_log_entry.snap.HCThruOctetsAcked >= 8192
AND (web100_log_entry.snap.SndLimTimeRwin +
web100_log_entry.snap.SndLimTimeCwnd +
web100_log_entry.snap.SndLimTimeSnd) >= 9000000
AND (web100_log_entry.snap.SndLimTimeRwin +
web100_log_entry.snap.SndLimTimeCwnd + web100_log_entry.snap.SndLimTimeSnd) &lt; 3600000000
AND IS_EXPLICITLY_DEFINED(web100_log_entry.snap.CongSignals)
AND web100_log_entry.snap.CongSignals > 0
AND (web100_log_entry.snap.State == 1 OR (web100_log_entry.snap.State >= 5 AND web100_log_entry.snap.State &lt;= 11))
AND web100_log_entry.log_time >= PARSE_UTC_USEC('2015-01-01 00:00:00') / POW(10, 6) AND web100_log_entry.log_time &lt; PARSE_UTC_USEC('2016-01-01 00:00:00') / POW(10, 6)
GROUP BY country
ORDER BY country ASC;&quot;</span>
downresult &lt;- query_exec<span>(</span>downquery_template<span>,</span> project=<span>&quot;measurement-lab&quot;</span><span>,</span> max_pages=<span>Inf</span><span>)</span></pre>
</div>
</div>
<p>Once we have the query results in a dataframe, we can proceed to visualize and map average download speeds for each country. To do this, we can use the <em>rworldmap</em> package which offers a relatively simple way to map country level and gridded user datasets. Mapping is done mainly through two functions: (1) <em>joinCountryData2Map</em> joins the query results with shapefiles of country boundaries; (2) <em>mapCountryData</em> plots the chloropleth map. Note that the join is best effected using either two or three-letter ISO country codes, although the <em>rworldmap</em> package also allows join columns filled with country names.</p>
<p>In order to make the chloropleth map prettier and more comprehensible, we can augment with a combination of the <em>classInt</em> package to calculate natural breaks in the range of download speed results and the <em>RColorBrewer</em> package for a wider selection of color schemes. In the succeeding R script, we specify the Jenks method to cluster download speed results in such a way that minimizes deviation from the class mean within each class but maximizes deviation across class means. Compared to other methods for clustering download speed results, the Jenks method draws a sharper picture of countries clocking greater than 25 Mbps on average.</p>
<div>
<div>
<pre><a target="_blank" href="http://inside-r.org/r-doc/base/require"><span>require</span></a><span>(</span><a target="_blank" href="http://inside-r.org/packages/cran/rworldmap">rworldmap</a><span>)</span>
<a target="_blank" href="http://inside-r.org/r-doc/base/require"><span>require</span></a><span>(</span><a target="_blank" href="http://inside-r.org/packages/cran/classInt">classInt</a><span>)</span>
<a target="_blank" href="http://inside-r.org/r-doc/base/require"><span>require</span></a><span>(</span><a target="_blank" href="http://inside-r.org/packages/cran/RColorBrewer">RColorBrewer</a><span>)</span>
 
downloadmap &lt;- joinCountryData2Map<span>(</span>downresult
                              <span>,</span> joinCode=<span>'ISO2'</span>
                              <span>,</span> nameJoinColumn=<span>'country'</span>
                              <span>,</span> verbose=<span>'TRUE'</span><span>)</span>
<a target="_blank" href="http://inside-r.org/r-doc/graphics/par"><span>par</span></a><span>(</span>mai=<a target="_blank" href="http://inside-r.org/r-doc/base/c"><span>c</span></a><span>(</span><span>0</span><span>,</span><span>0</span><span>,</span><span>0.2</span><span>,</span><span>0</span><span>)</span><span>,</span>xaxs=<span>&quot;i&quot;</span><span>,</span>yaxs=<span>&quot;i&quot;</span><span>)</span>
 
<span>#getting class intervals using a 'jenks' classification in classInt package</span>
<a target="_blank" href="http://inside-r.org/packages/cran/classInt">classInt</a> &lt;- <a target="_blank" href="http://inside-r.org/packages/cran/classInt">classInt</a>::classIntervals<span>(</span> downloadmap<span>[</span><span>[</span><span>&quot;downloadThroughput&quot;</span><span>]</span><span>]</span><span>,</span> n=<span>5</span><span>,</span> style=<span>&quot;jenks&quot;</span><span>)</span>
catMethod = <a target="_blank" href="http://inside-r.org/packages/cran/classInt">classInt</a><span>[</span><span>[</span><span>&quot;brks&quot;</span><span>]</span><span>]</span>
<span>#getting a colour scheme from the RColorBrewer package</span>
colourPalette &lt;- <a target="_blank" href="http://inside-r.org/packages/cran/RColorBrewer">RColorBrewer</a>::brewer.pal<span>(</span><span>5</span><span>,</span><span>'RdPu'</span><span>)</span>
mapParams &lt;- mapCountryData<span>(</span>downloadmap<span>,</span> nameColumnToPlot=<span>&quot;downloadThroughput&quot;</span><span>,</span> 
                            mapTitle=<span>&quot;Download Speed (mbps)&quot;</span><span>,</span> catMethod=catMethod<span>,</span> 
                            colourPalette=colourPalette<span>,</span>
                            addLegend=<span>FALSE</span><span>)</span>
<a target="_blank" href="http://inside-r.org/r-doc/base/do.call"><span>do.call</span></a><span>(</span> addMapLegend<span>,</span> <a target="_blank" href="http://inside-r.org/r-doc/base/c"><span>c</span></a><span>(</span>mapParams<span>,</span> legendWidth=<span>0.5</span><span>,</span> legendLabels=<span>&quot;all&quot;</span><span>,</span> 
                         legendIntervals=<span>&quot;data&quot;</span><span>,</span> legendMar = <span>2</span><span>)</span><span>)</span></pre>
</div>
</div>
<p>  <a target="_blank" href="http://revolution-computing.typepad.com/.a/6a010534b1db25970b01b7c870fc48970b-pi"><img title="Worldspeedmap2015revised" alt="Worldspeedmap2015revised" src="http://revolution-computing.typepad.com/.a/6a010534b1db25970b01b7c870fc48970b-800wi" border="0"></a></p>
<p>Looking at the map, we see that the UK, Japan, Romania, Sweden, Taiwan, The Netherlands, Denmark and Singapore (if we squint!) are the best places to be for internet speed addicts. Until further investigation, we can safely discount the suspiciously high results for North Korea since the number of observations are too low. In contrast, average download speeds in South Korea might be grossly underestimated when measured from foreign servers, as may be the case with NDT results, since most Koreans access locally hosted content. There are, of course, a number of caveats worth mentioning before drawing any conclusions regarding the causes of varying internet performance between countries. Confounding factors such as distance from the client to the test server, the client's operating system, and the proportion of fixed broadband to wireless connections will need to be controlled for. Despite these caveats, this tentative exploration already reveals interesting patterns in global internet performance that is worth a closer look.</p>
<p><a name="_ftn1" target="_blank" href="http://blog.revolutionanalytics.com/2016/06/exploring-global-internet-performance-data-using-r.html#_ftnref1">[1]</a>    Thanks to Stephen McInerney and Chris Ritzo for code advice.</p>
</div>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="http://www.r-bloggers.com/exploring-global-internet-performance-data-using-r/"></div></div><div><a data-url="http://www.r-bloggers.com/exploring-global-internet-performance-data-using-r/" data-counturl="http://www.r-bloggers.com/exploring-global-internet-performance-data-using-r/" data-count="vertical" data-text="Exploring Global Internet Performance Data Using R" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://blog.revolutionanalytics.com/2016/06/exploring-global-internet-performance-data-using-r.html"> Revolutions</a></strong>.</div>
<hr>
<a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="http://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="http://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="http://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="http://www.r-bloggers.com/?s=Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="http://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="http://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="http://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="http://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="http://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="http://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="http://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="http://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="http://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="http://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="http://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="http://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/oi9JJEMtI3A"></a></div>