python 在Pandas DataFrame中选择日期以计算夏令时

mspsb9vt  于 2023-01-16  发布在  Python
关注(0)|答案(3)|浏览(161)

我尝试在Pandas DataFrame(包含半小时数据)中选择一个日期范围,以确定这些天的夏令时。夏令时的开始时间是九月的最后一个星期日,结束时间是四月的第一个星期日。

import numpy as np
import pandas as pd
from datetime import datetime, date, timedelta

...

df0 = df0.set_index('datetime')

df0['mnth'] = pd.DatetimeIndex(df0.index).month
df0['dow'] = pd.DatetimeIndex(df0.index).dayofweek # Mon=0, ..., Sun=6

start_dst = df0.iloc[(df0.mnth==9) & (df0.dow==6).idxmax()]
end_dst = df0.iloc[(df0.mnth==4) & (df0.dow==6).idxmin()]
df0.index[start_dst:end_dst] = df0.index + pd.Timedelta('1h')

在Sep-Apr期间,我的数据实际上向后移动了1小时,因此我需要在这段时间的时间戳中添加1小时。

TypeError: Cannot perform 'and_' with a dtyped [bool] array and scalar of type [bool]

我不知道如何更改start_dst

**编辑:**以下是一个示例 Dataframe :

# End DST: first Sunday of April, 1h backward (5 Apr 2020)
# Start DST: last Sunday of September, 1h forward (27 Sep 2020)
# 4,5,6 April 2020, 26,27,28 Sep 2020
d1 = '2020-04-04'
d2 = '2020-04-05'
d3 = '2020-04-06'
d4 = '2020-09-26'
d5 = '2020-09-27'
d6 = '2020-09-28'

df1 = pd.DataFrame()
df1['date'] = pd.to_datetime([d1]*24, format='%Y-%m-%d')
df1['time'] = (pd.date_range(d1, periods=24, freq='H') - pd.Timedelta(hours=1)).time
df1 = df1.set_index('date')

df2 = pd.DataFrame()
df2['date'] = pd.to_datetime([d2]*25, format='%Y-%m-%d')
df2['time'] = (pd.date_range(d2, periods=25, freq='H') - pd.Timedelta(hours=1)).time
df2 = df2.set_index('date')

df3 = pd.DataFrame()
df3['date'] = pd.to_datetime([d3]*24, format='%Y-%m-%d')
df3['time'] = (pd.date_range(d3, periods=24, freq='H')).time
df3 = df3.set_index('date')

df4 = pd.DataFrame()
df4['date'] = pd.to_datetime([d4]*24, format='%Y-%m-%d')
df4['time'] = (pd.date_range(d4, periods=24, freq='H')).time
df4 = df4.set_index('date')

df5 = pd.DataFrame()
df5['date'] = pd.to_datetime([d5]*23, format='%Y-%m-%d')
df5a = pd.DataFrame(pd.date_range('00:00', '01:59', freq='H').time)
df5b = pd.DataFrame(pd.date_range('01:00', '01:59', freq='H').time)
df5c = pd.DataFrame(pd.date_range('03:00', '22:00', freq='H').time)
df5['time'] = pd.concat([df5a,df5b,df5c],axis=0).values
df5 = df5.set_index('date')

df6 = pd.DataFrame()
df6['date'] = pd.to_datetime([d6]*24, format='%Y-%m-%d')
df6['time'] = (pd.date_range(d6, periods=24, freq='H') - pd.Timedelta(hours=1)).time
df6 = df6.set_index('date')

df0 = pd.DataFrame()
z = df1.append(df2).append(df3).append(df4).append(df5).append(df6)
df0['datetime'] = pd.to_datetime(z.index.astype(str)+' '+z.time.astype(str),
                            format='%Y-%m-%d %H:%M:%S')
df0 = df0.set_index('datetime')

