<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/speeding-up-spatial-analyses-by-integrating-sf-and-data-table-a-test-case/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://lbusettspatialr.blogspot.com/2018/02/speeding-up-spatial-analyses-by.html"> Spatial Processing in R</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<h2><span>The problem</span></h2>
<h2>
<div>
<div><span>Last week, I replied to this </span><a rel="nofollow" href="https://stackoverflow.com/questions/48650274/spatial-efficient-way-of-finding-all-points-within-x-meters-of-a-point" target="_blank">interesting question</a><span> posted by </span><span>@Tim_K</span><span> </span><span>over stackoverflow. He was seeking efficient solutions to </span>identify all points falling within a maximum distance of xx meters with respect to each single point in a spatial points dataset<span>.</span></div>
<div><span>If you have a look at the thread, you will see that a simple solution based on creating a “buffered” polygon dataset beforehand and then intersecting it with the original points is quite fast </span><i>for “reasonably sized” datasets</i><span>, thanks to</span><span> </span><code>sf</code><span> </span><span>spatial indexing capabilities which reduce the number of the required comparisons to be done (See</span><span> </span><a rel="nofollow" href="http://r-spatial.org/r/2017/06/22/spatial-index.html" target="_blank">http://r-spatial.org/r/2017/06/22/spatial-index.html</a><span>). In practice, something like this:</span><br><a name="more"></a></div>
<div>
<pre><code><span># create test data: 50000 uniformly distributed points on a &quot;square&quot; of 100000</span><br><span># metres</span><br>maxdist &lt;-<span> </span><span>500</span><br>pts     &lt;-<span> </span><span>data.frame</span>(<span>x =</span> <span>runif</span>(<span>50000</span>, <span>0</span>, <span>100000</span>),<br>                      <span>y =</span> <span>runif</span>(<span>50000</span>, <span>0</span>, <span>100000</span>),<br>                      <span>id =</span> <span>1</span><span>:</span><span>50000</span>) <span>%>%</span><br><span> </span>sf<span>::</span><span>st_as_sf</span>(<span>coords =</span> <span>c</span>(<span>&quot;x&quot;</span>, <span>&quot;y&quot;</span>))<br><span># create buffered polygons</span><br>pts_buf &lt;-<span> </span>sf<span>::</span><span>st_buffer</span>(pts, maxdist)<br><span># Find points within 500 meters wrt each point</span><br>int &lt;-<span> </span>sf<span>::</span><span>st_intersects</span>(pts_buf, pts)<br>int</code></pre>
</div>
<pre><code>## Sparse geometry binary predicate list of length 50000, where the predicate was `intersects'<br>## first 10 elements:<br>##  1: 1, 11046, 21668, 25417<br>##  2: 2, 8720, 12595, 23620, 26926, 27169, 39484<br>##  3: 3, 11782, 20058, 27869, 33151, 47864<br>##  4: 4, 35665, 45691<br>##  5: 5, 37093, 37989<br>##  6: 6, 31487<br>##  7: 7, 38433, 42009, 45597, 49806<br>##  8: 8, 12129, 31486<br>##  9: 9, 27840, 35577, 36797, 40906<br>##  10: 10, 15482, 16615, 26103, 41417</code></pre>
<div><span>However, this starts to have </span>problems over really large datasets<span>, because the total number of comparisons to be done still rapidly increase besides the use of spatial indexes. A </span>test<span> done by changing the number of points in the above example in the range 25000 – 475000 shows for example this kind of behavior, for two different values of</span><span> </span><code>maxdist</code><span> </span><span>(500 and 2000 m):</span>
<div></div>
<div><a rel="nofollow" href="https://i2.wp.com/1.bp.blogspot.com/-KcqMy6mXBOo/WowAzjEyJSI/AAAAAAAANGE/_1-YSdF0gSgkAFwOg3hg0BqYUjMGTbWUACLcBGAs/s1600/Rplot01.png?ssl=1" target="_blank"><img border="0" src="https://i1.wp.com/1.bp.blogspot.com/-KcqMy6mXBOo/WowAzjEyJSI/AAAAAAAANGE/_1-YSdF0gSgkAFwOg3hg0BqYUjMGTbWUACLcBGAs/s640/Rplot01.png?resize=450%2C477&ssl=1" data-original-width="450" width="450" data-original-height="477" data-recalc-dims="1"></a></div>
<div></div>
</div>
<div><span>On the test dataset, the relationships are </span><i>almost perfectly quadratic </i><span>(due to the uniform distribution of points). Extrapolating them to the </span>12 Million points dataset of the OP<span>, we would get an execution time of about 14 hours for</span><span> </span><code>maxdist = 500</code><span>, and a staggering </span>3.5 days <span>for</span><code>maxdist = 2000</code><span>. Still doable, but not ideal…</span></div>
<div>My suggestion to the OP was therefore to<span> </span><span>“split” the points in chunks</span><span> </span>based on the x-coordinate and then work on a per-split basis, eventually assigning each chunk to a different core within a parallellized cycle.</div>
<div>In the end, I got curious and decided to give it a go<span> </span><span>to see what kind of performance improvement it was possible to obtain</span><span> </span>with that kind of approach. You can find results of some tests below.</div>
</div>
</h2>
<h3><span>A (possible) solution: Speeding up computation by combining data.table and sf_intersect</span></h3>
<h2>
<div>
<div>The idea here is to use a<span> </span><span>simple divide-and-conquer approach</span>.</div>
<div>We first<span> </span><span>split the total spatial extent</span><span> </span>of the dataset in a certain number of regular quadrants. We then iterate over the quadrants and for each one we:</div>
<ol>
<li>Extract the<span> </span><span>points contained into the quadrant</span><span> </span>and apply a buffer to them;</li>
<li>Extract the<span> </span><span>points contained in a slightly larger area</span>, computed by expanding the quadrant by an amount equal to the <i>maximum distance for which we want to identify the “neighbors”;</i></li>
<li><span>Compute and save the intersection</span><span> </span>between the buffered points and the points contained in the “expanded” quadrant</li>
</ol>
<div>“Graphically”, this translates to exploring the dataset like this:
<div><a rel="nofollow" href="https://i0.wp.com/1.bp.blogspot.com/-AG71hBW1vBw/Wov9Qxlo_8I/AAAAAAAANF4/OjpSHuc8Nx8vtRWiSSGHbgq_QCV8YraSQCLcBGAs/s1600/animation2.gif?ssl=1" target="_blank"><img border="0" src="https://i1.wp.com/1.bp.blogspot.com/-AG71hBW1vBw/Wov9Qxlo_8I/AAAAAAAANF4/OjpSHuc8Nx8vtRWiSSGHbgq_QCV8YraSQCLcBGAs/s320/animation2.gif?resize=450%2C480&ssl=1" data-original-width="450" width="450" data-original-height="480" data-recalc-dims="1"></a></div>
<p>, where the points included in the current “quadrant” are shown in green and the additional points needed to perform the analysis for that quadrant are shown in red.</p>
<p>Provided that the subsetting operations do not introduce an excessive overhead (i.e., they are fast enough…) this should provide a performance boost, because it<span> </span><span>should consistently reduce the total number of comparisons</span><span> </span>to be done.</div>
<div>Now, every “R” expert will tell you that if you need to perform fast subsetting over large datasets the way to go is to use<span> </span><span>properly indexed</span><code>data.tables</code>, which provide lightning-speed subsetting capabilities.</div>
<div>So, let’s see<span> </span><span>how we could code this</span><span> </span>in a functions:</div>
<div>
<pre><code>points_in_distance &lt;-<span> </span><span>function</span>(in_pts,<br>                               maxdist,<br>                               <span>ncuts =</span> <span>10</span>) {<br><br>  <span>require</span>(data.table)<br>  <span>require</span>(sf)<br>  <span># convert points to data.table and create a unique identifier</span><br>  pts &lt;-<span> </span><span>data.table</span>(in_pts)<br>  pts &lt;-<span> </span>pts[, or_id <span>:</span><span>=</span><span> </span><span>1</span><span>:</span><span>dim</span>(in_pts)[<span>1</span>]]<br><br>  <span># divide the extent in quadrants in ncuts*ncuts quadrants and assign each</span><br>  <span># point to a quadrant, then create the index over &quot;x&quot; to speed-up</span><br>  <span># the subsetting</span><br>  range_x  &lt;-<span> </span><span>range</span>(pts<span>$</span>x)<br>  limits_x &lt;-(range_x[<span>1</span>] <span>+</span><span> </span>(<span>0</span><span>:</span>ncuts)<span>*</span>(range_x[<span>2</span>] <span>-</span><span> </span>range_x[<span>1</span>])<span>/</span>ncuts)<br>  range_y  &lt;-<span> </span><span>range</span>(pts<span>$</span>y)<br>  limits_y &lt;-<span> </span>range_y[<span>1</span>] <span>+</span><span> </span>(<span>0</span><span>:</span>ncuts)<span>*</span>(range_y[<span>2</span>] <span>-</span><span> </span>range_y[<span>1</span>])<span>/</span>ncuts<br>  pts[, <span>`</span><span>:=</span><span>`</span>(<span>xcut =</span>  <span>as.integer</span>(<span>cut</span>(x, ncuts, <span>labels =</span> <span>1</span><span>:</span>ncuts)),<br>             <span>ycut =</span> <span>as.integer</span>(<span>cut</span>(y, ncuts, <span>labels =</span> <span>1</span><span>:</span>ncuts)))]  <span>%>%</span><br><span> </span><span>setkey</span>(x)<br><br>  results &lt;-<span> </span><span>list</span>()<br>  count &lt;-<span> </span><span>0</span><br>  <span># start cycling over quadrants</span><br>  <span>for</span> (cutx <span>in seq_len</span><span>(ncuts)</span>) {<br><br>    <span># get the points included in a x-slice extended by `maxdist`, and build</span><br>    <span># an index over y to speed-up subsetting in the inner cycle</span><br>    min_x_comp    &lt;-<span> </span><span>ifelse</span>(cutx <span>==</span><span> </span><span>1</span>,<br>                            limits_x[cutx],<br>                            (limits_x[cutx] <span>-</span><span> </span>maxdist))<br>    max_x_comp    &lt;-<span> </span><span>ifelse</span>(cutx <span>==</span><span> </span>ncuts,<br>                            limits_x[cutx <span>+</span><span> </span><span>1</span>],<br>                            (limits_x[cutx <span>+</span><span> </span><span>1</span>] <span>+</span><span> </span>maxdist))<br>    subpts_x &lt;-<span> </span>pts[x <span>>=</span><span> </span>min_x_comp <span>&amp;</span><span> </span>x <span></span><span> </span>max_x_comp] <span>%>%</span><br><span> </span><span>setkey</span>(y)<br><br>    <span>for</span> (cuty <span>in seq_len</span>(ncuts)<span>) {</span><br>      count &lt;-<span> </span>count <span>+</span><span> </span><span>1</span><br><br>      <span># subset over subpts_x to find the final set of points needed for the</span><br>      <span># comparisons</span><br>      min_y_comp  &lt;-<span> </span><span>ifelse</span>(cuty <span>==</span><span> </span><span>1</span>,<br>                            limits_y[cuty],<br>                            (limits_x[cuty] <span>-</span><span> </span>maxdist))<br>      max_y_comp  &lt;-<span> </span><span>ifelse</span>(cuty <span>==</span><span> </span>ncuts,<br>                            limits_x[cuty <span>+</span><span> </span><span>1</span>],<br>                            (limits_x[cuty <span>+</span><span> </span><span>1</span>] <span>+</span><span> </span>maxdist))<br>      subpts_comp &lt;-<span> </span>subpts_x[y <span>>=</span><span> </span>min_y_comp <span>&amp;</span><span> </span>y <span></span><span> </span>max_y_comp]<br><br>      <span># subset over subpts_comp to get the points included in a x/y chunk,</span><br>      <span># which &quot;neighbours&quot; we want to find. Then buffer them by maxdist.</span><br>      subpts_buf &lt;-<span> </span>subpts_comp[ycut <span>==</span><span> </span>cuty <span>&amp;</span><span> </span>xcut <span>==</span><span> </span>cutx] <span>%>%</span><br><span> </span>sf<span>::</span><span>st_as_sf</span>() <span>%>% </span><br><span> sf::</span><span>st_buffer</span>(maxdist)<br><br>      <span># retransform to sf since data.tables lost the geometric attrributes</span><br>      subpts_comp &lt;-<span> </span>sf<span>::</span><span>st_as_sf</span>(subpts_comp)<br><br>      <span># compute the intersection and save results in a element of &quot;results&quot;.</span><br>      <span># For each point, save its &quot;or_id&quot; and the &quot;or_ids&quot; of the points within &quot;dist&quot;</span><br>      inters &lt;-<span> </span>sf<span>::</span><span>st_intersects</span>(subpts_buf, subpts_comp)<br><br>      <span># save results</span><br>      results[[count]] &lt;-<span> </span><span>data.table</span>(<br>        <span>id =</span> subpts_buf<span>$</span>or_id,<br>        <span>int_ids =</span> <span>lapply</span>(inters, <span>FUN =</span> <span>function</span>(x) subpts_comp<span>$</span>or_id[x]))<br>    }<br>  }<br>  data.table<span>::</span><span>rbindlist</span>(results)<br>}</code></pre>
</div>
<div>The function takes as input a<span> </span><span>points<span> </span><code>sf</code><span> </span>object</span>, a<span> </span><span>target distance</span><span> </span>and a<span> </span><span>number of “cuts”</span><span> </span>to use to divide the extent in quadrants, and provides in output a data frame in which, for each original point, the “ids” of the points within<span> </span><code>maxdist</code><span> </span>are reported<span> </span><span>in the<span> </span><code>int_ids</code><span> </span>list column</span>.</div>
<div><span>Now, </span><u>let’s see if this works</u><span>:</span></div>
<div>
<pre><code>pts &lt;-<span> </span><span>data.frame</span>(<span>x =</span> <span>runif</span>(<span>20000</span>, <span>0</span>, <span>100000</span>),<br>                  <span>y =</span> <span>runif</span>(<span>20000</span>, <span>0</span>, <span>100000</span>),<br>                  <span>id =</span> <span>1</span><span>:</span><span>20000</span>) <span>%>%</span><br><span> </span><span>st_as_sf</span>(<span>coords =</span> <span>c</span>(<span>&quot;x&quot;</span>, <span>&quot;y&quot;</span>), <span>remove =</span> <span>FALSE</span>)<br>maxdist &lt;-<span> </span><span>2000</span><br>out &lt;-<span> </span><span>points_in_distance</span>(pts, <span>maxdist =</span> maxdist, <span>ncut =</span> <span>10</span>)<br>out</code></pre>
</div>
<pre><code>##           id                              int_ids<br>##     1: 15119  2054,18031, 9802, 8524, 4107, 7412,<br>##     2: 14392 12213,10696, 6399,14392, 4610, 1200,<br>##     3: 14675  2054,18031, 9802, 8524, 4107, 7412,<br>##     4:  3089 12293,18031, 8524, 4107,12727, 2726,<br>##     5: 17282       9802,8524,4107,7412,2726,1275,<br>##    ---                                           <br>## 19995:   248 16610, 7643, 8059,15998,16680, 1348,<br>## 19996:  8433 16821,15638,16680, 3876,13851, 1348,<br>## 19997: 17770 11060, 7643, 8059,19868, 7776,10146,<br>## 19998: 11963  9948, 9136,15956,18512, 9219, 8925,<br>## 19999: 15750  5291,18093,14462,15362,12575, 5189,</code></pre>
<div>
<pre><code><span># get a random point</span><br>sel_id  &lt;-<span> </span><span>sample</span>(pts<span>$</span>id,<span>1</span>)<br>pt_sel  &lt;-<span> </span>pts[sel_id, ]<br>pt_buff &lt;-<span> </span>pt_sel <span>%>%</span><span> </span>sf<span>::</span><span>st_buffer</span>(maxdist)<br><span># get ids of points within maxdist</span><br>id_inters &lt;-<span> </span><span>unlist</span>(out[id <span>==</span><span> </span>sel_id, ]<span>$</span>int_ids)<br>pt_inters &lt;-<span> </span>pts[id_inters,]<br><br><span>#plot results</span><br><span>ggplot</span>(pt_buff)  <span>+</span><span> </span><span>theme_light</span>() <span>+</span><br><span> </span><span>geom_point</span>(<span>data =</span> pts, <span>aes</span>(<span>x =</span> x, <span>y =</span> y), <span>size =</span> <span>1</span>) <span>+</span><br><span> </span><span>geom_sf</span>(<span>col =</span> <span>&quot;blue&quot;</span>, <span>size =</span> <span>1.2</span>, <span>fill =</span> <span>&quot;transparent&quot;</span>) <span>+</span><br><span> </span><span>geom_sf</span>(<span>data =</span> pt_inters, <span>col =</span> <span>&quot;red&quot;</span>, <span>size =</span> <span>1.5</span>) <span>+</span><br><span> </span><span>geom_point</span>(<span>data =</span> pt_sel, <span>aes</span>(<span>x =</span> x, <span>y =</span> y), <span>size =</span> <span>2</span>, <span>col =</span> <span>&quot;green&quot;</span>) <span>+</span><br><span> </span><span>xlim</span>(<span>st_bbox</span>(pt_buff)[<span>1</span>] <span>-</span><span> </span>maxdist, <span>st_bbox</span>(pt_buff)[<span>3</span>] <span>+</span><span> </span>maxdist) <span>+</span><br><span> </span><span>ylim</span>(<span>st_bbox</span>(pt_buff)[<span>2</span>] <span>-</span><span> </span>maxdist, <span>st_bbox</span>(pt_buff)[<span>4</span>] <span>+</span><span> </span>maxdist) <span>+</span><span> </span><br><span> </span><span>ggtitle</span>(<span>paste0</span>(<span>&quot;id = &quot;</span>, sel_id, <span>&quot; - Number of points within distance = &quot;</span>, <span>length</span>(id_inters)))</code></pre>
</div>
<div>
<div><a rel="nofollow" href="https://i1.wp.com/3.bp.blogspot.com/-S2NspQ46veo/WowBskp4_wI/AAAAAAAANGM/BdjMp99hg3QWexWxoPNo8xBLIpREsF5mACLcBGAs/s1600/Rplot2.png?ssl=1" target="_blank"><img border="0" src="https://i0.wp.com/3.bp.blogspot.com/-S2NspQ46veo/WowBskp4_wI/AAAAAAAANGM/BdjMp99hg3QWexWxoPNo8xBLIpREsF5mACLcBGAs/s400/Rplot2.png?resize=450%2C477&ssl=1" data-original-width="450" width="450" data-original-height="477" data-recalc-dims="1"></a></div>
<p><span>So far, so good</span>. Now, let’s do the same exercise with varying number of points to see <u>how it behaves in term of speed</u>:</p>
<div><a rel="nofollow" href="https://i2.wp.com/2.bp.blogspot.com/-jirwQtpYwuY/WowBureJrGI/AAAAAAAANGQ/bN94b1sanqg0KuWVtpn3USNPQjCmdC2ugCEwYBhgL/s1600/Rplot3.png?ssl=1" target="_blank"><img border="0" src="https://i0.wp.com/2.bp.blogspot.com/-jirwQtpYwuY/WowBureJrGI/AAAAAAAANGQ/bN94b1sanqg0KuWVtpn3USNPQjCmdC2ugCEwYBhgL/s640/Rplot3.png?resize=450%2C477&ssl=1" data-original-width="450" width="450" data-original-height="477" data-recalc-dims="1"></a></div>
<div></div>
</div>
<div>Already not bad! In particular for the<span> </span><code>maxdist = 2000</code><span> </span>case, we get a quite large speed improvement!</div>
<div>However, a nice thing about the<span> </span><code>points_in_distance</code><span> </span>approach is that<span> </span><span>it is easily parallelizable</span>. All is needed is to change some lines of the function so that <u>the outer loop over the<span> </span><code>x</code><span> </span>“chunks” exploits a parallel backend</u> of some kind. (You can find an example implementation exploiting<span> </span><code>foreach</code>in<span> </span><a rel="nofollow" href="https://gist.github.com/lbusett/247dc9b0b6bed04ac1b45c03999be348" target="_blank">this gist</a>)</div>
<div>On a not-particularly-fast PC, using a 6-cores parallelization leads to this:
<div><a rel="nofollow" href="https://i1.wp.com/4.bp.blogspot.com/-PcjVQP4Yx_E/WowBzAV6vnI/AAAAAAAANGU/ZhXsCjd4RTgVRhksNymc3KU84m2xH0H4ACEwYBhgL/s1600/Rplot4.png?ssl=1" target="_blank"><img border="0" src="https://i2.wp.com/4.bp.blogspot.com/-PcjVQP4Yx_E/WowBzAV6vnI/AAAAAAAANGU/ZhXsCjd4RTgVRhksNymc3KU84m2xH0H4ACEwYBhgL/s640/Rplot4.png?resize=450%2C477&ssl=1" data-original-width="450" width="450" data-original-height="477" data-recalc-dims="1"></a></div>
<div></div>
</div>
<div><span>Looking good!</span><span> </span>Some more skilled programmer could probably squeeze out even more speed from it by some additional<span> </span><code>data.table</code><span> </span>magic, but the improvement is very noticeable.</div>
<div>
<div>In terms of execution time, extrapolating again to the<span> </span><span>“infamous” 12 Million points dataset,</span><span> </span>this would be what we get:</div>
<div><span><br></span></div>
</div>
<table>
<thead>
<tr>
<th><span>Method </span></th>
<th><span>Maxdist </span></th>
<th><span>Expected completion time (hours) </span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>st_intersect </span></td>
<td><span>500 </span></td>
<td><span>15.00 </span></td>
</tr>
<tr>
<td><span>points_in_distance – serial </span></td>
<td><span>500 </span></td>
<td><span>2.50 </span></td>
</tr>
<tr>
<td><span>points_in_distance – parallel </span></td>
<td><span>500 </span></td>
<td><span>0.57 </span></td>
</tr>
<tr>
<td><span>st_intersect </span></td>
<td><span>2000 </span></td>
<td><span><b>85.00 </b></span></td>
</tr>
<tr>
<td><span>points_in_distance – serial </span></td>
<td><span>2000 </span></td>
<td><span>15.20 </span></td>
</tr>
<tr>
<td><span>points_in_distance – parallel </span></td>
<td><span>2000 </span></td>
<td><span><b>3.18 </b></span></td>
</tr>
</tbody>
</table>
<div>
<div>So, we get<span> </span><span>a 5-6X speed improvement</span><span> </span>already on the “serial” implementation, and<span> </span><span>another 5X</span><span> </span>thanks to parallelization over 6 cores! On the<code>maxdist = 2000</code><span> </span>case, this means going<span> </span><span>from more than 3 days to about 3 hours</span>. And if we had more cores and RAM to throw at it, it would finish in minutes!</div>
</div>
<div><span><u>Nice!</u></span></div>
</div>
</h2>
<h2><span>Final Notes</span></h2>
<h2>
<div>
<ul>
<li>
<div>The timings shown here are merely indicative, and related to the particular test-dataset we built. On a less uniformly distributed dataset I would expect a lower speed improvement.</div>
</li>
<li>
<div><span>Some time is “wasted” because</span><span> </span><code>sf</code><span> </span>does not (yet) extend<span> </span><code>data.tables</code><span>, making it necessary to recreate</span><span> </span><code>sf</code><span> </span><span>objects from the</span><code>data.table</code><span> </span><span>subsets.</span></div>
</li>
<li>
<div><span>The parallel implementation is quick-and-dirty, and it is a bit of a </span>memory-hog<span>! Be careful before throwing at it 25 processors!</span></div>
</li>
<li>
<div><span>Speed is </span>influenced in a non-trivial way by the number of “cuts”<span> used to subdivide the spatial extent. There may be a sweet-spot related to points distribution and maxdist allowing reaching maximum speed.</span></div>
</li>
<li>
<div><span>A similar approach for parallelization could exploit </span>repeatedly “cropping” the original<span> </span><code>sf</code><span> </span>points object <span>over the extent of the chunk/extended chunk. The</span><span> </span><code>data.table</code><span> </span><span>approach seems however to be faster.</span></div>
</li>
</ul>
<div>
<div></div>
<p><span>That’s all! Hope you liked this (rather long) post!</span></div>
</div>
</h2>
	<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://lbusettspatialr.blogspot.com/2018/02/speeding-up-spatial-analyses-by.html"> Spatial Processing in R</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 alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/gfZLqXvdFJg" height="1"></a></div>