python pandas 按照时间(h:m:s)条件对使用datetimeIndex或datetime类型列的数据进行筛选的方法

神奇的pandas,越用越觉得有意思。
pandas的切片功能非常强大,对于包含datetime类型列的dataframe和使用datetimeIndex的Series,通过给定datetime形式的字符串('2019-07-26 08:00:00', '2019-07', '2019-07-26', '2019-07-26 08:00')即可进行日期时间的筛选。

BUT!

如果是想查找某个周期(年,月,周)内的特定时间(h: m: s)的数据(比如,查看一年之中每天的08:00的数据行),上面的切片式筛选就不适用了!
虽然还是会按照字符串判定时间,但是由于所查询的列是datetime类型数据,其中包含了date(年月日),还不会智能到自动去掉date,只按time来筛选,导致返回的结果肯定不是想要的。

那么,对于这个需求,可分两种情况进行解决:
(本文成文时,基于0.24.2版本pandas,验证通过)

一,要筛选的数据,使用datetimeIndex作为index。

index有两个方法,针对datetimeIndex。
一个是index.indexer_at_time(),提取指定时间的数据的行号:

按照datetimeIndex 取Series中指定的时间(h:m:s)的数据行号
locs = test.index.indexer_at_time('7:00:00')
print(locs)

输出符合条件的数据行号
>>> [ 28 124]
print(type(locs))
>>> <class 'numpy.ndarray'>

再用iloc方法,按行号提取指定时间的数据行
print(test.iloc[locs])
>>> 
                        VALUE
START_TIME                   
2019-07-22 07:00:00  24238.11
2019-07-23 07:00:00  21946.81

搞定
print(type(test.iloc[locs]))
输出>>> <class 'pandas.core.frame.DataFrame'>

另一个是index.indexer_between_time(),这个可以按给定时间段进行筛选,返回符合条件的行号。
具体参数是:indexer_between_time(start_time, end_time, include_start=True,include_end=True),起时间(string),止时间(string),包含起时间(True/False),包含止时间(True/False)。这里的包含起止时间可以按照查询时“是否左闭,是否右闭”去理解。

按照datetimeIndex 取Series中指定的时间段(包含起时间,不包含止时间)
start_time = '08:00:00'
end_time = '09:00:00'
locs2 = test.index.indexer_between_time(start_time, end_time, include_start=True,include_end=False)

返回的是符合条件的数据的行号
print(locs2)
>>> [ 32  33  34  35 128 129 130 131]
print(type(locs2))
>>> <class 'numpy.ndarray'>

搞定
print(test.iloc[locs2])
>>> 
                        VALUE
START_TIME                   
2019-07-22 08:00:00  31107.17
2019-07-22 08:15:00  27614.50
2019-07-22 08:30:00  30453.01
2019-07-22 08:45:00  30660.73
2019-07-23 08:00:00  28185.59
2019-07-23 08:15:00  28690.62
2019-07-23 08:30:00  29500.40
2019-07-23 08:45:00  30008.18

二,要筛选的数据,不使用datetimeIndex作为index,但是该DataFrame中有至少一个使用了datetime类型数据的列。

非datetimeIndex情况下的DataFrame,内含有datetime类型的列时,
可以按datetime.time类型的数据来对datetime column进行指定筛选和切片筛选。
这样就可以提取指定的“小时:分钟:秒”的数据行。
pandas的datetime类型column支持dt方法,于是datetime类型的列就可以按照.time == .time进行匹配。
(这里的dt其实就是datetime,datetime类型数据支持的.year, .month, .day, .time, .hour等,这里都支持)

用datetime.datetime.time方法创造一个datetime.time类型的数据
将字符串转换成time:datetime.datetime.strptime('time string', 'format string')
import datetime
print(datetime.datetime.strptime('08:00','%H:%M').time())
>>> 08:00:00
print(type(datetime.datetime.strptime('08:00','%H:%M').time()))
>>> datetime.time

注:df中,df['START_TIME']列的数据是datetime数据类型,下面df.START_TIME既是指向该列

用df.query方法(挺有意思,刚发现的)进行特定time的数据筛选
print(df.query('START_TIME.dt.time == datetime.datetime.strptime("08:00","%H:%M").time()'))

用df条件筛选进行特定time的数据筛选
print(df[df.START_TIME.dt.time == datetime.datetime.strptime("08:00","%H:%M").time()])

这两条命令的返回是一样的。
             START_TIME            END_TIME         NE_NAME     VALUE
32  2019-07-22 08:00:00 2019-07-22 08:15:00            baka  31107.17
128 2019-07-23 08:00:00 2019-07-23 08:15:00            baka  28185.59


