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

如何用Pandera校验DataFrame中一列子串是否存在于另一列?

问题

我定义了如下 Pandas DataFrameSchema:

Schema = DataFrameSchema(
   columns={
        'Complete_Name': Column(name='Complete_Name', dtype='string', nullable=True),
        'Surname': Column(name='Surname', dtype='string', nullable=True),
    }, 
   checks=check_cross_check_name_and_surname, 
   coerce=True, 
   strict=True, 
   ordered=False, 
   unique_column_names=True, 
   metadata=None
)

需要实现的校验逻辑等价于如下 SQL 查询(每条Complete_Name必须包含对应的Surname):

SELECT * FROM database.user 
WHERE Complete_Name LIKE '%'||Surname||'%'

我尝试了以下几种写法,但都没达到预期效果:

check_cross_check_name_and_surname = [pa.Check(lambda df: df["Complete_Name"].str.contains(df["Surname"], regex=True), element_wise=True, ignore_na=False)]

check_cross_check_name_and_surname = [pa.Check(lambda df: df["Complete_Name"].str.contains(df["Surname"], regex=False), element_wise=True, ignore_na=False)]

check_cross_check_name_and_surname = [pa.Check(lambda df: df["Surname"] in df["Complete_Name"], element_wise=True, ignore_na=False)] 

请问应该如何编写check_cross_check_name_and_surname,才能在调用Schema.validate(dataframe)时正确执行校验?

正确的校验逻辑实现

之前的写法存在两个核心问题:

  1. 设置element_wise=True时,Check的lambda参数是单条数据的Series而非整个DataFrame,直接用df["Complete_Name"]会引发索引或取值错误。
  2. str.contains默认是向量化匹配,当传入Series作为匹配值时,无法逐行对应匹配,必须显式处理每行的对应关系。

推荐两种可行的实现方式:

方式一:逐行处理(直观易维护)

利用apply逐行检查,同时处理空值场景(因为字段允许为空):

from pandera import Check

def check_name_contains_surname(df):
    # 空值行直接通过校验
    null_mask = df[["Complete_Name", "Surname"]].isna().any(axis=1)
    # 非空行检查Complete_Name是否包含对应Surname
    match_mask = df.apply(lambda row: row["Surname"] in row["Complete_Name"], axis=1)
    # 所有行都满足条件则返回True
    return (null_mask | match_mask).all()

check_cross_check_name_and_surname = [Check(check_name_contains_surname)]

方式二:向量化处理(性能更优)

用numpy.vectorize包装匹配逻辑,实现向量化运算:

import numpy as np
import pandas as pd
from pandera import Check

def contains_surname(full_name, surname):
    if pd.isna(full_name) or pd.isna(surname):
        return True
    return surname in full_name

vectorized_check = np.vectorize(contains_surname)

check_cross_check_name_and_surname = [
    Check(lambda df: vectorized_check(df["Complete_Name"], df["Surname"]).all())
]

关键注意点

  • 必须移除element_wise=True,因为我们需要对整个DataFrame做跨行校验,而非单条数据的字段校验。
  • 空值处理:由于字段设置了nullable=True,所以只要任一字段为空,校验自动通过;如果需要空值也触发校验失败,可以删除空值判断逻辑,直接返回surname in full_name(此时空值会返回False,触发校验错误)。
  • Python的in运算符和SQL的LIKE '%...%'行为完全一致,都是简单的子串匹配,不需要启用正则模式。

内容的提问来源于stack exchange,提问作者Rafael Cassemiro Tezzotto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 09:24:54