df0['mnth'] = pd.DatetimeIndex(df0.index).month
df0['dow'] = pd.DatetimeIndex(df0.index).dayofweek # Mon=0, ..., Sun=6
df0['hour'] = pd.DatetimeIndex(df0.index).hour
sd2nnvve

sd2nnvve1#

您可以创建/定义一个函数,通过计算以下条件为您提供索引:

def get_indexex():
    try:
        idxmx=df0.index==((df0['dow']==6).idxmax())
        idxmn=df0.index==((df0['dow']==6).idxmin())
        start_dst = df0.loc[(df0['mnth']==9) & idxmx]
        end_dst = df0.loc[(df0['mnth']==4) & idxmn]
        if not start_dst.index.tolist():
            return df0.loc[:end_dst.index[-1]].index
        elif not end_dst.index.tolist():
            return  df0.loc[start_dst.index[0]:].index
        else:
            return  df0.loc[start_dst.index[0]:end_dst.index[-1]].index
    except IndexError:
        start_dst=df0.loc[(df0['dow'].eq(6) & df0['mnth'].eq(9)) & df0['hour'].eq(2)]
        end_dst=df0.loc[df0['mnth'].eq(4) & df0['hour'].eq(3)]
        if not start_dst.index.tolist():
            return df0.loc[:end_dst.index[-1]].index
        elif not end_dst.index.tolist():
            return  df0.loc[start_dst.index[0]:].index
        else:
            return  df0.loc[start_dst.index[0]:end_dst.index[-1]].index

最后:

df0['dt']=df0.index
m=df0.index.isin(get_indexex())
df0.loc[m,'dt']=df0.loc[m,'dt']+pd.Timedelta('1H')
df0.index=df0.pop('dt')
    • 某些事情的原因:**
  • 您不能更改子集的索引,因此我们创建了'dt'列,并将该值设置为等于 Dataframe 的index
  • 我们为idxmax()设置了idxmx变量,为idxmin()设置了idxmn变量,这两个变量将idxmax()idxmin()的值与 Dataframe 的index进行比较,并为您提供一个布尔数组,您将得到错误,因为(df0.dow==6).idxmax() or (df0.dow==6).idxmin()为您提供了单个值,而不是一系列布尔值
  • 我们正在定义一个名为get_indexex()的函数,它将为您提供index的索引,其中条件满足,以便在start_dst为空 Dataframe 时处理这种情况
  • 还有一件事要注意,在函数内部,如果start_dst和end_dst包含多个条目,我们将获取start_dst的第0个索引和end_dst的最后一个索引
    • 更新日期:**

你从函数中得到2020-04-05 23:00:00因为你的条件满足end_dst和start_dst中的任何一个,给你结果,如果你不想的话,你可以从函数中删除这个case,现在它变成:

def get_indexex():
    start_dst=df0.loc[(df0['dow'].eq(6) & df0['mnth'].eq(9)) & df0['hour'].eq(2)]
    end_dst=df0.loc[df0['mnth'].eq(4) & df0['hour'].eq(3)]
    if not start_dst.index.tolist():
        return df0.loc[:end_dst.index[-1]].index
    elif not end_dst.index.tolist():
        return  df0.loc[start_dst.index[0]:].index
    else:
        return  df0.loc[start_dst.index[0]:end_dst.index[-1]].index

最后:

df0['dt']=df0.index
m=df0.index.isin(get_indexex())
df0.loc[m,'dt']=df0.loc[m,'dt']+pd.Timedelta('1H')
df0.index=df0.pop('dt')
eni9jsuy

eni9jsuy2#

我认为错误是由于idxmax()和idxmin();都返回索引号,且该索引不是bool类型,(df0.mnth==9)和(df0.mnth==4)返回True和False的数组;而当你试图比较它们时,这个错误就会出现。

6yoyoihd

6yoyoihd3#

手动处理DST的想法让我很头疼,Pandas时间戳对象(一个Series的单个值)有dst()函数,它返回夏令时的时差。

相关问题