想切片方式筛选的话,可以设定start_time和end_time,
start_time = datetime.datetime.strptime('16:00','%H:%M').time()
end_time = datetime.datetime.strptime('16:30','%H:%M').time()
ne_list = ['baka']
筛选出df['START_TIME']之中:大于等于start_time、小于等于end_time,以及df['NE_NAME']在ne_list列表中的所有数据
print(df[(df.START_TIME.dt.time >= start_time) & (df.START_TIME.dt.time <= end_time) & (df.NE_NAME.isin(ne_list))])
>>> 
             START_TIME            END_TIME         NE_NAME     VALUE
64  2019-07-22 16:00:00 2019-07-22 16:15:00            baka  28861.52
65  2019-07-22 16:15:00 2019-07-22 16:30:00            baka  28934.74
66  2019-07-22 16:30:00 2019-07-22 16:45:00            baka  29235.14
160 2019-07-23 16:00:00 2019-07-23 16:15:00            baka  26666.94
161 2019-07-23 16:15:00 2019-07-23 16:30:00            baka  28675.96
162 2019-07-23 16:30:00 2019-07-23 16:45:00            baka  28586.23


甚至可以搞一个time_list,也用.isin方法进行筛选,这样一次提取多个指定时间的数据非常方便。
比如把今年内,每天的上午915和下午115的数据都弄出来。
而且也可以做类似切片形式的按时间段提取,只要把想要时间段的时间数据全部添加到列表中即可。
(当然,如果数据的时间粒度已经细化到分、甚至秒的话,就有点不适用了,那样的话,写两个切片式条件,用 | 连接更好些。)
time_list = []
time_list.append(datetime.datetime.strptime("08:00","%H:%M").time())
time_list.append(datetime.datetime.strptime("09:15","%H:%M").time())
time_list.append(datetime.datetime.strptime("11:30","%H:%M").time())
time_list.append(datetime.datetime.strptime("13:45","%H:%M").time())
ne_list = ['baka']
print(df[(df.START_TIME.dt.time.isin(time_list)) & (df.NE_NAME.isin(ne_list))])
>>> 
             START_TIME            END_TIME         NE_NAME     VALUE
32  2019-07-22 08:00:00 2019-07-22 08:15:00            baka  31107.17
37  2019-07-22 09:15:00 2019-07-22 09:30:00            baka  31268.25
46  2019-07-22 11:30:00 2019-07-22 11:45:00            baka  29116.12
55  2019-07-22 13:45:00 2019-07-22 14:00:00            baka  24565.35
128 2019-07-23 08:00:00 2019-07-23 08:15:00            baka  28185.59
133 2019-07-23 09:15:00 2019-07-23 09:30:00            baka  30427.79
142 2019-07-23 11:30:00 2019-07-23 11:45:00            baka  28852.88
151 2019-07-23 13:45:00 2019-07-23 14:00:00            baka  24931.63

两个时间段
start_time = datetime.datetime.strptime('16:00','%H:%M').time()
end_time = datetime.datetime.strptime('16:30','%H:%M').time()
start_time1 = datetime.datetime.strptime('18:00','%H:%M').time()
end_time1 = datetime.datetime.strptime('18:30','%H:%M').time()
ne_list = ['baka']

两个切片式条件取或
print(df[ (((df.START_TIME.dt.time >= start_time) & (df.START_TIME.dt.time <= end_time)) | 
((df.START_TIME.dt.time >= start_time1) & (df.START_TIME.dt.time <= end_time1))) & 
(df.NE_NAME.isin(ne_list))]
)
>>> 
             START_TIME            END_TIME         NE_NAME     VALUE
64  2019-07-22 16:00:00 2019-07-22 16:15:00            baka  28861.52
65  2019-07-22 16:15:00 2019-07-22 16:30:00            baka  28934.74
66  2019-07-22 16:30:00 2019-07-22 16:45:00            baka  29235.14
72  2019-07-22 18:00:00 2019-07-22 18:15:00            baka  28193.47
73  2019-07-22 18:15:00 2019-07-22 18:30:00            baka  27489.57
74  2019-07-22 18:30:00 2019-07-22 18:45:00            baka  27459.55
160 2019-07-23 16:00:00 2019-07-23 16:15:00            baka  26666.94
161 2019-07-23 16:15:00 2019-07-23 16:30:00            baka  28675.96
162 2019-07-23 16:30:00 2019-07-23 16:45:00            baka  28586.23
168 2019-07-23 18:00:00 2019-07-23 18:15:00            baka  26940.09
169 2019-07-23 18:15:00 2019-07-23 18:30:00            baka  26536.41
170 2019-07-23 18:30:00 2019-07-23 18:45:00            baka  25966.47

题外:将datetime类型的列,搞一个只有time的Series出来,这样就能做到。

ts = df.START_TIME.dt.time
print(type(ts))
>>> <class 'pandas.core.series.Series'>
print(ts)
>>> 
0       00:00:00
1       00:15:00
2       00:30:00
          ...   
1533    23:15:00
1534    23:30:00
1535    23:45:00
Name: START_TIME, Length: 1536, dtype: object

以上。

  • 31
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值