Pandas时间筛选问题:生成时段标记列表出错求助
问题描述
给定如下DataFrame:
Index Dates 0 2017-01-01 23:30:00 1 2017-01-12 22:30:00 2 2017-01-20 13:35:00 3 2017-01-21 14:25:00 4 2017-01-28 22:30:00 5 2017-08-01 13:00:00 6 2017-09-26 09:39:00 7 2017-10-08 06:40:00 8 2017-10-04 07:30:00 9 2017-12-13 07:40:00 10 2017-12-31 14:55:00
需求是筛选出时间在5:00到11:59之间的数据,生成**对应位置标记为'morning'**的列表。
当前使用的代码:
hour_morning=(pd.to_datetime(df['Dates']).dt.strftime('%H:%M:%S').between('05:00:00','11:59:00')) text_morning=[str('morning') for x in hour_morning if x==True]
但这段代码仅返回若干个'morning'字符串,没有保留原序列的对应位置,请问原因是什么?该如何解决?
原因分析
你的列表推导式里的if x==True是过滤逻辑,它会直接丢弃不满足条件的元素,只保留符合条件的项生成新列表,所以最终得到的列表长度等于原序列中符合时间条件的行数,而不是和原序列长度一致的带位置标记的列表。
另外,用dt.strftime将时间转为字符串再做区间判断属于绕路操作,直接提取小时数做数值判断更高效准确。
解决方法
下面提供几种实用的解决方案:
方法1:列表推导式三元表达式(保留所有位置)
把过滤条件改成三元判断,对每个元素都生成对应值,满足条件的标记为'morning',不满足的可设为None或空字符串:
import pandas as pd # 构造示例DataFrame df = pd.DataFrame({ 'Dates': [ '2017-01-01 23:30:00', '2017-01-12 22:30:00', '2017-01-20 13:35:00', '2017-01-21 14:25:00', '2017-01-28 22:30:00', '2017-08-01 13:00:00', '2017-09-26 09:39:00', '2017-10-08 06:40:00', '2017-10-04 07:30:00', '2017-12-13 07:40:00', '2017-12-31 14:55:00' ] }) # 提取小时数并生成布尔序列 hour_series = pd.to_datetime(df['Dates']).dt.hour is_morning = (hour_series >= 5) & (hour_series <= 11) # 生成带位置标记的列表 text_morning = ['morning' if x else None for x in is_morning] print(text_morning)
输出结果:
[None, None, None, None, None, None, 'morning', 'morning', 'morning', 'morning', None]
方法2:pandas内置where方法
利用pandas的where方法保留原序列结构,满足条件的替换为'morning',不满足的设为指定值:
# 基于已生成的is_morning布尔序列 text_morning_series = is_morning.replace(True, 'morning').where(is_morning, None) text_morning = text_morning_series.tolist()
方法3:numpy的where函数(高效批量处理)
用numpy的where函数实现批量判断,效率更高,适合大数据量场景:
import numpy as np text_morning = np.where(is_morning, 'morning', None).tolist()
内容的提问来源于stack exchange,提问作者Strovic
相关产品推荐
相关产品推荐

