<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/linear-splines-with-convenient-parametrisations/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://bc.bojanorama.pl/2017/04/linear-splines-with-convenient-parametrisations/"> R – Brokering Closure</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>I have just published a small package <code>lspline</code> on CRAN that implements linear splines using convenient parametrisations such that</p>
<ul>
<li>coefficients are slopes of consecutive segments</li>
<li>coefficients capture slope change at consecutive knots</li>
</ul>
<p>Knot locations can be specified</p>
<ul>
<li>manually (with <code>lspline()</code>)</li>
<li>at breaks dividing the range of <code>x</code> into <code>q</code> equal-frequency intervals (with <code>qlspline()</code>)</li>
<li>at breaks dividing the range of <code>x</code> into <code>n</code> equal-width intervals (with <code>elspline()</code>)</li>
</ul>
<p>The implementation follows Greene (2003, chapter 7.5.2).</p>
<p>The package sources are on GitHub <a target="_blank" rel="nofollow" href="https://github.com/mbojan/lspline">here</a>.</p>
<h1>Examples</h1>
<p>We will use the following artificial data with knots at <code>x=5</code> and <code>x=10</code>:</p>
<pre><code>set.seed(666)
n &lt;- 200
d &lt;- data.frame(
  x = scales::rescale(rchisq(n, 6), c(0, 20))
)
d$interval &lt;- findInterval(d$x, c(5, 10), rightmost.closed = TRUE) + 1
d$slope &lt;- c(2, -3, 0)[d$interval]
d$intercept &lt;- c(0, 25, -5)[d$interval]
d$y &lt;- with(d, intercept + slope * x + rnorm(n, 0, 1))
</code></pre>
<p>Plotting <code>y</code> against <code>x</code>:</p>
<pre><code>library(ggplot2)
fig &lt;- ggplot(d, aes(x=x, y=y)) + 
  geom_point(aes(shape=as.character(slope))) +
  scale_shape_discrete(name=&quot;Slope&quot;) +
  theme_bw()
fig
</code></pre>
<p><a target="_blank" rel="nofollow" href="https://i1.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-show_data-1.png"><img sizes="(max-width: 300px) 100vw, 300px" alt="" class="wp-image-876" src="https://i2.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-show_data-1-300x214.png?resize=300%2C214" data-recalc-dims="1"></a></p>
<p>The slopes of the consecutive segments are 2, -3, and 0.</p>
<h2>Setting knot locations manually</h2>
<p>We can parametrize the spline with slopes of individual segments (default <code>marginal=FALSE</code>):</p>
<pre><code>library(lspline)
m1 &lt;- lm(y ~ lspline(x, c(5, 10)), data=d)
knitr::kable(broom::tidy(m1))
</code></pre>
<table>
<thead>
<tr>
<th align="left">term</th>
<th align="right">estimate</th>
<th align="right">std.error</th>
<th align="right">statistic</th>
<th align="right">p.value</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">(Intercept)</td>
<td align="right">0.1343204</td>
<td align="right">0.2148116</td>
<td align="right">0.6252941</td>
<td align="right">0.5325054</td>
</tr>
<tr>
<td align="left">lspline(x, c(5, 10))1</td>
<td align="right">1.9435458</td>
<td align="right">0.0597698</td>
<td align="right">32.5171747</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">lspline(x, c(5, 10))2</td>
<td align="right">-2.9666750</td>
<td align="right">0.0503967</td>
<td align="right">-58.8664832</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">lspline(x, c(5, 10))3</td>
<td align="right">-0.0335289</td>
<td align="right">0.0518601</td>
<td align="right">-0.6465255</td>
<td align="right">0.5186955</td>
</tr>
</tbody>
</table>
<p>Or parametrize with coeficients measuring change in slope (with <code>marginal=TRUE</code>):</p>
<pre><code>m2 &lt;- lm(y ~ lspline(x, c(5,10), marginal=TRUE), data=d)
knitr::kable(broom::tidy(m2))
</code></pre>
<table>
<thead>
<tr>
<th align="left">term</th>
<th align="right">estimate</th>
<th align="right">std.error</th>
<th align="right">statistic</th>
<th align="right">p.value</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">(Intercept)</td>
<td align="right">0.1343204</td>
<td align="right">0.2148116</td>
<td align="right">0.6252941</td>
<td align="right">0.5325054</td>
</tr>
<tr>
<td align="left">lspline(x, c(5, 10), marginal = TRUE)1</td>
<td align="right">1.9435458</td>
<td align="right">0.0597698</td>
<td align="right">32.5171747</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">lspline(x, c(5, 10), marginal = TRUE)2</td>
<td align="right">-4.9102208</td>
<td align="right">0.0975908</td>
<td align="right">-50.3143597</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">lspline(x, c(5, 10), marginal = TRUE)3</td>
<td align="right">2.9331462</td>
<td align="right">0.0885445</td>
<td align="right">33.1262479</td>
<td align="right">0.0000000</td>
</tr>
</tbody>
</table>
<p>The coefficients are</p>
<ul>
<li><code>lspline(x, c(5, 10), marginal = TRUE)1</code> – the slope of the first segment</li>
<li><code>lspline(x, c(5, 10), marginal = TRUE)2</code> – the change in slope at knot <em>x</em> = 5; it is changing from 2 to -3, so by -5</li>
<li><code>lspline(x, c(5, 10), marginal = TRUE)3</code> – tha change in slope at knot <em>x</em> = 10; it is changing from -3 to 0, so by 3</li>
</ul>
<p>The two parametrisations (obviously) give identical predicted values:</p>
<pre><code>all.equal( fitted(m1), fitted(m2) )
## [1] TRUE
</code></pre>
<p>graphically</p>
<pre><code>fig +
  geom_smooth(method=&quot;lm&quot;, formula=formula(m1), se=FALSE) +
  geom_vline(xintercept = c(5, 10), linetype=2)
