基于指定日期从Pandas列的分隔列表中筛选对应符号
问题描述
现有如下Pandas DataFrame,包含id、symbols和symbol_dates三列:
id symbols symbol_dates 1 ABC 20070103:29991231 2 DEF;GH 20100307:20141215;20141216:29991231 3 IJ;KLM;NO 20040107:20051105;20051106:20180316;20180317:29991231 4 PQ 20080103:20090613 5 RST;UV 20080206:20150603;20150604:29991231 6 WXY 20070103:20130516
其中symbols与symbol_dates的内容均以分号分隔,每个符号对应一个日期区间(格式为YYYYMMDD:YYYYMMDD)。例如id=2时,日期区间20141216:29991231对应的符号是GH。
需求:输入一个日期(格式YYYYMMDD),返回新的DataFrame,仅保留该日期所属区间对应的符号;若输入日期不在该行的任何区间内,则丢弃该行。例如输入20141220时,预期输出:
id symbol 1 ABC 2 GH 3 KLM 5 RST
实现思路与方法
核心思路
- 统一日期格式:将输入日期和区间的起止日期转为整数,方便直接做大小比较
- 关联符号与区间:拆分每行的多符号、多区间为列表,保证符号和对应区间一一匹配
- 匹配筛选:找到每个
id下包含输入日期的区间,取出对应符号;过滤无匹配的行
方法一:逐行遍历匹配
逻辑直观,适合理解基础匹配流程:
import pandas as pd # 初始化示例DataFrame df = pd.DataFrame({ 'id': [1,2,3,4,5,6], 'symbols': ['ABC', 'DEF;GH', 'IJ;KLM;NO', 'PQ', 'RST;UV', 'WXY'], 'symbol_dates': ['20070103:29991231', '20100307:20141215;20141216:29991231', '20040107:20051105;20051106:20180316;20180317:29991231', '20080103:20090613', '20080206:20150603;20150604:29991231', '20070103:20130516'] }) def filter_by_date(input_date): input_date_int = int(input_date) # 拆分每行的符号和区间为列表 df['symbol_list'] = df['symbols'].str.split(';') df['date_range_list'] = df['symbol_dates'].str.split(';') # 定义函数,为每行找到匹配的符号 def get_matching_symbol(row): for symbol, date_range in zip(row['symbol_list'], row['date_range_list']): start, end = map(int, date_range.split(':')) if start <= input_date_int <= end: return symbol return None # 无匹配返回空 # 应用函数生成匹配结果 df['symbol'] = df.apply(get_matching_symbol, axis=1) # 过滤空结果,整理目标列 result = df[df['symbol'].notna()][['id', 'symbol']].reset_index(drop=True) # 清理临时列 df.drop(columns=['symbol_list', 'date_range_list'], inplace=True) return result # 测试输入日期20141220 output = filter_by_date('20141220') print(output)
方法二:用explode展开后筛选
利用Pandas的explode方法将多值字段拆分为多行,再做筛选,代码更简洁,大数据量下效率更高:
def filter_by_date_explode(input_date): input_date_int = int(input_date) # 拆分符号和区间,展开为每行对应一个符号-区间对 expanded_df = df.assign( symbol=df['symbols'].str.split(';'), date_range=df['symbol_dates'].str.split(';') ).explode(['symbol', 'date_range'], ignore_index=True) # 拆分区间为起止日期并转为整数 expanded_df[['start', 'end']] = expanded_df['date_range'].str.split(':', expand=True).astype(int) # 筛选输入日期在区间内的行,去重并整理列 result = expanded_df[(expanded_df['start'] <= input_date_int) & (expanded_df['end'] >= input_date_int)][['id', 'symbol']] result = result.drop_duplicates(subset='id').reset_index(drop=True) return result # 测试 output = filter_by_date_explode('20141220') print(output)
内容的提问来源于stack exchange,提问作者carvalh3
相关产品推荐
相关产品推荐

