title: Rate of change over last n hours using pandas timeseries
body: <p>I would like to add columns to a time-indexed pandas DataFrame which contain the rate of change over the last n hours for each of the existing columns. I have accomplished this with the following code, however, it is too slow for my needs (probably due to looping over every index of each column?). </p>
  
  <p>Is there a (computationally) faster way to do this?</p>
  
  <pre><code>roc_hours = 12
  tol = 1e-10 
  for c in ts.columns:
      c_roc = c + ' +++ RoC ' + str(roc_hours) + 'h' 
      ts[c_roc] = np.nan
      for i in ts.index[np.isfinite(ts[c])]:
          df = ts[c][i - np.timedelta64(roc_hours, 'h'):i]
          X = (df.index.values - df.index.values.min()).astype('Int64')*2.77778e-13 #hours back
          Y = df.values
          if Y.std() &gt; tol and X.shape[0] &gt; 1:
              fit = np.polyfit(X,Y,1)
              ts[c_roc][i] = fit[0]
          else:
              ts[c_roc][i] = 0
  </code></pre>
  
  <p><strong>Edit</strong> input dataframe ts is irregularly sampled and can contain <code>NaN</code>s. First few lines of input ts:</p>
  
  <pre><code>+---------------------+-------------------+------+------+--------------------+-------------------+------------------+
  |         WCT         |         a         |  b   |  c   |         d          |         e         |        f         |
  +---------------------+-------------------+------+------+--------------------+-------------------+------------------+
  | 2011-09-04 20:00:00 |                   |      |      |                    |                   |                  |
  | 2011-09-04 21:00:00 |                   |      |      |                    |                   |                  |
  | 2011-09-04 22:00:00 |                   |      |      |                    |                   |                  |
  | 2011-09-04 23:00:00 |                   |      |      |                    |                   |                  |
  | 2011-09-05 02:00:00 |        93.0       | 97.0 | 20.0 |       209.0        |        85.0       |       98.0       |
  | 2011-09-05 03:00:00 | 74.14285714285714 | 97.0 | 20.0 | 194.14285714285717 | 74.42857142857143 |       98.0       |
  | 2011-09-05 04:00:00 |        67.5       | 98.5 | 20.0 |       176.0        |        75.0       |       98.0       |
  | 2011-09-05 05:00:00 |        72.0       | 98.5 | 20.0 |       176.0        |        75.0       |       98.0       |
  | 2011-09-05 07:00:00 |        80.0       | 93.0 | 19.0 |       186.0        |        71.0       |       97.0       |
  | 2011-09-05 08:00:00 |        80.0       | 93.0 | 19.0 |       186.0        |        71.0       |       97.0       |
  | 2011-09-05 09:00:00 |        78.5       | 98.0 | 19.0 |       186.0        |        71.0       |       97.0       |
  | 2011-09-05 10:00:00 |        73.0       | 98.0 | 19.0 |       186.0        |        71.0       |       97.0       |
  | 2011-09-05 11:00:00 |        77.0       | 98.0 | 18.0 |       175.0        |        87.0       | 97.0999984741211 |
  | 2011-09-05 12:00:00 |        78.0       | 98.0 | 19.0 |       163.0        |        57.0       | 98.4000015258789 |
  | 2011-09-05 15:00:00 |        78.0       | 98.0 | 19.0 |       163.0        |        57.0       | 98.4000015258789 |
  +---------------------+-------------------+------+------+--------------------+-------------------+------------------+
  </code></pre>
  
  <p><strong>Edit 2</strong></p>
  
  <p>After profiling, the bottleneck is in the slicing step: <code>df = ts[c][i - np.timedelta64(roc_hours, 'h'):i]</code>. This line pulls out observations time-stamped between now-roc_hours and now. It's very handy syntax, but is taking up the bulk of the compute time.</p>