如何在Pandas中实现spec列与对应行lst列列表的匹配(广播.isin)
Pandas:逐行检查值是否存在于对应行的列表中
在匹配spec与允许值的工作流中,我需要找出哪些行符合spec要求——即每行的spec值是否存在于该行的lst列表里。这和Stack Overflow上《Pandas, isin, column of lists》的问题不同,因为我不是将每行与一个静态列表匹配。
我试过用.explode+.groupby或者.apply实现需求:前者操作过于繁琐,后者存在性能问题。我认为应该有更优的实现方式,但不知道该怎么做——尝试让.isin实现广播却没成功,这原本看起来是最佳解决方案。
示例代码
import pandas as pd import numpy as np df = pd.DataFrame(data = { 'name': ['a', 'b', 'c'], 'lst': [[0,2,4], [1,2], []], 'spec': [2,4,0] }) expect = pd.DataFrame(data= { 'name': ['a', 'b', 'c'], 'match_spec': [True, False, False] }) def check(f): try: got = f() result = (expect['match_spec'] == got) ok = result.all() if ok: print(f'OK {f}') else: print(f'FAIL {f}\n{got}') except Exception as ex: print(f'ERROR {f}\n{ex}') # 尝试的方法 def naive_broadcast(): return df.spec in df.lst check(naive_broadcast) def result_apply(): return df.apply(lambda x: x.spec in x.lst, axis=1) check(result_apply) def naive_isin(): return df.spec.isin(df.lst) check(naive_isin) def vectorization(): np.vectorize(df.spec.isin)(df.lst.values) check(vectorization) # 繁琐的方法:explode+groupby def explode_groupby(): exp = df.explode('lst') return (exp.assign(m = (exp['lst'].eq(exp['spec']))) .groupby('name') .agg(match_spec=('m', max)) .reset_index()['match_spec']) check(explode_groupby)
尝试结果
ERROR <function naive_broadcast at 0x7fe0a4f6c9d0> 不可哈希类型: 'Series' OK <function result_apply at 0x7fe0a4f6ca60> FAIL <function naive_isin at 0x7fe0a4f6c310> 0 False 1 False 2 False Name: spec, dtype: bool ERROR <function vectorization at 0x7fe0a4f6c940> 使用序列设置数组元素。 OK <function explode_groupby at 0x7fe0a4f6ce50>
最优实现方案
1. 列表推导式(推荐,性能最优)
列表推导式是纯Python循环,比df.apply的开销小很多,代码简洁且高效:
df['match_spec'] = [spec in lst for spec, lst in zip(df['spec'], df['lst'])] # 验证结果 print(df['match_spec'].equals(expect['match_spec'])) # 输出 True
2. 正确使用np.vectorize
如果偏好向量化写法,可以用np.vectorize包装逐元素检查的函数,注意要传入正确的元素级函数:
def check_spec_in_lst(spec, lst): return spec in lst vec_check = np.vectorize(check_spec_in_lst) df['match_spec'] = vec_check(df['spec'], df['lst']) # 验证结果 print(df['match_spec'].equals(expect['match_spec'])) # 输出 True
失败原因说明
naive_broadcast:df.spec in df.lst是将整个specSeries与lstSeries比较,不是逐行匹配,因此报错“不可哈希类型: 'Series'”。naive_isin:df.spec.isin(df.lst)的逻辑是检查每个spec值是否存在于所有行的lst列表合并后的集合中,而非当前行的lst列表,因此全部返回False。vectorization:写法错误,np.vectorize需要传入元素级的函数,而不是直接传入df.spec.isin这种Series方法,导致类型不匹配报错。
内容的提问来源于stack exchange,提问作者Helge Jensen
相关产品推荐
相关产品推荐

