mosc9575
mosc9575

Reputation: 6337

How to group by days with a timeshift in pandas?

I have a DataFrame with an DataTimeIndex and I try to find the maximum between the first timestamp after 00:00 and 00:00 of the upcoming day. Right now I have a workin solution using pd.groupby() with an index by day.

Here is a minimal example with a maximum value of 24 which moves on hour each day:

data with moving max

df = pd.DataFrame(
    {'v':list(range(25))*3},
     index=pd.date_range('2020-01-01', freq='1H', periods=25*3)
)
df.index.name = 'datetime'
gg = df.groupby(df.index.copy().tz_localize(None).to_period("D"))
m = pd.merge(gg.idxmax(), gg.max(), on="datetime")
m.columns = ["idxmax", "max"]
>>> m
                        idxmax  max
datetime                           
2020-01-01 2020-01-01 23:00:00   23
2020-01-02 2020-01-02 00:00:00   24
2020-01-03 2020-01-03 01:00:00   24
2020-01-04 2020-01-04 02:00:00   24

What I am looking for is

                        idxmax  max
datetime                           
2019-12-31 2020-01-01 00:00:00   0
2020-01-01 2020-01-02 00:00:00   24
2020-01-02 2020-01-03 00:00:00   23
2020-01-03 2020-01-03 01:00:00   24
2020-01-04 2020-01-04 02:00:00   24

How can I create the wanted results?

Upvotes: 1

Views: 60

Answers (3)

jezrael
jezrael

Reputation: 862511

Use Grouper with offset parameter:

df = pd.DataFrame(
    {'v':list(range(25))*3},
     index=pd.date_range('2020-01-01', freq='1H', periods=25*3)
)
df.index.name = 'datetime'

#if necessary
df.index = df.index.tz_localize(None)
gg = df.groupby(pd.Grouper(freq='D', offset='1H'))
m = pd.merge(gg.idxmax(), gg.max(), on="datetime")
m.columns = ["idxmax", "max"]
print (m)
                                 idxmax  max
datetime                                    
2019-12-31 01:00:00 2020-01-01 00:00:00    0
2020-01-01 01:00:00 2020-01-02 00:00:00   24
2020-01-02 01:00:00 2020-01-03 00:00:00   23
2020-01-03 01:00:00 2020-01-03 01:00:00   24
2020-01-04 01:00:00 2020-01-04 02:00:00   24
    

Upvotes: 1

Learning is a mess
Learning is a mess

Reputation: 8277

What about:

df = pd.DataFrame({'v':list(range(25))*3}, index=pd.date_range('2020-01-01', freq='1H', periods=25*3))
df.index.name = 'datetime'
df.index -= pd.Timedelta('1h')
df = pd.merge_asof( df, df.resample('D')['v'].max().rename('v_max'), left_index=True, right_index=True)
df.index += pd.Timedelta('1h')
df

Upvotes: 0

mosc9575
mosc9575

Reputation: 6337

Ok. I found a solution with an pd.Timdelta.

df = pd.DataFrame({'v':list(range(25))*3}, index=pd.date_range('2020-01-01', freq='1H', periods=25*3))
df.index.name = 'datetime'
df.index -= pd.Timedelta('1h')
gg = df.groupby(df.index.copy().tz_localize(None).to_period("D"))
m = pd.merge(gg.idxmax()+pd.Timedelta('1h'), gg.max(), on="datetime")
m.columns = ["idxmax", "max"]
>>>                        idxmax  max
datetime                           
2019-12-31 2020-01-01 00:00:00    0
2020-01-01 2020-01-02 00:00:00   24
2020-01-02 2020-01-03 00:00:00   23
2020-01-03 2020-01-03 01:00:00   24
2020-01-04 2020-01-04 02:00:00   24

Upvotes: 0

Related Questions