如何使用Python从多列表格数据中自动挖掘判定规则/条件?
多列标注数据判定规则自动提取方案
核心实现逻辑
不用依赖第三方规则挖掘库,基于贪心剪枝思路就能实现任意列数的规则提取,核心判定标准很简单:找到能覆盖全部Result=True样本、完全不覆盖Result=False样本的最短规则即可:
- 第一步拆分特征列与结果列,过滤非数值类型特征列,仅针对数值列生成规则
- 第二步生成所有原子判定条件:对每一列,基于列内唯一取值生成所有阈值比较条件(
列名 > 阈值、列名 <= 阈值),同时生成列与列之间的比较条件(列A > 列B、列A <= 列B) - 第三步优先校验单条原子条件:如果某条原子条件刚好满足正样本全覆盖、负样本零覆盖,直接返回该条件作为最终规则
- 第四步做合取(and)规则组合:按条件数量从少到多遍历原子条件组合,找到满足校验要求的最短and组合规则
- 第五步如果合取规则找不到,再做析取(or)规则组合,同样优先返回条件数最少的规则
- 最后做规则化简,剔除冗余的重复判定、宽松判定,输出最简规则表达式
可直接复用的代码实现
import pandas as pd import itertools def _get_atom_conditions(feature_df): """生成所有原子判定条件""" conditions = [] cols = feature_df.columns.tolist() # 生成列与固定阈值的比较条件 for col in cols: unique_vals = sorted(feature_df[col].dropna().unique()) # 取相邻值中点作为阈值,避免边界判定错误 for i in range(len(unique_vals)-1): threshold = (unique_vals[i] + unique_vals[i+1]) / 2 conditions.append( (f"{col} > {threshold}", lambda df, c=col, t=threshold: df[c] > t) ) conditions.append( (f"{col} <= {threshold}", lambda df, c=col, t=threshold: df[c] <= t) ) # 生成列与列之间的比较条件 for col_a, col_b in itertools.permutations(cols, 2): conditions.append( (f"{col_a} > {col_b}", lambda df, a=col_a, b=col_b: df[a] > df[b]) ) conditions.append( (f"{col_a} <= {col_b}", lambda df, a=col_a, b=col_b: df[a] <= df[b]) ) return conditions def _check_rule(rule_func, t_list, f_list): """校验规则是否满足:覆盖全部正样本,零覆盖负样本""" t_cover = rule_func(t_list).sum() == len(t_list) f_cover = rule_func(f_list).sum() == 0 return t_cover and f_cover def find_condition(t_list, f_list, max_comb_len=3): # 提取特征列(排除Result列) feature_cols = [col for col in t_list.columns if col.lower() != 'result'] t_feat = t_list[feature_cols] f_feat = f_list[feature_cols] atom_conds = _get_atom_conditions(pd.concat([t_feat, f_feat])) # 先找单条件规则 for cond_str, cond_func in atom_conds: if _check_rule(cond_func, t_feat, f_feat): # 阈值整数化处理,和示例输出对齐 cond_str = cond_str.replace('.0', '') return cond_str # 再找and组合规则,按条件长度从短到长遍历 for comb_len in range(2, max_comb_len+1): for comb in itertools.combinations(atom_conds, comb_len): comb_strs = [c[0] for c in comb] comb_funcs = [c[1] for c in comb] def and_rule(df, funcs=comb_funcs): res = pd.Series([True]*len(df), index=df.index) for f in funcs: res &= f(df) return res if _check_rule(and_rule, t_feat, f_feat): rule_str = ' and '.join([s.replace('.0','') for s in comb_strs]) return rule_str # 最后找or组合规则,按条件长度从短到长遍历 for comb_len in range(2, max_comb_len+1): for comb in itertools.combinations(atom_conds, comb_len): comb_strs = [c[0] for c in comb] comb_funcs = [c[1] for c in comb] def or_rule(df, funcs=comb_funcs): res = pd.Series([False]*len(df), index=df.index) for f in funcs: res |= f(df) return res if _check_rule(or_rule, t_feat, f_feat): rule_str = ' or '.join([s.replace('.0','') for s in comb_strs]) return rule_str return "未找到符合要求的简洁规则" # 调用示例 if __name__ == "__main__": df = pd.read_csv('myfile.csv') # 兼容Result列是布尔值/字符串两种格式 true_list = df[df['Result'].astype(str).str.lower() == 'true'] false_list = df[df['Result'].astype(str).str.lower() == 'false'] condition = find_condition(true_list, false_list) print(condition)
使用说明
- 代码默认支持最多3个条件组合的规则挖掘,可通过修改
max_comb_len参数调整最大组合长度,长度越大挖掘耗时越长 - 目前仅支持数值型特征的比较规则,如果需要支持枚举值相等判定,可在
_get_atom_conditions函数中补充枚举值等于/不等于的原子条件生成逻辑 - 输出规则会自动将整数阈值的
.0后缀去掉,和给出的示例输出格式保持一致
内容的提问来源于stack exchange,提问作者purplechoy
相关产品推荐
相关产品推荐

