A few cheap shotsRandom thoughts, code snippets, and a trail of internet breadcrumbs.
http://atyre2.github.io/
Thu, 23 Feb 2017 19:27:54 +0000Thu, 23 Feb 2017 19:27:54 +0000Jekyll v3.3.1What's the best way to implement the logistic model in R?<p>I’m teaching my population dynamics class using R for the first time. I want the students to use a simple logistic population model to make predictions about how population size will respond to different management actions. So, I need to figure out the best way to implement a discrete time, logistic growth model in R.</p>
<p>EDIT: I’ve added some more thoughts based on twitter discussions with @pixxpih. I also added a bit of discussion of Henry Steven’s implementation in <a href="http://www.springer.com/life+sciences/ecology?SGWID=0-10034-0-0-0"><em>A primer of Ecology with R</em></a>.</p>
<p>I have students think through the logistic model with graphs of per capita birth and death rates. I don’t expect them to be able to write a function for the model from scratch, so I’m going to give them the code. I’m putting it in a function instead of just doing a for loop in a script to facilitate using functional programming tools (e.g. <code class="highlighter-rouge">purrr</code>). I want the function to return a <code class="highlighter-rouge">data.frame</code> ready for plotting by <code class="highlighter-rouge">ggplot2</code>. Here is the function I’ve come up with. If anyone is aware of an implementation of this model I’d love to hear about it!<sup id="fnref:allthecode"><a href="#fn:allthecode" class="footnote">1</a></sup></p>
<p>We will use the form of the logistic that uses explicit birth and death rates:</p>
<script type="math/tex; mode=display">N_{t+1} = N_t + (b_0 + b_1 N_t) N_t - (d_0 + d_1 N_t) N_t</script>
<p>This model will have 5 parameters: <em>b_0, b_1, d_0, d_1, N_0</em> as well as vector of times.</p>
<div class="language-r highlighter-rouge"><pre class="highlight"><code><span class="n">logisticpop</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">N</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">b_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1.25</span><span class="p">,</span><span class="w">
</span><span class="n">b_1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">-0.01</span><span class="p">,</span><span class="w">
</span><span class="n">d_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.5</span><span class="p">,</span><span class="w">
</span><span class="n">d_1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.005</span><span class="p">){</span><span class="w">
</span><span class="n">N</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">vector</span><span class="p">(</span><span class="s2">"numeric"</span><span class="p">,</span><span class="w"> </span><span class="n">length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">t</span><span class="p">))</span><span class="w">
</span><span class="n">N</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">N</span><span class="m">0</span><span class="w"> </span><span class="c1"># first entry in vector is initial population size
</span><span class="w"> </span><span class="n">last_t</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">N</span><span class="p">)</span><span class="w">
</span><span class="c1"># these next lines will cause warnings if
</span><span class="w"> </span><span class="c1"># b is not either length 1 or last_t
</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">b_0</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">last_t</span><span class="p">)</span><span class="w"> </span><span class="n">b_0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="n">b_0</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="o">=</span><span class="n">last_t</span><span class="p">)</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">b_1</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">last_t</span><span class="p">)</span><span class="w"> </span><span class="n">b_1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="n">b_1</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="o">=</span><span class="n">last_t</span><span class="p">)</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">d_0</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">last_t</span><span class="p">)</span><span class="w"> </span><span class="n">d_0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="n">d_0</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="o">=</span><span class="n">last_t</span><span class="p">)</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">d_1</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">last_t</span><span class="p">)</span><span class="w"> </span><span class="n">d_1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="n">d_1</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="o">=</span><span class="n">last_t</span><span class="p">)</span><span class="w">
</span><span class="c1"># Now we "loop" and calculate N for each time
</span><span class="w"> </span><span class="c1"># notice that the code is *exactly* like the equation
</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">seq_along</span><span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="o">-</span><span class="n">last_t</span><span class="p">])){</span><span class="w">
</span><span class="n">N</span><span class="p">[</span><span class="n">i</span><span class="m">+1</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">N</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="m">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">b_0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b_1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="n">N</span><span class="p">[</span><span class="n">i</span><span class="p">])</span><span class="w"> </span><span class="o">-</span><span class="w">
</span><span class="p">(</span><span class="n">d_0</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">d_1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="n">N</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">data.frame</span><span class="p">(</span><span class="n">t</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">b_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b_0</span><span class="p">,</span><span class="w">
</span><span class="n">b_1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b_1</span><span class="p">,</span><span class="w">
</span><span class="n">d_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">d_0</span><span class="p">,</span><span class="w">
</span><span class="n">d_1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">d_1</span><span class="p">,</span><span class="w">
</span><span class="n">N</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">N</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
</div>
<div class="language-r highlighter-rouge"><pre class="highlight"><code><span class="n">M</span><span class="m">1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">logisticpop</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="o">:</span><span class="m">20</span><span class="p">)</span><span class="w">
</span><span class="n">ggplot</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">1</span><span class="p">)</span><span class="w">
</span></code></pre>
</div>
<p><img src="/figure/whats-the-best-logistic-model/unnamed-chunk-1-1.png" alt="plot of chunk unnamed-chunk-1" /></p>
<p>This structure gives me the ability to predict the effects of management actions by providing a vector of birth or death rate parameters. For example, if habitat quality starts to degrade at t = 10, then the intercept of the per capita birth rate could be decreasing.</p>
<div class="language-r highlighter-rouge"><pre class="highlight"><code><span class="n">b_0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">1.25</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="o">=</span><span class="m">10</span><span class="p">),</span><span class="n">seq</span><span class="p">(</span><span class="m">1.2</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="m">-0.025</span><span class="p">,</span><span class="w"> </span><span class="n">length</span><span class="o">=</span><span class="m">11</span><span class="p">))</span><span class="w">
</span><span class="n">M</span><span class="m">2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">logisticpop</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="o">:</span><span class="m">20</span><span class="p">,</span><span class="w"> </span><span class="n">b_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b_0</span><span class="p">)</span><span class="w">
</span><span class="n">ggplot</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="s2">"red"</span><span class="p">)</span><span class="w">
</span></code></pre>
</div>
<p><img src="/figure/whats-the-best-logistic-model/unnamed-chunk-2-1.png" alt="plot of chunk unnamed-chunk-2" /></p>
<p>If I want a stochastic model with environmental stochasticity, I simply provide a vector drawn from random numbers.</p>
<div class="language-r highlighter-rouge"><pre class="highlight"><code><span class="n">b_0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">rnorm</span><span class="p">(</span><span class="m">21</span><span class="p">,</span><span class="w"> </span><span class="m">1.25</span><span class="p">,</span><span class="w"> </span><span class="m">0.2</span><span class="p">)</span><span class="w">
</span><span class="n">M</span><span class="m">3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">logisticpop</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="o">:</span><span class="m">20</span><span class="p">,</span><span class="w"> </span><span class="n">b_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b_0</span><span class="p">)</span><span class="w">
</span><span class="n">ggplot</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="s2">"red"</span><span class="p">)</span><span class="w">
</span></code></pre>
</div>
<p><img src="/figure/whats-the-best-logistic-model/unnamed-chunk-3-1.png" alt="plot of chunk unnamed-chunk-3" /></p>
<p>Now I want 20 replicates of that model. This is one place where functional programming comes in. I’ll make a list of b_0 vectors, then use <code class="highlighter-rouge">map_df()</code> to call my model with each of those vectors and return the results as a dataframe.</p>
<div class="language-r highlighter-rouge"><pre class="highlight"><code><span class="n">inputs</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">map</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">21</span><span class="p">,</span><span class="w"> </span><span class="n">times</span><span class="o">=</span><span class="m">20</span><span class="p">),</span><span class="w"> </span><span class="n">rnorm</span><span class="p">,</span><span class="w"> </span><span class="n">mean</span><span class="o">=</span><span class="m">1.25</span><span class="p">,</span><span class="w"> </span><span class="n">sd</span><span class="o">=</span><span class="m">0.2</span><span class="p">)</span><span class="w">
</span><span class="n">M</span><span class="m">4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">map_df</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span><span class="w"> </span><span class="o">~</span><span class="n">logisticpop</span><span class="p">(</span><span class="n">N</span><span class="m">0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span><span class="o">:</span><span class="m">20</span><span class="p">,</span><span class="w"> </span><span class="n">b_0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">.x</span><span class="p">),</span><span class="w"> </span><span class="n">.id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"rep"</span><span class="p">)</span><span class="w">
</span><span class="n">ggplot</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">group</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rep</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">4</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="s2">"red"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">N</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">M</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">2</span><span class="p">)</span><span class="w">
</span></code></pre>
</div>
<p><img src="/figure/whats-the-best-logistic-model/unnamed-chunk-4-1.png" alt="plot of chunk unnamed-chunk-4" /></p>
<p>So that’s my best shot. So far it seems to be working for students to give them the function and have the manipulate the parameters. But lot’s of time left in the semester. Their next assignment is to use a similar function to predict population growth in their flour beetle (<em>Tribolium confusum</em>) populations.</p>
<p>Henry Steven’s <code class="highlighter-rouge">dlogistic()</code> function is very similar, but doesn’t accept vector valued arguments, and doesn’t return a <code class="highlighter-rouge">data.frame</code>. That’s largely cosmetic, so the basic idea of packaging the model inside a function to use functional programming tools has occurred to at least one other person!</p>
<p>@pixxpih suggested separating the <em>iteration</em> part of the function from the <em>transition</em> part of the function. Karline Soetaert and Peter Hermann do something like this in their book <a href="http://www.springer.com/life+sciences/ecology?SGWID=0-10034-0-0-0"><em>A practical guide to ecological modelling</em></a>. They just used a naked for loop in a script wrapped around the one step transition function. If this worked out well, I think the iteration function could be re-used for different models, reducing the burden on the students to learn new things, and making it clear that iteration is the general task, while the details of the individual model change depending on the task we have. To make that work with functions that parameterize models in different ways I would need to use <code class="highlighter-rouge">...</code> arguments, and every time I’ve tried to do that it’s ended badly!</p>
<div class="footnotes">
<ol>
<li id="fn:allthecode">
<p>All the code for this post, including that not shown, <a href="https://github.com/atyre2/atyre2.github.io/raw/master/_drafts/whats-the-best-logistic-model.Rmd">can be found here</a>. <a href="#fnref:allthecode" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Wed, 22 Feb 2017 00:00:00 +0000
http://atyre2.github.io/2017/02/22/whats-the-best-logistic-model.html
http://atyre2.github.io/2017/02/22/whats-the-best-logistic-model.htmlteachingmodelsAccounting for exposure days<p>Every year I suggest a student use Terry Shaffer’s log exposure models
for nest survival (Shaffer 2004). And every year I spend hours trying to
figure out why the code in the help section of <code class="highlighter-rouge">?family</code> doesn’t work.
So this year I’m writing it down.</p>
<p>Irregular data collection intervals are an annoying feature of much
ecological data. Nest survival data in particular. Try monitoring the
fate of dozens or hundreds of nests scattered across a large landscape
and make sure you always visit every one every 3 days. There is always
going to be slop[1]. Ignoring that slop leads to biased estimates of
survival. What we really want is the daily survival rate <em>p</em>, but when
the intervals vary what we are observing is <em>p</em><sup><em>d</em></sup> where <em>d</em>
is the number of days in the interval.</p>
<p>Harold Mayfield recognized this problem (Mayfield 1975, and references
therein), and his estimator is the classic way to deal with this
problem. Coming up with alternatives and improvements to the Mayfield
estimator is a cottage industry among statisticians! Terry Schaffer
recognized that a simple change to the link function in a binomial glm
model achieved the same goal, and gives us access to many powerful
modeling tools. For example, Max Post van der Burg (2010) used the
modified link function together with generalized additive models to
identify periods of increased risk of nest parasitism.</p>
<p>Terry used SAS in his paper, but the good R fairies provided code for a
log exposure day link function in the examples for <code class="highlighter-rouge">family()</code>. Except
the code doesn’t work.</p>
<div class="highlighter-rouge"><pre class="highlight"><code>logexp_bad <- function(days = 1)
{
linkfun <- function(mu) qlogis(mu^(1/days))
linkinv <- function(eta) plogis(eta)^days
mu.eta <- function(eta) days * plogis(eta)^(days-1) * binomial()$mu_eta # this is the error
valideta <- function(eta) TRUE
link <- paste0("logexp(", days, ")")
structure(list(linkfun = linkfun, linkinv = linkinv,
mu.eta = mu.eta, valideta = valideta, name = link),
class = "link-glm")
}
# simulate some data with different exposure days
library(tidyverse)
set.seed(30894879)
abc <- data.frame(x=rnorm(100),
days=sample(1:5, 100, replace=TRUE))
abc <- mutate(abc,
p=plogis(x),
p_days=p^days,
y = rbinom(100, 1, p_days))
glm(y~x, data=abc, family=binomial(link=logexp_bad(days=abc$days))) # fails
## Error in glm.fit(x = structure(c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, : NAs in d(mu)/d(eta)
</code></pre>
</div>
<p>The problem is subtle, because it doesn’t cause anything to fail in an
obvious way, even when you try to use it. The definition of the function
<code class="highlighter-rouge">mu.eta()</code> includes a call to <code class="highlighter-rouge">binomial()</code> to extract the <code class="highlighter-rouge">mu_eta</code>
component, except <em>it doesn’t exist</em> so <code class="highlighter-rouge">mu.eta()</code> ends up NULL. The
correct component name is <code class="highlighter-rouge">mu.eta</code>, so:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>logexp <- function(days = 1)
{
linkfun <- function(mu) qlogis(mu^(1/days))
linkinv <- function(eta) plogis(eta)^days
mu.eta <- function(eta) days * plogis(eta)^(days-1) * binomial()$mu.eta(eta)
valideta <- function(eta) TRUE
link <- paste0("logexp(", days, ")")
structure(list(linkfun = linkfun, linkinv = linkinv,
mu.eta = mu.eta, valideta = valideta, name = link),
class = "link-glm")
}
summary(glm(y~x, data=abc, family=binomial(link=logexp(days=abc$days)))) # works
##
## Call:
## glm(formula = y ~ x, family = binomial(link = logexp(days = abc$days)),
## data = abc)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.67072 -0.67665 -0.26660 0.09403 2.40338
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.1210 0.2505 -0.483 0.629
## x 1.1601 0.2608 4.449 8.63e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 112.467 on 99 degrees of freedom
## Residual deviance: 76.386 on 98 degrees of freedom
## AIC: 80.386
##
## Number of Fisher Scoring iterations: 6
</code></pre>
</div>
<p>and that works. The estimated slope should not be different from 1 on
the log - odds scale, and it is, so that makes me happy too.</p>
<h1 id="references">References</h1>
<p>Burg, Max Post Van Der, Larkin A Powell, and Andrew J Tyre. 2010.
“Finding the Smoothest Path to Success: Model Complexity and the
Consideration of Nonlinear Patterns in Nest-Survival Data.” <em>The Condor</em>
112 (3). University of California Press: 421–31.</p>
<p>Mayfield, Harold F. 1975. “Suggestions for Calculating Nest Success.”
<em>The Wilson Bulletin</em>. JSTOR, 456–66.</p>
<p>Shaffer, Terry L. 2004. “A Unified Approach to Analyzing Nest Success.”
<em>The Auk</em> 121 (2): 526–40.</p>
<p>[1] All the code for this post, including that not shown, <a href="https://github.com/atyre2/atyre2.github.io/raw/master/_drafts/custom_link.Rmd">can be found
here</a>.</p>
Thu, 02 Feb 2017 00:00:00 +0000
http://atyre2.github.io/2017/02/02/custom_link.html
http://atyre2.github.io/2017/02/02/custom_link.htmlstatisticsRecologyStatistics training<p><a href="https://twitter.com/am_anatiala/status/818453264190603264">This tweet</a> sparked a host of comments about the need for R prep courses, as well as some great gifs! This is <a href="https://atyre2.github.io/data-management">my R prep course</a>, with a few other computational skills thrown in for good measure.</p>
Tue, 10 Jan 2017 00:00:00 +0000
http://atyre2.github.io/2017/01/10/statistics-training.html
http://atyre2.github.io/2017/01/10/statistics-training.htmlhigher edcomputationWhat about that 1970's ice age?<p>A good friend posted <a href="http://www.christianpost.com/news/global-cooling-why-we-need-politics-out-of-climate-change-science-167173/">this link</a>
to FB. I read the post, did some background reading, and debated whether to write this post or not. I’ve been writing it in my head anyway, so time to get it out!</p>
<p>I’ll preface my remarks by pointing out that I am not a climate scientist. I am an educated observer. Regardless, Stephen spent many hours explaining conservatism and the bible to me, so I owe it to him to try explaining this! I do care about climate change, both personally and as a driver of ecological systems which ARE my expertise.</p>
<p>In the article Bill Mundhausen makes three statements worth thinking about.</p>
<ol>
<li>“Those of you who were alive in the 70’s may remember articles in Time Magazine warning the world about an impending ice age.”</li>
<li>“The potential warming effects by human activity affecting the biosphere may be completely dwarfed by changes in heat and magnetic wind from the sun that solar scientists study.”</li>
<li>“… the unusual warmth of the previous five months was the short term effect of an unusually strong El Niño, not the continuation of long-term, human-induced global warming.”</li>
</ol>
<p>Eventually I’ll go through each of these individually. This post will just address the first one.</p>
<h1 id="70s-ice-age-scare">70’s Ice Age scare</h1>
<p>This is something I’d heard before but not pursued. This statement is often thrown about as evidence that climate scientists don’t know what they’re talking about, or that they change their minds to suit the prevailing political climate, or that things go up and down anyway so why worry?
It’s true that <a href="http://data.giss.nasa.gov/gistemp/graphs/graph_data/Global_Mean_Estimates_based_on_Land_and_Ocean_Data/graph.png">the global temperature trend flattened out or even decreased during the middle of the 20th century</a>. So did that have climate science predicting an ice age? This time I resolved to figure out what was going on.</p>
<p>There is an <em>awesome</em> collection of scanned news articles <a href="https://stevengoddard.wordpress.com/1970s-ice-age-scare/">here</a>, and a similar list with references <a href="http://www.populartechnology.net/2013/02/the-1970s-global-cooling-alarmism.html">here</a>. With a couple exceptions on the first page, these are all media stories, not peer-reviewed publications. A new ice-age made good headlines at least! What were scientists writing at the time? There’s a good summary <a href="https://www.skepticalscience.com/ice-age-predictions-in-1970s-intermediate.htm">here</a>, including a reference to a peer-reviewed review of the science at the time. Between 1965 and 1979 7 published articles predicted continued cooling. But 42 articles predicted warming! And over 20 articles predicted no systematic change would occur. Scientists were genuinely uncertain about the future of the climate at the time.</p>
<p>Part of the reason for the uncertainty had to do with a lack of understanding about how two distinct human drivers of climate would interact with each other. On the one hand there were the first decades of evidence that atmospheric <script type="math/tex">CO_2</script> was increasing. On the other hand there were observations of dramatic increases in aerosol emmisions, particularly <script type="math/tex">SO_2</script>. Remember acid rain? The same chemicals responsible for acid rain also have a cooling effect on the atmosphere, and those emissions were dramatically increasing in the early 70’s. So the scientific uncertainty reflected these competing drivers. <script type="math/tex">CO_2</script> warms the lower atmosphere, while <script type="math/tex">SO_2</script> cools it. The <em>scientific</em> articles predicting a new ice age were forecasting the impacts of continued increases in <script type="math/tex">SO_2</script> (<a href="https://stevengoddard.files.wordpress.com/2014/02/screenhunter_127-feb-04-04-44.gif">see this scan</a> ). Humanity acted to limit <script type="math/tex">SO_2</script> emissions which began declining around 1980. We acted on <script type="math/tex">SO_2</script> because some impacts were more obvious (decreasing pH in surface waters), and the economic costs smaller than reducing <script type="math/tex">CO_2</script> emissions (although still substantial).</p>
<p>So overall the “ice age scare” was a media construction at a time when political discussions were focused on <script type="math/tex">SO_2</script> emissions. It would be interesting to see if those debates stimulated climate scientists to focus more on building long term data records, and to use those data to measure the effects of human and natural drivers on climate change. The available data in the 1970’s were quite limited (<a href="https://stevengoddard.wordpress.com/1970s-ice-age-scare/">see figures at the top</a> ). At that time climate scientists also lacked the most powerful tool for understanding the interacting effects of climate drivers: computational models of the global climate system.</p>
Thu, 08 Dec 2016 00:00:00 +0000
http://atyre2.github.io/2016/12/08/ice_age_1970s.html
http://atyre2.github.io/2016/12/08/ice_age_1970s.htmlclimatephilosophySlow Science<p>I’ve heard a number of calls for faculty to slow down, think, and write. <a href="http://www.chronicle.com/article/Helping-Professors-Find-Time/238569">This is the latest</a>, by Allison Adams from Emory University. I’m trying, but it’s hard.</p>
<p>Why slow down? Essentially, thinking is hard work. In the rat-race for funding and bums on seats it is easy to forget that the essential fuel of it all is new ideas. New ideas are my rate limiting step<sup id="fnref:allthecode"><a href="#fn:allthecode" class="footnote">1</a></sup>.</p>
<p>The notion of slowing down is powerfully attractive when my schedule fills up with classes, administrative meetings, and deadlines of all sorts. The pace of my days accelerates dramatically during the semester. Every week comes with multiple deadlines. Get the minutes out for the last Undergraduate Committee meeting. Prepare the handouts for tomorrow’s class. Grade the homeworks from last week. Finish that review. I didn’t become an academic because of my good time management skills. But I sure need them now.</p>
<p>Slowing down is the wrong metaphor. What’s needed, at least for me, is a narrower scope. Rather than chase every <a href="https://shiny.rstudio.com/">shiny thing</a> I come across I need to be laser focused on a few things. As my colleague <a href="http://larkinpowell.wixsite.com/larkinpowell">Larkin Powell</a> keeps saying, increased focus means saying no. Alot.</p>
<p>Take blogging as an example. Looking at my posts, <a href="https::/github.com/atyre2/atyre2.github.io/">and especially the unpublished ones</a>, I’ve got posts on philosophy, statistics, coding, climate, theoretical ecology, teaching, and management of higher education. That’s not focus. No wonder I’m not having original thoughts.</p>
<p>My ecological statistics course is another source of scatterbrainedness. So often I’m talking with a student about their project and I say “you know, your data really needs METHODX”. Almost immediately</p>
<p><img src="http://media.tumblr.com/deaecc0e466e47a7ea77167381961a69/tumblr_inline_mmxb96FeXx1qz4rgp.gif" alt="" /></p>
<p>I don’t know how to do METHODX, but now I feel like I
need to figure it out, because <em>it is</em> in fact, the
best approach for that student’s data. I learn alot
every time I teach that course. Often students include me on papers. But … no original ideas.</p>
<p>The solution, according to Adams, is to create spaces and times where faculty can get together to write and think. A shared spacetime holds faculty accountable to the group and possibly creates new interdisciplinary connections. I like this idea alot. At UNL the <a href="http://peerreview.unl.edu/">Peer Review of Teaching project</a> creates this shared spacetime for faculty to think about pedagogy and document the scholarship of learning. It was a fantastic experience. Doing it with a research focus would be a great idea.</p>
<p>I am also a skeptic. The absolute easiest way to learn about other disciplines is to attend our weekly department seminar. In our unit faculty can’t find even one hour a week to attend unless the seminar topic is directly related to their work. We constantly try new ways to incentivize attendance. Bring in big name speakers less often is the latest effort. A previous director tried that too, and it didn’t work then either.</p>
<p>For me, writing isn’t really the problem. I can write. But if I don’t have an original idea I don’t have much to write about. I need to take time to read. To write computer code. To do math. And, I need to narrow the focus of those activities so that actual results follow.</p>
<p>Hm. Might be a good spot to stop blogging and get ready for class.</p>
<div class="footnotes">
<ol>
<li id="fn:allthecode">
<p>All the code for this post, including that not shown, <a href="https::/github.com/atyre2/atyre2.github.io/raw/master/_drafts/slow_science.Rmd">can be found here</a>. <a href="#fnref:allthecode" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Wed, 07 Dec 2016 00:00:00 +0000
http://atyre2.github.io/2016/12/07/slow_science.html
http://atyre2.github.io/2016/12/07/slow_science.htmlHigher EdDiversity matters. Everywhere.<p>Yesterday a colleague posted a link to <a href="http://thefederalist.com/2016/11/18/liberals-should-stop-ranting-and-seek-out-silent-trump-voters-like-me/">an article in The Federalist</a> calling out liberals for not listening. I think the author has a point.</p>
<p>The anonymous author voted for Trump. She’s afraid of the reaction from liberals that surround her in her professional career. Everywhere she sees liberals painting Trump voters with a broad brush: deplorable. The liberals around her repeat the mistake made by the media, commentators, and political campaigns over the past two years: <a href="https://en.wikipedia.org/wiki/Ecological_fallacy">the ecological fallacy</a>. Both sides of politics made this mistake. But our anonymous Trump supporter is repeating it.</p>
<p>Over and over I saw headlines, blogs, videos, tweets and facebook comments that said things like “Racism is associated with Trump support”. Every single one of these articles was based on poll results that ended up reporting an average level of X (substitute racism, misogyny, education, income) for probable Trump voters compared with probable Clinton voters. The fallacy arises when this average, an attribute of the entire population of Trump voters is assumed to apply to all of them as individuals. I agree with Anonymous that this mistake ends up making conversation difficult, if not impossible.</p>
<p>Reflecting on her time in graduate school, Anonymous says</p>
<blockquote>
<p>We want to stop feeling silenced and condemned for having alternative viewpoints. We want to articulate thought-provoking, uncomfortable truisms, and not be told, “you can’t say that,” without even a modest effort at explaining why.</p>
</blockquote>
<p>I’ve heard this sentiment from other conservative colleagues. I think it is a terrible outcome for universities to reject ideological diversity across disciplines. We celebrate diversity in race, gender, and ecosystems. Why not diversity of political opinions?</p>
<p>At the same time, painting all liberals as people who insist “you can’t say that” without explaining why is the ecological fallacy all over again. Yes, there are people who insist I shouldn’t say “Gay people shouldn’t get married.”, without really thinking through <em>why</em> I shouldn’t say that. Some liberals <em>have</em> thought through why. But most people don’t have the energy or time to work out the details of moral reasoning. They buy a worldview as a package. Conservatives do this too – it is simply a consequence of our bounded rationality. Expecting everyone on both sides of the political spectrum to be deeply conversant in moral reasoning is, well, unreasonable.</p>
<p>It is uncomfortable to be somewhere people don’t share your political views. In the gym yesterday I overheard “You’re too nice to be a liberal!”. As I sweated away on the bike I wondered what she would think of an atheist immigrant liberal. “If you’re not with God you’re with Satan!” Ulp. Good thing I kept my mouth shut. I get it. Having different thoughts from the people around you is uncomfortable. Universities should do better.</p>
<p>Anonymous says that her and her husband</p>
<blockquote>
<p>… endeavor to get our points across by subtly questioning our opponents’ assumptions, while letting them take things to their logical conclusion if they are open-minded enough to do so.</p>
</blockquote>
<p>Why is taking this approach a bad thing? It’s brilliant! Examining our base assumptions about moral reasoning is a fantastic way to build a deeper understanding of the other. I had many great conversations with a conservative, deeply religious colleague that took this form. I learned a great deal.</p>
<p>In conclusion Anonymous writes</p>
<blockquote>
<p>When confronting people who disagree with you, the best tactic is to prove why they’re wrong instead of shutting them up. Have enough faith in your own arguments to welcome dissenting opinions; if your ideas are truly superior, it will show. No need to get emotional, indignant, or defensive.</p>
</blockquote>
<p>I agree with the last sentence, but disagree that the goal is to “prove why they are wrong”. At best, you can reveal that someone’s base assumptions are different from yours, or that their logic is inconsistent. But expecting to change those assumptions, those bedrock beliefs, is unreasonable. Nonetheless, avoiding the ecological fallacy is a great place to start.</p>
Sun, 27 Nov 2016 00:00:00 +0000
http://atyre2.github.io/2016/11/27/idealogical_diversity.html
http://atyre2.github.io/2016/11/27/idealogical_diversity.htmlpoliticsTesting disqus comments<p>At a reader’s request I’m attempting to add disqus comments to my blog posts. Ignore this post!</p>
<p>This is just to see if comments block will show up if I make a new post. Because following the default directions isn’t cutting it …<sup id="fnref:allthecode"><a href="#fn:allthecode" class="footnote">1</a></sup></p>
<div class="footnotes">
<ol>
<li id="fn:allthecode">
<p>All the code for this post, including that not shown, <a href="https::/github.com/atyre2/atyre2.github.io/raw/master/_drafts/testing_disqus.Rmd">can be found here</a>. <a href="#fnref:allthecode" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Fri, 25 Nov 2016 00:00:00 +0000
http://atyre2.github.io/2016/11/25/testing_disqus.html
http://atyre2.github.io/2016/11/25/testing_disqus.htmlkeyword1keyword2Statistical training in ecology<p><a href="http://onlinelibrary.wiley.com/doi/10.1002/ecs2.1394/abstract">This article</a> made the rounds of twitter recently. I agree. There is a mismatch between statistical practice and training. Almost the first thing I did was flip to the appended data and see how they categorized UNL. I was relieved to see that we have a course “beyond linear models”; mine!</p>
<p>The real question is what to do about this mismatch, if anything. Touchon and McCoy “… strongly believe that all professional ecologists should be able to understand, interpret, evaluate, and implement the approaches that are clearly becoming the norm in our field …”. Understand and interpret, yes. Evaluate, ideally, but I’m not so convinced. Implement? These methods are increasingly complex, and I think it is unreasonable to think every ecologist will be an expert in data analysis. It’s entirely reasonable to collaborate with an expert to get the implementation done. If you’re an author on a paper you should be able to explain what was done and why, even if you couldn’t implement it yourself<sup id="fnref:caveat"><a href="#fn:caveat" class="footnote">1</a></sup>. That’s a much lower bar.</p>
<p>Here’s the thing. Time is finite. As a PhD student in America you might take 2 courses in statistics, or maybe 3. A few might take enough to get a minor or even a MSc in statistics alongside their PhD. Is 3 courses enough to reach the standard set by Touchon and McCoy? For a small number of the students I’ve taught, it is. For most it isn’t. And most, if not all, of those would struggle to complete additional coursework in statistics because they lack required background in calculus and matrix algebra.</p>
<p>What’s more important to being an ecologist? Having a solid and broad understanding of your subdiscipline so you know what to measure and what hypotheses to test, or being good at R programming? A few might be able to do both, but I believe many can’t or won’t. The former is more important than you think. The first step in developing an information theoretic analysis is to define the model set. You <em>can’t</em> do this effectively if you don’t know what others have found, or what hypotheses should be tested. The ecology matters.</p>
<p>So what statistics courses should we expect a PhD student to take? The structure I’m currently thinking of looks like this:</p>
<p>0) A course in data collection, entry, management and visualization.</p>
<p>1) An introductory statistics course – hypothesis tests, linear regression, ANOVA.</p>
<p>2) A course beyond linear models that reinforces the core concepts, introduces a range of approaches to inference and provides lots and lots of practice at interpreting and evaluating.</p>
<p>3) Time permitting, one additional course focused on a particular techique (e.g. multivariate statistics, mark recapture, distance sampling) relevant to the student’s research.</p>
<p>The top of my list is something that exists in no PhD program anywhere, I bet. Well, there are exceptions<sup id="fnref:exceptions"><a href="#fn:exceptions" class="footnote">2</a></sup>. But <em>every</em> PhD student collects data. And generally they have no idea what to do with it. So stuff gets lost, mangled, errors creep in and are not detected, etc. In my course students do a project analysing their own data. I spent the vast majority of the time helping students rearrange their data from a mangled spreadsheet into something useful for analysis. In response I’ve developed a 1 credit hour <a href="http://atyre2.github.io/2016-01-11-Lincoln/">semester long course borrowing from Software Carpentry</a>. I think this set of skills is both critical and not difficult to acquire. Even <a href="https://dynamicecology.wordpress.com/2016/08/22/ten-commandments-for-good-data-management/">Brian McGill agrees we need to think about this more</a>, although he stops short of recommending we teach this.</p>
<p>I’ve spent a great deal of time working on my “beyond the linear model” course. It’s now fully online. My vision is that students from anywhere could work through it and come out ready for the third course. I’ve talked with faculty in many departments who <em>want</em> to teach that third course in their specialty. But because the 2nd course doesn’t exist at their university they end up teaching that course instead. Like me. Well, enough! I want to do the best job of that course so that everyone else can send their students there, and then teach the course their students really need. Faculty time is finite too.</p>
<p>Touchon and McCoy actually recommend merging my courses (1) and (2) – or maybe doing away with (1) altogether. My current structure is based on how my course fits in with other offerings at UNL, so maybe a broad rethink of that sequence would be in order. I do think it takes at least two semesters, however you choose to organize them. If you really worked at it, (0) could probably merge into the 2 semester sequence too.</p>
<p>Touchon and McCoy are also a bit down on hypothesis testing. If you looked at the methods I typically use in my papers you might think I’d agree with them entirely. I also devote a lot of time in my course to Information Theoretic approaches and do a bit of Bayesian inference. However, I think the notion of a frequentist hypothesis test is a good way to get students thinking about probability generally. <a href="http://www.zoology.ubc.ca/~whitlock/ABD/teaching/">Whitlock and Schluter’s excellent introductory textbook</a> does this; their first example is a test of proportion data. It’s also possible to improve inferences using NHT by <a href="http://daniellakens.blogspot.com/2016/05/absence-of-evidence-is-not-evidence-of.html">changing the null hypothesis to something interesting</a>. Also, thinking about the probability of extreme values is still useful when doing inference by resampling and indeed, even with Bayesian inference. Sure, there are issues with how ecologists use NHT methods<sup id="fnref:NHTissues"><a href="#fn:NHTissues" class="footnote">3</a></sup>. There are also issues with how ecologists use information theoretic methods<sup id="fnref:AICissues"><a href="#fn:AICissues" class="footnote">4</a></sup>. So let’s not throw the baby out with the bathwater; fix the problems and use the most appropriate methods where you will.</p>
<p>What do you think? Send me an email! Tweet me!</p>
<div class="footnotes">
<ol>
<li id="fn:caveat">
<p>Although, thinking about some papers I’ve been on for this reason, I’m not sure all the authors could explain what was done. <a href="#fnref:caveat" class="reversefootnote">↩</a></p>
</li>
<li id="fn:exceptions">
<p><a href="http://www.datacarpentry.org/semester-biology/">University of Florida</a> and DataCarpentry workshops generally. <a href="#fnref:exceptions" class="reversefootnote">↩</a></p>
</li>
<li id="fn:NHTissues">
<p>For example, <a href="http://warnercnr.colostate.edu/~anderson/PDF_files/TESTING.pdf">Burnham and Anderson</a>, <a href="http://web.wilkes.edu/jeffrey.stratford/files/stephens2005.pdf">Stephens et al</a>, the subset of <a href="https://errorstatistics.com/category/p-values/">Deborah Mayo’s blog posts on p-values</a>, and the <a href="http://www.tandfonline.com/doi/abs/10.1080/00031305.2016.1154108">ASA’s statement on p-values</a> <a href="#fnref:NHTissues" class="reversefootnote">↩</a></p>
</li>
<li id="fn:AICissues">
<p>A growing literature … see <a href="https://www.researchgate.net/publication/280757781_Uninformative_Parameters_and_Model_Selection_Using_Akaike's_Information_Criterion">Todd Arnold’s description of uninformative parameters</a>, <a href="https://www.researchgate.net/publication/267288202_Model_averaging_and_muddled_multimodel_inference">Brian Cade’s takedown of AIC and MMI</a> and even <a href="http://warnercnr.colostate.edu/~anderson/PDF_files/AIC%20Myths%20and%20Misunderstandings.pdf">Burnham and Anderson!</a> <a href="#fnref:AICissues" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Sun, 18 Sep 2016 00:00:00 +0000
http://atyre2.github.io/2016/09/18/Training_need_mismatch.html
http://atyre2.github.io/2016/09/18/Training_need_mismatch.htmlteachingstatisticsShould I use sum-to-zero contrasts?<p>A sum-to-zero contrast codes a categorical variable as deviations from a grand mean. Social scientists use them extensively. Should ecologists?</p>
<p><strong>EDIT</strong> the first version of this post that went up had some bugs in it. Hopefully all fixed now.</p>
<p>More accurately, should I tell my students in Ecological Statistics to use them? Sum-to-zero contrasts are conceptually similar to centering a continuous variable by subtracting the mean from your predictor variable prior to analysis. Discussions of centering often end up conflated with <em>scaling</em>, which is dividing your predictor variable by a constant, usually the standard deviation, prior to analysis. <em>Always scaling</em> covariates prior to regression analysis is controversial advice. See for example <a href="http://andrewgelman.com/2009/07/11/when_to_standar/">Andrew Gelman’s blogpost and comments</a>, or many crossvalidated questions <a href="http://stats.stackexchange.com/q/29781/12258">such as this one</a> which has links to many others. There is a good reference as well as some useful discussion in the comments of <a href="http://stats.stackexchange.com/questions/179732/motivation-to-center-continuous-predictor-in-multiple-regression-for-sake-of-mul">this question</a>. In this post I focus on the effects of sum to zero contrasts for categorical variables and interactions with continuous variables.<sup id="fnref:allthecode"><a href="#fn:allthecode" class="footnote">1</a></sup></p>
<p>Here is my summary of the pros and cons of centering drawn from those references above.<sup id="fnref:CVpost"><a href="#fn:CVpost" class="footnote">2</a></sup></p>
<ul>
<li>Centering continuous variables eliminates collinearity between
interaction and polynomial terms and the individual covariates
that make them up.</li>
<li>Centering does not affect inference about the covariates.</li>
<li>Centering can improve the interpretability of the coefficients in
a regression model, particularly because the intercept
represents the value of the response at the mean of the
predictor variables.</li>
<li>Predicting out of sample data with a model fitted to centered
data must be done carefully because the center of the out of
sample data will be different from the fitted data.</li>
<li>There may be some constant value other than the sample mean
that makes more sense based on domain knowledge.</li>
</ul>
<p>To make the discussion concrete, let me demonstrate with an example of the interaction between a continuous covariate and a categorical one. In the following I refer to the effect of individual covariates outside the interaction as the “simple effect” of that covariate.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">data</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">m</span><span class="m">0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="n">Sepal.Width</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">Sepal.Length</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Species</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="n">summary_m0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">summary</span><span class="p">(</span><span class="n">m</span><span class="m">0</span><span class="p">))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">##
## Call:
## lm(formula = Sepal.Width ~ Sepal.Length * Species, data = iris)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.72394 -0.16327 -0.00289 0.16457 0.60954
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.58301 0.27333 2.133 0.03462 *
## Sepal.Length 0.45005 0.04900 9.185 4.11e-16 ***
## Species1 -1.15244 0.42067 -2.740 0.00693 **
## Species2 0.28914 0.37673 0.767 0.44405
## Sepal.Length:Species1 0.34848 0.08038 4.335 2.72e-05 ***
## Sepal.Length:Species2 -0.13033 0.06553 -1.989 0.04862 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2723 on 144 degrees of freedom
## Multiple R-squared: 0.6227, Adjusted R-squared: 0.6096
## F-statistic: 47.53 on 5 and 144 DF, p-value: < 2.2e-16</code></pre></figure>
<p>The intercept of this model isn’t directly interpretable because it gives the average width at a length of zero, which is impossible. In addition, both the intercept and simple effect of length represent the change in width for only one species, <em>setosa</em>. The default contrast in R estimates coefficients for $k - 1$ levels of a factor. In the simple effect of a factor each coefficient is the difference between the first level (estimated by the intercept), and the named level. In the above, <code class="highlighter-rouge">Speciesversicolor</code> has sepals that are 1.4 mm wider than <em>setosa</em>. The interaction coefficients
such as <code class="highlighter-rouge">Sepal.Length:Speciesversicolor</code> tell us how much the effect of Sepal.Length in <em>versicolor</em> changes from that in <em>setosa</em>. So every mm of sepal length in versicolor increases sepal width by $0.8 - 0.48 = 0.32$ mm.</p>
<p>Maybe a plot will help.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="n">ggplot2</span><span class="p">)</span><span class="w">
</span><span class="n">base_iris</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ggplot</span><span class="p">(</span><span class="n">iris</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Sepal.Length</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Sepal.Width</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">geom_point</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">shape</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Species</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">xlab</span><span class="p">(</span><span class="s2">"Sepal Length [mm]"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ylab</span><span class="p">(</span><span class="s2">"Sepal Width [mm]"</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">broom</span><span class="p">)</span><span class="w">
</span><span class="n">nd</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">expand.grid</span><span class="p">(</span><span class="n">Sepal.Length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="m">-1</span><span class="p">,</span><span class="w"> </span><span class="m">8</span><span class="p">,</span><span class="w"> </span><span class="m">0.1</span><span class="p">),</span><span class="w"> </span><span class="n">Species</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">factor</span><span class="p">(</span><span class="n">levels</span><span class="p">(</span><span class="n">iris</span><span class="o">$</span><span class="n">Species</span><span class="p">)))</span><span class="w">
</span><span class="n">pred.0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">augment</span><span class="p">(</span><span class="n">m</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">newdata</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nd</span><span class="p">)</span><span class="w">
</span><span class="n">base_iris</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">.fitted</span><span class="p">,</span><span class="w"> </span><span class="n">linetype</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Species</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pred.0</span><span class="p">)</span></code></pre></figure>
<p><img src="/figure/sum-to-zero-contrasts/unnamed-chunk-2-1.png" alt="plot of chunk unnamed-chunk-2" /></p>
<p>I did something rather silly looking there because I wanted to see where the curves cross x = 0. That is where the estimates for the intercept and simple effect of species are calculated. The intercept is negative, and the line for <em>setosa</em> crosses x = 0 well below y = 0. The simple effect estimates of Species are both positive, with <em>virginica</em> being larger, and indeed the line for <em>virginica</em> crosses x = 0 at the highest point. Similarly, the simple effect of length is the slope of the line for <em>setosa</em>, and it is larger than the slopes of the other two species because the estimated interactions are both negative. But not centering really makes things ugly for direct interpretation of the estimated coefficients.</p>
<p>Centering the continuous variable gives us</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span><span class="w"> </span><span class="c1">#Stay in the tidyverse!
</span><span class="n">iris</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">iris</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">mutate</span><span class="p">(</span><span class="n">cSepal.Length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Sepal.Length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">Sepal.Length</span><span class="p">))</span><span class="w">
</span><span class="n">m</span><span class="m">1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="n">Sepal.Width</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">cSepal.Length</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Species</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="n">summary_m1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">summary</span><span class="p">(</span><span class="n">m</span><span class="m">1</span><span class="p">))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">##
## Call:
## lm(formula = Sepal.Width ~ cSepal.Length * Species, data = iris)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.72394 -0.16327 -0.00289 0.16457 0.60954
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.21278 0.04098 78.395 < 2e-16 ***
## cSepal.Length 0.45005 0.04900 9.185 4.11e-16 ***
## Species1 0.88386 0.07086 12.473 < 2e-16 ***
## Species2 -0.47240 0.04680 -10.094 < 2e-16 ***
## cSepal.Length:Species1 0.34848 0.08038 4.335 2.72e-05 ***
## cSepal.Length:Species2 -0.13033 0.06553 -1.989 0.0486 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2723 on 144 degrees of freedom
## Multiple R-squared: 0.6227, Adjusted R-squared: 0.6096
## F-statistic: 47.53 on 5 and 144 DF, p-value: < 2.2e-16</code></pre></figure>
<p>Although the coefficients change because now the model estimates the differences between the species at the mean length, the t-statistics for the continuous covariate, including the interaction terms, do not change. The t-statistics for the intercept and simple effect of species do change.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">zapsmall</span><span class="p">(</span><span class="n">summary_m1</span><span class="o">$</span><span class="n">coefficients</span><span class="p">[,</span><span class="w"> </span><span class="m">3</span><span class="p">]</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">summary_m0</span><span class="o">$</span><span class="n">coefficients</span><span class="p">[,</span><span class="w"> </span><span class="m">3</span><span class="p">])</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## (Intercept) cSepal.Length Species1
## 76.26185 0.00000 15.21301
## Species2 cSepal.Length:Species1 cSepal.Length:Species2
## -10.86160 0.00000 0.00000</code></pre></figure>
<p>That’s OK, because they are really testing something quite different from before. Just to confirm that the graph isn’t different.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># remember to center the newdata values by the original mean!
</span><span class="n">nd</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">nd</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">filter</span><span class="p">(</span><span class="n">Sepal.Length</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">4</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">mutate</span><span class="p">(</span><span class="n">cSepal.Length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Sepal.Length</span><span class="w"> </span><span class="o">-</span><span class="w">
</span><span class="n">mean</span><span class="p">(</span><span class="n">iris</span><span class="o">$</span><span class="n">Sepal.Length</span><span class="p">))</span><span class="w">
</span><span class="n">pred.1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">augment</span><span class="p">(</span><span class="n">m</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">newdata</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nd</span><span class="p">)</span><span class="w">
</span><span class="n">base_iris</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">.fitted</span><span class="p">,</span><span class="w"> </span><span class="n">linetype</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Species</span><span class="p">),</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pred.1</span><span class="p">)</span></code></pre></figure>
<p><img src="/figure/sum-to-zero-contrasts/unnamed-chunk-5-1.png" alt="plot of chunk unnamed-chunk-5" /></p>
<p>What happens if we use sum to zero contrasts for species?</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">iris</span><span class="o">$</span><span class="n">szSpecies</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">iris</span><span class="o">$</span><span class="n">Species</span><span class="w">
</span><span class="n">contrasts</span><span class="p">(</span><span class="n">iris</span><span class="o">$</span><span class="n">szSpecies</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">contr.sum</span><span class="p">(</span><span class="m">3</span><span class="p">)</span><span class="w">
</span><span class="n">m</span><span class="m">2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="n">Sepal.Width</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">cSepal.Length</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">szSpecies</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="n">summary_m2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">summary</span><span class="p">(</span><span class="n">m</span><span class="m">2</span><span class="p">))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">##
## Call:
## lm(formula = Sepal.Width ~ cSepal.Length * szSpecies, data = iris)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.72394 -0.16327 -0.00289 0.16457 0.60954
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.21278 0.04098 78.395 < 2e-16 ***
## cSepal.Length 0.45005 0.04900 9.185 4.11e-16 ***
## szSpecies1 0.88386 0.07086 12.473 < 2e-16 ***
## szSpecies2 -0.47240 0.04680 -10.094 < 2e-16 ***
## cSepal.Length:szSpecies1 0.34848 0.08038 4.335 2.72e-05 ***
## cSepal.Length:szSpecies2 -0.13033 0.06553 -1.989 0.0486 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2723 on 144 degrees of freedom
## Multiple R-squared: 0.6227, Adjusted R-squared: 0.6096
## F-statistic: 47.53 on 5 and 144 DF, p-value: < 2.2e-16</code></pre></figure>
<p>I can now directly interpret the intercept as the average width at the average length, averaged over species. Similarly the simple effect of length as the change in width averaged across species. This seems like a very useful set of coefficients to look at, particularly if my categorical covariate has many levels.
You might ask (I did), what do the categorical coefficients mean? They represent deviations from the mean intercept for each species. OK, you say (I did), then where’s species <em>virginica</em>? After much head scratching, the answer is that it is the negative of the <strong>sum</strong> of the other two coefficients.</p>
<p>I just thought of something else. Are those “average” intercept and slope the same as what I would get if I only use <code class="highlighter-rouge">cSepal.Length</code>?</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">m</span><span class="m">3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="n">Sepal.Width</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">cSepal.Length</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="n">summary_m3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">summary</span><span class="p">(</span><span class="n">m</span><span class="m">3</span><span class="p">))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">##
## Call:
## lm(formula = Sepal.Width ~ cSepal.Length, data = iris)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.1095 -0.2454 -0.0167 0.2763 1.3338
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.05733 0.03546 86.22 <2e-16 ***
## cSepal.Length -0.06188 0.04297 -1.44 0.152
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4343 on 148 degrees of freedom
## Multiple R-squared: 0.01382, Adjusted R-squared: 0.007159
## F-statistic: 2.074 on 1 and 148 DF, p-value: 0.1519</code></pre></figure>
<p>Whoa! It is not the same, in fact it is radically different. Totally different conclusion about the “average” effect.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">m</span><span class="m">4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lm</span><span class="p">(</span><span class="n">Sepal.Width</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">cSepal.Length</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">szSpecies</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="n">summary_m4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">summary</span><span class="p">(</span><span class="n">m</span><span class="m">4</span><span class="p">))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">##
## Call:
## lm(formula = Sepal.Width ~ cSepal.Length + szSpecies, data = iris)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.95096 -0.16522 0.00171 0.18416 0.72918
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.05733 0.02360 129.571 < 2e-16 ***
## cSepal.Length 0.34988 0.04630 7.557 4.19e-12 ***
## szSpecies1 0.66363 0.05115 12.974 < 2e-16 ***
## szSpecies2 -0.31976 0.03364 -9.504 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.289 on 146 degrees of freedom
## Multiple R-squared: 0.5693, Adjusted R-squared: 0.5604
## F-statistic: 64.32 on 3 and 146 DF, p-value: < 2.2e-16</code></pre></figure>
<p>This is closer to the conclusion obtained with the interaction model.</p>
<p>I have seen assertions in some papers (particularly from social sciences), that using sum to zero contrasts (also called effects coding, I believe), allows the direct interpretation of lower order terms in an ANOVA table even in the presence of interactions.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">anova</span><span class="p">(</span><span class="n">m</span><span class="m">2</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">doesn</span><span class="err">'</span><span class="n">t</span><span class="w"> </span><span class="n">matter</span><span class="w"> </span><span class="n">which</span><span class="w"> </span><span class="n">model</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="n">use</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## Analysis of Variance Table
##
## Response: Sepal.Width
## Df Sum Sq Mean Sq F value Pr(>F)
## cSepal.Length 1 0.3913 0.3913 5.2757 0.02307 *
## szSpecies 2 15.7225 7.8613 105.9948 < 2.2e-16 ***
## cSepal.Length:szSpecies 2 1.5132 0.7566 10.2011 7.19e-05 ***
## Residuals 144 10.6800 0.0742
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1</code></pre></figure>
<p>If so, in this case I could say “Sepal Width differs significantly between species.” I’m not sure I believe that. The ANOVA table is identical between all 3 models, whether I use sum-to-zero contrasts or not. Why should the interpretation differ if I just change the parameterization of the model?</p>
<p>Explaining treatment contrasts to students is a pain. I’m not sure that these are any easier. I have a few thoughts about the effects of sum-to-zero contrasts and model averaging, but that will have to wait for a different post.</p>
<div class="footnotes">
<ol>
<li id="fn:allthecode">
<p>All the code for this post, including that not shown, <a href="https://github.com/atyre2/atyre2.github.io/raw/master/_drafts/sum-to-zero-contrasts.Rmd">can be found here</a>. <a href="#fnref:allthecode" class="reversefootnote">↩</a></p>
</li>
<li id="fn:CVpost">
<p>This stuff first appeared <a href="http://stats.stackexchange.com/questions/188852/centering-in-the-presence-of-interactions-with-categorical-predictors">as a question on CrossValidated</a>, but received no attention. <a href="#fnref:CVpost" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Sat, 03 Sep 2016 00:00:00 +0000
http://atyre2.github.io/2016/09/03/sum-to-zero-contrasts.html
http://atyre2.github.io/2016/09/03/sum-to-zero-contrasts.htmlrstatsteachingCan you sum the sensitivities?<p>TL;DR No.</p>
<p>I’m going out on a bit of a limb here with that assertion. I don’t have <a href="https://books.google.com/books/about/Matrix_Population_Models.html?id=KZviQwAACAAJ&hl=en">The Gospel According to Caswell</a> close at hand to check. But I think the following argument is sufficient.<sup id="fnref:allthecode"><a href="#fn:allthecode" class="footnote">1</a></sup></p>
<p>This was stimulated by a question to my boss who passed it on to me. Here’s the question:</p>
<blockquote>
<p>Can you sum sensitivities if they are on the same scale (e.g., survival rates)?
I know you can’t sum fecundity and survival sensitive because they are on
different scales, but we were debating today whether you can sum or average
sensitivities on stage transition rates.</p>
</blockquote>
<h2 id="whats-the-sensitivity">What’s the sensitivity?</h2>
<p>In the analysis of structured population models, the sensitivity of a matrix element is just the partial derivative of the population growth rate <script type="math/tex">\lambda</script> with respect to that matrix element. So the question is, does this make any sense?</p>
<script type="math/tex; mode=display">\frac{\partial \lambda}
{\partial a_{ij}} +
\frac{\partial \lambda}
{\partial a_{kl}} = ?</script>
<h2 id="the-total-differential">The total differential</h2>
<p>Think of what’s behind this thing. The population growth rate is a function of the matrix elements, <script type="math/tex">\lambda = f(a_{ij}, a_{kl})</script> and let’s pretend for the moment that there are only two. The change in <script type="math/tex">\lambda</script> caused by changing the inputs to the function can be approximated using the total differential</p>
<script type="math/tex; mode=display">\Delta \lambda \approx \frac{\partial \lambda}
{\partial a_{ij}} \Delta a_{ij} +
\frac{\partial \lambda}
{\partial a_{kl}} \Delta a_{kl}</script>
<p>which gets more accurate as the changes in the matrix elements get small. If
<script type="math/tex">\Delta a_{ij} = \Delta a_{kl} = 1</script>, then this is just the sum of the sensitivities. So summing the sensitivities is the amount <script type="math/tex">\lambda</script> changes if you change the matrix elements by 1 unit. But for survival that makes no sense biologically; survival is always less than 1.</p>
<p>OK, choose <script type="math/tex">\Delta a_{ij}</script> to be something smaller, like, a 1% change. Fine. Guess what? That’s called the elasticity. Those CAN be summed up.</p>
<h2 id="conclusion">Conclusion</h2>
<p>You can sum up the sensitivities, but the result is biologically meaningless. So don’t.</p>
<div class="footnotes">
<ol>
<li id="fn:allthecode">
<p>All the code for this post, including that not shown, <a href="https::/github.com/atyre2/atyre2.github.io/blob/master/_drafts/post-template.Rmd">can be found here</a>. <a href="#fnref:allthecode" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
Fri, 19 Aug 2016 00:00:00 +0000
http://atyre2.github.io/2016/08/19/sum-of-sensitivities.html
http://atyre2.github.io/2016/08/19/sum-of-sensitivities.htmlmodelstructured population