如何在Pandas中校验多列数据格式并合并校验结果至单列?
实现多规则校验结果的追加(而非覆盖)方案
我明白你现在的困扰——每次执行一条校验规则时,check列里之前的结果都会被覆盖,没法把多个校验问题用分号合并在一起对吧?下面给你两种可行的实现思路和代码:
方法一:逐规则定位行并追加内容
这种方式会逐个处理每条校验规则,只对符合条件的行追加提示文本,不会覆盖已有结果。
步骤1:准备示例数据
import pandas as pd import numpy as np # 构造你提供的示例数据集 data = { 'id': [0,1,2,3,4,5,6], 'room': ['A-102', np.nan, 'B309', 'C·102', 'E_1089', '27', '27'], 'area': ['world', '24', np.nan, '25', 'hello', np.nan, np.nan], 'situation': ['under construction', 'under construction', np.nan, 'under decoration', 'under decoration', 'under plan', np.nan] } df = pd.DataFrame(data)
步骤2:初始化check列
先把check列初始化为空字符串,方便后续追加内容:
df['check'] = ''
步骤3:逐条执行校验规则
规则1:校验room格式
# 匹配数字、字母、连字符,NaN视为无效 room_invalid = ~df['room'].str.match('^[a-zA-Z\d\-]*$', na=False) # 对符合条件的行追加提示,已有内容则加分号分隔 df.loc[room_invalid, 'check'] = df.loc[room_invalid, 'check'].apply( lambda x: x + 'incorrect room name' if x == '' else x + '; incorrect room name' )
规则2:校验area是否为数字
# 非NaN且不是纯数字的情况触发提示 area_invalid = df['area'].notna() & ~df['area'].str.contains('^\d+$') df.loc[area_invalid, 'check'] = df.loc[area_invalid, 'check'].apply( lambda x: x + 'area is not numbers' if x == '' else x + '; area is not numbers' )
规则3:校验situation包含指定内容
# 包含"under decoration"的情况触发提示 situation_match = df['situation'].str.contains('under decoration', na=False) df.loc[situation_match, 'check'] = df.loc[situation_match, 'check'].apply( lambda x: x + 'decoration is in the content' if x == '' else x + '; decoration is in the content' )
步骤4:处理空值(可选)
把没有校验问题的空字符串转为NaN,和你预期的输出格式一致:
df['check'] = df['check'].replace('', np.nan)
最终输出结果:
| id | room | area | situation | check |
|---|---|---|---|---|
| 0 | A-102 | world | under construction | area is not numbers; decoration is in the content |
| 1 | NaN | 24 | under construction | decoration is in the content |
| 2 | B309 | NaN | NaN | NaN |
| 3 | C·102 | 25 | under decoration | incorrect room name; decoration is in the content |
| 4 | E_1089 | hello | under decoration | area is not numbers; decoration is in the content |
| 5 | 27 | NaN | under plan | NaN |
| 6 | 27 | NaN | NaN | NaN |
方法二:用apply逐行处理(更直观)
如果你觉得逐规则定位行太繁琐,可以用apply函数逐行校验,把所有符合条件的提示收集到列表后再拼接:
def check_single_row(row): check_items = [] # 规则1:校验room if pd.isna(row['room']) or not row['room'].match('^[a-zA-Z\d\-]*$'): check_items.append('incorrect room name') # 规则2:校验area if pd.notna(row['area']) and not row['area'].contains('^\d+$'): check_items.append('area is not numbers') # 规则3:校验situation if pd.notna(row['situation']) and 'under decoration' in row['situation']: check_items.append('decoration is in the content') # 拼接结果,无问题则返回NaN return '; '.join(check_items) if check_items else np.nan df['check'] = df.apply(check_single_row, axis=1)
这个方法逻辑更清晰,和逐规则处理的结果完全一致。
为什么之前的代码会覆盖结果?
你之前用np.where或者df['check'].where()的时候,都是直接给整个check列重新赋值,这会完全覆盖掉之前已经写入的校验内容。而上面的两种方法都是只对符合条件的行进行内容追加,保留了之前的校验结果,从而实现多规则提示的合并。
内容的提问来源于stack exchange,提问作者ah bon
相关产品推荐
相关产品推荐

