神奇的pandas,越用越觉得有意思。
pandas的切片功能非常强大,对于包含datetime类型列的dataframe和使用datetimeIndex的Series,通过给定datetime形式的字符串('2019-07-26 08:00:00', '2019-07', '2019-07-26', '2019-07-26 08:00'
)即可进行日期时间的筛选。
如果是想查找某个周期(年,月,周)内的特定时间(h: m: s)的数据(比如,查看一年之中每天的08:00的数据行),上面的切片式筛选就不适用了!
虽然还是会按照字符串判定时间,但是由于所查询的列是datetime类型数据,其中包含了date(年月日),还不会智能到自动去掉date,只按time来筛选,导致返回的结果肯定不是想要的。
那么,对于这个需求,可分两种情况进行解决:
(本文成文时,基于0.24.2
版本pandas,验证通过)
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情况下的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方法进行筛选,这样一次提取多个指定时间的数据非常方便。
比如把今年内,每天的上午9点15和下午1点15的数据都弄出来。
而且也可以做类似切片形式的按时间段提取,只要把想要时间段的时间数据全部添加到列表中即可。
(当然,如果数据的时间粒度已经细化到分、甚至秒的话,就有点不适用了,那样的话,写两个切片式条件,用 | 连接更好些。)
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
以上。