</code></pre>
<p><a target="_blank" rel="nofollow" href="https://i1.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-lspline_fitted-1.png"><img sizes="(max-width: 300px) 100vw, 300px" alt="" class="wp-image-875" src="https://i1.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-lspline_fitted-1-300x214.png?resize=300%2C214" data-recalc-dims="1"></a></p>
<h2>Knots at <code>n</code> equal-length intervals</h2>
<p>Function <code>elspline()</code> sets the knots at points dividing the range of <code>x</code> into <code>n</code> equal length intervals.</p>
<pre><code>m3 &lt;- lm(y ~ elspline(x, 3), data=d)
knitr::kable(broom::tidy(m3))
</code></pre>
<table>
<thead>
<tr>
<th align="left">term</th>
<th align="right">estimate</th>
<th align="right">std.error</th>
<th align="right">statistic</th>
<th align="right">p.value</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">(Intercept)</td>
<td align="right">3.5484817</td>
<td align="right">0.4603827</td>
<td align="right">7.707678</td>
<td align="right">0.00e+00</td>
</tr>
<tr>
<td align="left">elspline(x, 3)1</td>
<td align="right">0.4652507</td>
<td align="right">0.1010200</td>
<td align="right">4.605529</td>
<td align="right">7.40e-06</td>
</tr>
<tr>
<td align="left">elspline(x, 3)2</td>
<td align="right">-2.4908385</td>
<td align="right">0.1167867</td>
<td align="right">-21.328105</td>
<td align="right">0.00e+00</td>
</tr>
<tr>
<td align="left">elspline(x, 3)3</td>
<td align="right">0.9475630</td>
<td align="right">0.2328691</td>
<td align="right">4.069080</td>
<td align="right">6.84e-05</td>
</tr>
</tbody>
</table>
<p>Graphically</p>
<pre><code>fig +
  geom_smooth(aes(group=1), method=&quot;lm&quot;, formula=formula(m3), se=FALSE, n=200)
</code></pre>
<p><a target="_blank" rel="nofollow" href="https://i1.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-elspline-fitted-1.png"><img sizes="(max-width: 300px) 100vw, 300px" alt="" class="wp-image-874" src="https://i1.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-elspline-fitted-1-300x214.png?resize=300%2C214" data-recalc-dims="1"></a></p>
<h2>Knots at <code>q</code>uantiles of <code>x</code></h2>
<p>Function <code>qlspline()</code> sets the knots at points dividing the range of <code>x</code> into <code>q</code> equal-frequency intervals.</p>
<pre><code>m4 &lt;- lm(y ~ qlspline(x, 4), data=d)
knitr::kable(broom::tidy(m4))
</code></pre>
<table>
<thead>
<tr>
<th align="left">term</th>
<th align="right">estimate</th>
<th align="right">std.error</th>
<th align="right">statistic</th>
<th align="right">p.value</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">(Intercept)</td>
<td align="right">0.0782285</td>
<td align="right">0.3948061</td>
<td align="right">0.198144</td>
<td align="right">0.8431388</td>
</tr>
<tr>
<td align="left">qlspline(x, 4)1</td>
<td align="right">2.0398804</td>
<td align="right">0.1802724</td>
<td align="right">11.315548</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">qlspline(x, 4)2</td>
<td align="right">1.2675186</td>
<td align="right">0.1471270</td>
<td align="right">8.615132</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">qlspline(x, 4)3</td>
<td align="right">-4.5846478</td>
<td align="right">0.1476810</td>
<td align="right">-31.044273</td>
<td align="right">0.0000000</td>
</tr>
<tr>
<td align="left">qlspline(x, 4)4</td>
<td align="right">-0.4965858</td>
<td align="right">0.0572115</td>
<td align="right">-8.679818</td>
<td align="right">0.0000000</td>
</tr>
</tbody>
</table>
<p>Graphically</p>
<pre><code>fig +
  geom_smooth(method=&quot;lm&quot;, formula=formula(m4), se=FALSE, n=200)
</code></pre>
<p><a target="_blank" rel="nofollow" href="https://i1.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-qlspline-fitted-1.png"><img sizes="(max-width: 300px) 100vw, 300px" alt="" class="wp-image-873" src="https://i0.wp.com/bc.bojanorama.pl/wp-content/uploads/2017/04/lspline-qlspline-fitted-1-300x214.png?resize=300%2C214" data-recalc-dims="1"></a></p>
<h1>Installation</h1>
<p>Stable version from CRAN or development version from GitHub with</p>
<pre><code>devtools::install_github(&quot;mbojan/lspline&quot;, build_vignettes=TRUE)
</code></pre>
<h1>Acknowledgements</h1>
<p>Inspired by Stata command <code>mkspline</code> and function <code>ares::lspline</code> from Junger &amp; Ponce de Leon (2011). As such, the implementation follows Greene (2003), chapter 7.5.2.</p>
<ul>
<li>Greene, William H. (2003) <em>Econometric analysis</em>. Pearson Education</li>
<li>Junger &amp; Ponce de Leon (2011) <em><code>ares</code>: Environment air pollution epidemiology: a library for timeseries analysis</em>. R package version 0.7.2 retrieved from CRAN archives.</li>
</ul>
<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://bc.bojanorama.pl/2017/04/linear-splines-with-convenient-parametrisations/"> R – Brokering Closure</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 title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/DGH_MEJIJmI"></a></div>