title: Removing rows if they occur within a certain time of first instance by a group value in R
body: <p>This is a follow up question to <a href="https://stackoverflow.com/questions/69453191/removing-rows-if-they-occur-within-a-certain-time-of-each-other-by-a-group-value">Removing rows if they occur within a certain time of each other by a group value in R</a>.</p>
  <p>I have modified the <code>df</code> presented there with a particular case I am trying to filter.</p>
  <p>This is the <code>code</code> with a quick way to filter out rows with less than a 5 minutes interval using tidyverse (similar to the solution posted by <a href="https://stackoverflow.com/a/69455289/5427165">PaulS</a> in the original question).</p>
  <pre><code>library(tidyverse)
  
  df &lt;- tribble(
    ~Row,   ~Timestamp,                ~ID,
    1,      &quot;0020-06-29 12:14:00&quot;,     &quot;B&quot;,
    2,      &quot;0020-06-29 12:27:00&quot;,     &quot;A&quot;, 
    3,      &quot;0020-06-29 12:27:22&quot;,     &quot;B&quot;,  
    4,      &quot;0020-06-29 12:28:30&quot;,     &quot;A&quot;, 
    5,      &quot;0020-06-29 12:31:30&quot;,     &quot;A&quot;, 
    6,      &quot;0020-06-29 12:33:30&quot;,     &quot;A&quot;, 
    7,      &quot;0020-06-29 12:33:45&quot;,     &quot;A&quot;, 
    8,      &quot;0020-06-29 12:43:00&quot;,     &quot;B&quot;, 
    9,      &quot;0020-06-29 12:44:00&quot;,     &quot;C&quot;, 
    10,     &quot;0020-06-29 12:45:00&quot;,     &quot;B&quot;, 
    11,     &quot;0020-06-29 12:55:00&quot;,     &quot;A&quot;, 
    12,     &quot;0020-06-29 12:57:00&quot;,     &quot;C&quot;, 
    13,     &quot;0020-06-29 13:04:00&quot;,     &quot;B&quot;, 
  )
  
  df %&gt;% 
    group_by(ID) %&gt;% 
    mutate(d = abs(difftime(lag(Timestamp), Timestamp)),
           keep = is.na(d) | d &gt; 5*60) %&gt;% 
    filter(keep) %&gt;% 
    select(-d, -keep) %&gt;% 
    arrange(Row)
  </code></pre>
  <p>This is the result:</p>
  <pre><code># A tibble: 8 × 3
  # Groups:   ID [3]
    Row Timestamp           ID   
  &lt;dbl&gt; &lt;chr&gt;               &lt;chr&gt;
      1 0020-06-29 12:14:00 B    
      2 0020-06-29 12:27:00 A    
      3 0020-06-29 12:27:22 B    
      8 0020-06-29 12:43:00 B    
      9 0020-06-29 12:44:00 C    
     11 0020-06-29 12:55:00 A    
     12 0020-06-29 12:57:00 C    
     13 0020-06-29 13:04:00 B   
  </code></pre>
  <p>This is not what I want because the time difference is always obtained to the previous row (using <code>lag</code>). This means that <strong>Row 6</strong> and <strong>Row 7</strong> are removed because they are less than 5 minutes away from each other and also from <strong>Row 5</strong>. The truth is, though, that <strong>Row 6</strong> is <strong>more</strong> than five minutes away from the first instance in group <strong>A</strong>. It should be kept and become the first instance for a new interval and then <strong>Row 7</strong> would be removed accordingly to the distance to the new first instance in <strong>Row 6</strong>.</p>
  <p>What I have been unable to obtain (without a loop) is how to define this time interval groups of 5 minutes, not from successive rows, but from the first instance after 5 minues.</p>
  <p>EDIT 1: Possible solution using an hybrid tidyverse-loop approach:</p>
  <pre><code>library(tidyverse)
  
  df &lt;- tribble(
    ~Row,   ~Timestamp,                ~ID,
    1,      &quot;0020-06-29 12:14:00&quot;,     &quot;B&quot;,
    2,      &quot;0020-06-29 12:27:00&quot;,     &quot;A&quot;, 
    3,      &quot;0020-06-29 12:27:22&quot;,     &quot;B&quot;,  
    4,      &quot;0020-06-29 12:28:30&quot;,     &quot;A&quot;, 
    5,      &quot;0020-06-29 12:31:30&quot;,     &quot;A&quot;, 
    6,      &quot;0020-06-29 12:33:30&quot;,     &quot;A&quot;, 
    7,      &quot;0020-06-29 12:33:45&quot;,     &quot;A&quot;, 
    8,      &quot;0020-06-29 12:43:00&quot;,     &quot;B&quot;, 
    9,      &quot;0020-06-29 12:44:00&quot;,     &quot;C&quot;, 
    10,     &quot;0020-06-29 12:45:00&quot;,     &quot;B&quot;, 
    11,     &quot;0020-06-29 12:55:00&quot;,     &quot;A&quot;, 
    12,     &quot;0020-06-29 12:57:00&quot;,     &quot;C&quot;, 
    13,     &quot;0020-06-29 13:04:00&quot;,     &quot;B&quot;, 
  )
  
  loop &lt;- TRUE
  
  while(loop) {
    
    df &lt;- df %&gt;% 
      group_by(ID) %&gt;% 
      mutate(d = abs(difftime(lag(Timestamp), Timestamp, units=&quot;secs&quot;)),
             first = is.na(d) | d &gt; 300,
             prev_first = lag(first),
             keep = first | is.na(d) | (prev_first &amp; d &gt; 300) | (!first &amp; !prev_first))
    
    if (all(df$keep)) loop &lt;- FALSE
    
    df &lt;- df %&gt;% filter(keep)
    
  }
  
  df &lt;- df %&gt;% 
    select(Row, Timestamp, ID) %&gt;% 
    arrange(Row)
  </code></pre>
  <p>This is the <strong>real</strong> expected result:</p>
  <pre><code># A tibble: 9 × 3
  # Groups:   ID [3]
    Row Timestamp           ID   
  &lt;dbl&gt; &lt;chr&gt;               &lt;chr&gt;
      1 0020-06-29 12:14:00 B    
      2 0020-06-29 12:27:00 A    
      3 0020-06-29 12:27:22 B    
      6 0020-06-29 12:33:30 A    
      8 0020-06-29 12:43:00 B    
      9 0020-06-29 12:44:00 C    
     11 0020-06-29 12:55:00 A    
     12 0020-06-29 12:57:00 C    
     13 0020-06-29 13:04:00 B 
  </code></pre>
  <p>EDIT 2: More clarifiations. This is the <code>df</code> ordered by ID and with a comment on each row on whether it should be kept or removed:</p>
  <pre><code>  Row Timestamp           ID   
  &lt;dbl&gt; &lt;chr&gt;               &lt;chr&gt;
      2 0020-06-29 12:27:00 A  &lt;-- Keep (first in interval)  
      4 0020-06-29 12:28:30 A  &lt;-- Remove (&lt;5 mins from Row 2)   
      5 0020-06-29 12:31:30 A  &lt;-- Remove (&lt;5 mins from Row 2)  
      6 0020-06-29 12:33:30 A  &lt;-- Keep (first in interval, &gt;5 mins from previous first Row 2)  
      7 0020-06-29 12:33:45 A  &lt;-- Remove (&lt;5 mins from Row 6)    
     11 0020-06-29 12:55:00 A  &lt;-- Keep (first in interval, &gt;5 mins from previous first Row 6)  
      1 0020-06-29 12:14:00 B  &lt;-- Keep (first in interval)
      3 0020-06-29 12:27:22 B  &lt;-- Keep (first in interval, &gt;5 mins from previous first Row 1)
      8 0020-06-29 12:43:00 B  &lt;-- Keep (first in interval, &gt;5 mins from previous first Row 3)
     10 0020-06-29 12:45:00 B  &lt;-- Remove (&lt;5 mins from Row 8)
     13 0020-06-29 13:04:00 B  &lt;-- Keep (first in interval, &gt;5 mins from previous first Row 8)  
      9 0020-06-29 12:44:00 C  &lt;-- Keep (first in interval)  
     12 0020-06-29 12:57:00 C  &lt;-- Keep (first in interval, &gt;5 mins from previous first Row 9)
  </code></pre>
  <p>Even if this solution is not terrible, do you know whether the while statement can be removed in any way?</p>