4

I've got some daily data in a Pandas DataFrame and it has a nice index. Something like this:

import pandas as pd
import numpy as np

rng = pd.date_range('1/1/2010', periods=1000, freq='D')
ts = pd.DataFrame(randn(len(rng)), index=rng, columns=['vals'])
print ts.head()

                vals
2010-01-01  1.098302
2010-01-02 -1.384821
2010-01-03 -0.426329
2010-01-04 -0.587967
2010-01-05 -0.853374

I'd like to subset my DataFrame to only the records that fall between February 2 & March 3 for all years.

It seems there should be a very Pandas-esque way of doing this but I'm struggling to find it. Any help?

JD Long
  • 59,675
  • 58
  • 202
  • 294
  • There's indexer_between_time for between *times*, but I don't think there is a similar convenience function for dates. – Andy Hayden Sep 11 '13 at 17:16

2 Answers2

6

I don't think there is a native way to do this (there is with between times).

But you can do it naively (this will be efficient, but is a pain to write!):

In [11]: ts[((ts.index.month == 2) & (2 <= ts.index.day)  # in Feb after the 2nd inclusive
              | (ts.index.month == 3) & (ts.index.day <= 3))]  # in March before the 3rd inclusive
Out[11]: 
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 94 entries, 2010-02-01 00:00:00 to 2012-03-03 00:00:00
Data columns (total 1 columns):
vals    94  non-null values
dtypes: float64(1)
Community
  • 1
  • 1
Andy Hayden
  • 359,921
  • 101
  • 625
  • 535
3

To select all records of an annual returning period covering multiple months, do as follow:

rng = pd.date_range('2010-1-1', periods=1000, freq='D')
df = pd.DataFrame(np.random.randn(len(rng)), index=rng, columns=['A'])

startMM, startdd = (2,15) # Feb 15th 
endMM, enddd = (10,3) # Oct 3rd

month_day = pd.concat([
                df.index.to_series().dt.month, 
                df.index.to_series().dt.day
            ], axis=1).apply(tuple, axis=1)

df[(month_day >= (startMM, startdd)) & (month_day <= (endMM, enddd))]

as mentioned by @IanS in https://stackoverflow.com/a/45996897/2459096

Mattijn
  • 12,975
  • 15
  • 45
  • 68