You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据列表前缀匹配为DataFrame新增BAN列与FLAG列

问题描述

现有如下结构的DataFrame(含数万行数据):

CALL_START             IMSI
0  24.07.2025 12:00:51  123456888888888
1  24.07.2025 17:58:57  123456999999999
2  24.07.2025 17:05:47  543214511111111
3  24.07.2025 17:02:30  543214522222222
4  24.07.2025 16:07:44  987654444444444
5  24.07.2025 16:07:49  777777444444444

用于匹配的列表较短(约100个元素,长度为5或6位),示例:

['123456', '54321', '98765']

需求:
检查IMSI列(字符串类型)是否以列表中的元素开头,满足以下任一方案即可:

  1. 新增两列:BAN列存储匹配的列表元素,FLAG列设为True;未匹配则BAN设为None(或空字符串),FLAG设为False。
  2. 仅保留匹配结果(不含FLAG列),示例输出:
CALL_START             IMSI    BAN  
0  24.07.2025 12:00:51  123456888888888  123456 
1  24.07.2025 17:58:57  123456999999999  123456 
2  24.07.2025 17:05:47  543214511111111  54321  
3  24.07.2025 17:02:30  543214522222222  54321  
4  24.07.2025 16:07:44  987654444444444  98765 

已知pd.Series.str.startswith()仅返回布尔值Series,无法满足需求,寻求可行方案。

解决方案

方法1:正则表达式提取(高效)

利用str.extract结合正则匹配前缀,适合处理大规模数据:

import pandas as pd

# 初始化示例数据
df = pd.DataFrame({
    'CALL_START': ['24.07.2025 12:00:51', '24.07.2025 17:58:57', '24.07.2025 17:05:47', 
                   '24.07.2025 17:02:30', '24.07.2025 16:07:44', '24.07.2025 16:07:49'],
    'IMSI': ['123456888888888', '123456999999999', '543214511111111', 
             '543214522222222', '987654444444444', '777777444444444']
})

ban_list = ['123456', '54321', '98765']

# 生成正则匹配模式:匹配以任意ban元素开头的前缀
pattern = fr'^({"|".join(ban_list)})'
df['BAN'] = df['IMSI'].str.extract(pattern)
# 生成FLAG列
df['FLAG'] = df['BAN'].notna()

# 仅保留匹配结果(不含FLAG列)
matched_df = df.dropna(subset=['BAN']).drop(columns=['FLAG'])
  • 正则^表示字符串开头,|分隔所有备选前缀,str.extract会提取匹配到的前缀,未匹配则返回NaN(等价于None)。
  • FLAG列直接通过BAN列是否非空生成,逻辑简洁高效。

方法2:apply遍历匹配(直观)

因为匹配列表仅约100个元素,对万级数据来说性能完全够用,逻辑更易理解:

def find_matched_ban(imsi):
    for ban in ban_list:
        if imsi.startswith(ban):
            return ban
    return None

df['BAN'] = df['IMSI'].apply(find_matched_ban)
df['FLAG'] = df['BAN'].notna()

# 仅保留匹配结果
matched_df = df[df['FLAG']].drop(columns=['FLAG'])
  • 自定义函数遍历ban列表,返回第一个匹配的前缀,未匹配则返回None。
  • 后续生成FLAG和过滤结果的逻辑与方法1一致。

方法3:利用str.startswith广播特性(进阶)

结合np.select将布尔匹配结果映射为对应前缀:

import numpy as np

# 生成每个ban对应的布尔匹配Series
conditions = [df['IMSI'].str.startswith(ban) for ban in ban_list]
# 按顺序匹配,返回第一个满足条件的ban值,未匹配返回None
df['BAN'] = np.select(conditions, ban_list, default=None)
df['FLAG'] = df['BAN'].notna()

# 仅保留匹配结果
matched_df = df[df['FLAG']].drop(columns=['FLAG'])
  • conditions是布尔Series列表,每个元素对应一个ban的匹配结果。
  • np.select按顺序检查条件,返回第一个满足条件的ban值,无匹配则返回默认值。

内容的提问来源于stack exchange,提问作者urosdigital

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 11:45:16