title: counting values after and before change in value, within groups, generating new variables for each unique shift
body: <p>I am looking for a way to, within <code>id</code> groups, count unique occurrences of value shifts in <code>TF</code> in the data data<code>tbl</code>.</p>
  
  <p>I want to count both forward and backwards from when <code>TF</code> changes between <code>1</code> and <code>0</code> or <code>o</code> and <code>1</code>.  The counting is to be stored in a new variable <code>PM##</code>, so that the <code>PM##</code>s holds each unique shift in <code>TF</code>, in both plus and minus. The MWE below leads to an outcome with 7 PM, but my production data can have 15 or more shifts. If a <code>TF</code> values does not change between <code>NA</code>'s I want to mark it <code>0</code>.</p>
  
  <p>This question is similar to <a href="https://stackoverflow.com/questions/46541843/counting-after-and-before-change-in-value-within-groups-generating-new-variabl">a question I previously asked</a>, but the last part about <code>TF</code> standing alone is new. Both <a href="https://stackoverflow.com/users/3817004/uwe">Uwe</a> and <a href="https://stackoverflow.com/a/46871196/1305688">Psidom</a> provided elegant answers to the initial question using <code>data.table</code> <a href="https://stackoverflow.com/a/46558797/1305688">here</a> and using <code>tidyverse</code> <a href="https://stackoverflow.com/a/46871196/1305688">here</a>. <a href="https://stackoverflow.com/questions/46541843/counting-after-and-before-change-in-value-within-groups-generating-new-variabl/46558797#comment83596540_46558797">after conferencing with Uwe</a>, I am posting this slightly modified version of my question.</p>
  
  <blockquote>
    <p>If this question violates any SO policies please let me know and I'll be happy to reopen my initial question or append this an bounty-issue.</p>
  </blockquote>
  
  <p>To illustrate my question with a <em>minimal working example</em>. I have data like this,</p>
  
  <h3>what I have,</h3>
  
  <pre><code># install.packages(c("tidyverse"), dependencies = TRUE)
  library(tibble)
  tbl &lt;- tibble(id = c(rep(10L, 17L), rep(0L, 13L), rep(1L, 10L)), 
         TF = c(NA, NA, 0, NA, 0, NA, 1, 1, 1, 1, 1, NA, 1, 0, 1, 0, 1, NA, 0L, NA, 0L, 
         0L, 1L, 1L, 1L, 0L, 0L, NA, NA, 0L, NA, 0L, 0L, 0L, 1L, 1L, 1L, 0L, NA, 1L))
  tbl %&gt;% print(n=18)
  #&gt; # A tibble: 40 x 2
  #&gt;       id    TF
  #&gt;    &lt;int&gt; &lt;dbl&gt;
  #&gt;  1    10    NA
  #&gt;  2    10    NA
  #&gt;  3    10     0
  #&gt;  4    10    NA
  #&gt;  5    10     0
  #&gt;  6    10    NA
  #&gt;  7    10     1
  #&gt;  8    10     1
  #&gt;  9    10     1
  #&gt; 10    10     1
  #&gt; 11    10     1
  #&gt; 12    10    NA
  #&gt; 13    10     1
  #&gt; 14    10     0
  #&gt; 15    10     1
  #&gt; 16    10     0
  #&gt; 17    10     1
  #&gt; 18     0    NA
  #&gt; # ... with 22 more rows
  </code></pre>
  
  <h3>what I am trying to obtain,</h3>
  
  <pre><code>tblPM &lt;- structure(list(id = c(10L, 10L, 10L, 10L, 10L, 10L, 10L, 10L, 
  10L, 10L, 10L, 10L, 10L, 10L, 10L, 10L, 10L, 0L, 0L, 0L, 0L, 
  0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
  1L, 1L, 1L), TF = c(NA, NA, 0, NA, 0, NA, 1, 1, 1, 1, 1, 
  NA, 1, 0, 1, 0, 1, NA, 0, NA, 0, 0, 1, 1, 1, 0, 0, 
  NA, NA, 0, NA, 0, 0, 0, 1, 1, 1, 0, NA, 1), PM01 = c(NA, 
  NA, 0L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  NA, 0L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -3L, 
  -2L, -1L, 1L, 2L, 3L, NA, NA, NA), PM02 = c(NA, NA, NA, NA, 0L, 
  NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -2L, 
  -1L, 1L, 2L, 3L, NA, NA, NA, NA, NA, NA, NA, NA, NA, -3L, -2L, 
  -1L, 1L, NA, NA), PM03 = c(NA, NA, NA, NA, NA, NA, 0L, 0L, 0L, 
  0L, 0L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -3L, -2L, 
  -1L, 1L, 2L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  0L), PM04 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  -1L, 1L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  NA, NA, 0L, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), PM05 = c(NA, 
  NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -1L, 1L, NA, 
  NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  NA, NA, NA, NA, NA, NA, NA, NA), PM06 = c(NA, NA, NA, NA, NA, 
  NA, NA, NA, NA, NA, NA, NA, NA, NA, -1L, 1L, NA, NA, NA, NA, 
  NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  NA, NA, NA, NA), PM07 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 
  NA, NA, NA, NA, NA, NA, -1L, 1L, NA, NA, NA, NA, NA, NA, NA, 
  NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
  )), .Names = c("id", "TF", "PM01", "PM02", "PM03", "PM04", "PM05", 
  "PM06", "PM07"), class = c("tbl_df", 
  "tbl", "data.frame"), row.names = c(NA, -40L
  ))
  
  
  tblPM %&gt;% print(n=18)  
  #&gt; # A tibble: 40 x 9
  #&gt;       id    TF  PM01  PM02  PM03  PM04  PM05  PM06  PM07
  #&gt;    &lt;int&gt; &lt;dbl&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt; &lt;int&gt;
  #&gt;  1    10    NA    NA    NA    NA    NA    NA    NA    NA
  #&gt;  2    10    NA    NA    NA    NA    NA    NA    NA    NA
  #&gt;  3    10     0     0    NA    NA    NA    NA    NA    NA
  #&gt;  4    10    NA    NA    NA    NA    NA    NA    NA    NA
  #&gt;  5    10     0    NA     0    NA    NA    NA    NA    NA
  #&gt;  6    10    NA    NA    NA    NA    NA    NA    NA    NA
  #&gt;  7    10     1    NA    NA     0    NA    NA    NA    NA
  #&gt;  8    10     1    NA    NA     0    NA    NA    NA    NA
  #&gt;  9    10     1    NA    NA     0    NA    NA    NA    NA
  #&gt; 10    10     1    NA    NA     0    NA    NA    NA    NA
  #&gt; 11    10     1    NA    NA     0    NA    NA    NA    NA
  #&gt; 12    10    NA    NA    NA    NA    NA    NA    NA    NA
  #&gt; 13    10     1    NA    NA    NA    -1    NA    NA    NA
  #&gt; 14    10     0    NA    NA    NA     1    -1    NA    NA
  #&gt; 15    10     1    NA    NA    NA    NA     1    -1    NA
  #&gt; 16    10     0    NA    NA    NA    NA    NA     1    -1
  #&gt; 17    10     1    NA    NA    NA    NA    NA    NA     1
  #&gt; 18     0    NA    NA    NA    NA    NA    NA    NA    NA
  #&gt; # ... with 22 more rows 
  
  identical([some solution], tblPM)
  #&gt; [1] TRUE
  </code></pre>
  
  <p><strong>update w/ <code>microbenchmark</code> 2018-01-24  14:20:18Z</strong>,</p>
  
  <p>Thanks to Fierr and Chris for taking the time to tease out the logic and submit an answer. Inspired my <a href="https://stackoverflow.com/a/46871196/1305688">this setup</a> I've computed a small microbenchmark comparison of thier functions. I put Fierr<code>s answer into the function</code>tidyverse_Fierr()<code>and Chris' answer into</code>dt_Chris()` (if someone want the exact functions please let me know and I'll add them here.</p>
  
  <p>After some minor tweaks they both come out identical when match with <code>tblPM</code>, i.e.</p>
  
  <pre><code>identical(tblPM, tidyverse_Fierr(tbl))
  #&gt; [1] TRUE
  identical(tblPM, dt_Chris(tbl))
  #&gt; [1] TRUE
  </code></pre>
  
  <p>Now to the quick microbenchmark,</p>
  
  <pre><code>df_test &lt;- bind_rows(rep(list(tbl), 111))
  microbenchmark::microbenchmark(tidyverse_Fierr(df_test), dt_Chris(df_test), times = 3*1)
  #&gt; Unit: milliseconds
  #&gt;                      expr      min       mean   median        uq         max neval cld
  #&gt; tidyverse_Fierr(df_test) 19503.366  20171.268 20080.99 20505.219  20929.4489     3   b
  #&gt;        dt_Chris(df_test)   199.165    233.924   203.72   251.304    298.8887     3   a 
  </code></pre>
  
  <p>Interestingly the tidy_method comes out way faster in this <a href="https://stackoverflow.com/a/46871196/1305688">kinda similar comparison</a>.</p>