python - 在 Pandas DataFrame 中选择日期来计算夏令时
问题描述
我正在尝试在 Pandas DataFrame(包含半小时数据)中选择一系列日期来确定那些日子的夏令时。DST 开始于 9 月的最后一个星期日,结束于 4 月的第一个星期日。
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')
我的数据在 9 月至 4 月期间基本上向后移动了 1 小时,因此我需要在此期间的时间戳中添加 1 小时。但是当我定义时start_dst
,我得到一个错误
TypeError: Cannot perform 'and_' with a dtyped [bool] array and scalar of type [bool]
我不知道如何改变start_dst
。
编辑:这是一个示例数据框:
# 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
解决方案
您可以创建/定义一个函数,通过计算条件为您提供索引:
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'
列并将该值设置为等于index
我们数据框的值我们制作了 idxmx 变量
idxmax()
和 idxmn 变量,idxmin()
它们正在比较数据帧的值idxmax()
和idxmin()
与数据帧的值并index
为您提供一个布尔数组,您会收到错误,因为(df0.dow==6).idxmax() or (df0.dow==6).idxmin()
给您一个单一的值而不是一系列布尔值我们正在定义一个名为的函数
get_indexex()
,它将为您提供满足条件的索引的索引,以在start_dst
为空数据帧时处理这种情况在函数内部还有一件事要注意,如果 start_dst 和 end_dst 包含多个条目,我们将索引到 start_dst 的第 0 个索引和 end_dst 的最后一个索引
更新:
您2020-04-05 23:00:00
从函数中获取信息是因为您的条件满足因此 end_dst 和 start_dst 中的任何一个都会为您提供结果,所以如果您不想要,那么您可以从函数中删除这种情况,所以现在它变为:
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')
推荐阅读
- git - 如何修改和维护导入的 go 依赖?
- allure - 与 Allure 的 Azure 问题
- java - 如何设置杰克逊反序列化base64编码字符串到控制器内的对象
- c++ - 如何使用 C++ 字符串将大写辅音替换为相应的小写辅音?
- c# - Xamarin 需要作为 commandParameter 从同一 xaml 的元素中选择项目
- c# - 一些unicode字符未显示在文本框中c#wpf
- docker - alpine docker 中的 node-sass 和 gyp
- c - C 中数字的凯撒密码
- javascript - 无法在 JavaScript 中添加事件侦听器
- python - Pandas 将数据从列中提取到字符串中