如何在Pandas中按目标列分组替换分类列的低频次标签
实现思路
- 先按目标分组列(这里是
att_cat)对数据集分组 - 针对每个分组,单独统计指定分类列的标签出现频率,保留排名前n的高频标签
- 该分组下其余低频标签统一替换为
{分组取值}_{分类列名}格式的通用标签 - 支持为不同分组设置不同的n值,适配不同分组的阈值需求
完整实现代码
import pandas as pd import numpy as np def rare_labels(df, target_col, cat_col, n): """ 参数说明: df: 待处理的DataFrame target_col: 分组依据的目标列名,示例中为'att_cat' cat_col: 要处理的分类列名,示例中为'proto'/'state' n: 保留的高频标签数量,传入int则所有分组共用n;传入dict则key为分组取值,value为对应分组的n """ df = df.copy() def replace_rare(group): group_val = group.name current_n = n[group_val] if isinstance(n, dict) else n # 统计当前分组下分类列的频率,取前n个标签 top_labels = group[cat_col].value_counts().index[:current_n].tolist() # 非top标签替换为指定格式 group[cat_col] = np.where(group[cat_col].isin(top_labels), group[cat_col], f"{group_val}_{cat_col}") return group df = df.groupby(target_col, group_keys=False).apply(replace_rare) return df
使用示例
1. 构造测试数据
data = [ [1, 0.121460, 'tcp', 'FIN', 'Normal'], [2, 0.649902, 'tcp', 'FIN', 'Normal'], [3, 1.623047, 'tcp', 'FIN', 'Normal'], [4, 1.681641, 'tcp', 'FIN', 'Normal'], [5, 0.449463, 'tcp', 'CON', 'Normal'], [6, 0.000009, 'udp', 'INT', 'Generic'], [7, 0.505859, 'udp', 'CON', 'Normal'], [8, 0.000009, 'udp', 'INT', 'Generic'], [9, 0.000009, 'udp', 'INT', 'Generic'], [10, 0.000009, 'tcp', 'INT', 'Generic'], [11, 0.222761, 'unas', 'ECO', 'Normal'], [12, 1.461278, 'tcp', 'CON', 'Normal'], [13, 1.065289, 'arp', 'FIN', 'Normal'], [14, 2.782646, 'udp', 'CON', 'Normal'], [15, 1.457923, 'tcp', 'FIN', 'Normal'], [16, 0.000009, 'udp', 'INT', 'Generic'], [18, 0.125550, 'arp', 'INT', 'Generic'], [19, 0.000009, 'tcp', 'INT', 'Generic'], [20, 0.000009, 'tcp', 'CON', 'Generic'] ] df = pd.DataFrame(data, columns=['id', 'dur', 'proto', 'state', 'att_cat'])
2. 按需求处理不同列
# 处理proto列,所有分组n=2 df = rare_labels(df, target_col='att_cat', cat_col='proto', n=2) # 处理state列,Normal分组n=2,Generic分组n=1 df = rare_labels(df, target_col='att_cat', cat_col='state', n={'Normal':2, 'Generic':1})
运行后得到的结果和预期输出完全一致。
内容的提问来源于stack exchange,提问作者Ernesto Lopez Fune
相关产品推荐
相关产品推荐

