优化多分类数据集下KDE交集面积计算的Python函数问题
搞定多分类下KDE交集面积的鲁棒计算问题
我来帮你把代码优化成支持任意类别数的版本,先拆解下问题,再一步步解决:
先修正你代码里的小bug
你原来的类别提取和参数引用有两处错误:
data.target_variable_name.unique()是错的,因为target_variable_name是函数传入的字符串参数,得用索引方式data[target_variable_name].unique()- 后面的
target_name是笔误,要和参数名target_variable_name统一
核心逻辑:多分类要算所有类别对的交集
对于多分类任务,我们需要计算每两个不同类别之间的KDE交集(避免重复计算,比如只算(0,1)不算(1,0)),可以用itertools.combinations生成所有不重复的类别对。
完整优化后的代码
import numpy as np import pandas as pd from scipy.stats import gaussian_kde from itertools import combinations def intersection_area(data, bandwidth, margin, target_variable_name): # 预处理:删除缺失值,分离自变量和目标变量 data = data.dropna() feature_names = data.drop(columns=[target_variable_name], axis=1).columns.tolist() # 获取所有唯一类别,转成列表 classes = data[target_variable_name].unique().tolist() # 生成所有不重复的类别对(比如(0,1)、(0,2),不会重复生成(1,0)) class_pairs = list(combinations(classes, 2)) # 存储结果的列表,方便后续转成DataFrame results = [] # 遍历每个特征 for feature in feature_names: # 遍历每个类别对 for class_a, class_b in class_pairs: # 提取当前类别对对应的特征数据(这就是你卡住的部分,现在搞定了) x_a = data.loc[data[target_variable_name] == class_a, feature] x_b = data.loc[data[target_variable_name] == class_b, feature] # 计算两个类别的KDE kde_a = gaussian_kde(x_a, bw_method=bandwidth) kde_b = gaussian_kde(x_b, bw_method=bandwidth) # 确定x轴范围:覆盖两个类别的数据范围,再加上margin扩展(修正了你原来的min错误) x_min = min(x_a.min(), x_b.min()) x_max = max(x_a.max(), x_b.max()) dx = margin * (x_max - x_min) x_range = np.linspace(x_min - dx, x_max + dx, 500) # 计算KDE在x轴上的取值 kde_a_vals = kde_a(x_range) kde_b_vals = kde_b(x_range) # 计算交集区域的面积 intersection_vals = np.minimum(kde_a_vals, kde_b_vals) area = np.trapz(intersection_vals, x_range) # 把结果存入列表 results.append({ 'feature': feature, 'class_pair': f"({class_a}, {class_b})", 'intersection_area': round(area, 4) }) # 返回结构化的结果DataFrame,方便查看和后续分析 return pd.DataFrame(results)
用你的模拟数据集测试
from sklearn.datasets import make_classification # 生成4分类模拟数据集 X, y = make_classification( n_samples=50000, n_features=6, n_informative=6, n_redundant=0, n_repeated=0, n_classes=4, n_clusters_per_class=3, class_sep=0.95, flip_y=0.2, weights=[0.7, 0.2, 0.1], shuffle=True, random_state=93 ) dataset_x = pd.DataFrame({ 'var1': X[:, 0], 'var2': X[:, 1], 'var3': X[:, 2], 'var4': X[:, 3], 'var5': X[:, 4], 'var6': X[:, 5] }) dataset_y = pd.DataFrame({'target': y}) sample_dataset = pd.concat([dataset_x, dataset_y], axis=1) # 调用函数计算交集面积 result_df = intersection_area(sample_dataset, bandwidth=0.5, margin=0.1, target_variable_name='target') print(result_df.head(10))
几个关键细节说明
- 用
itertools.combinations生成类别对,避免重复计算,节省资源 - 修正了你原来x轴范围的错误:把
x_max = min(...)改成了max(...),不然会截断KDE的尾部,导致面积计算不准 - 返回的是DataFrame格式结果,比单纯打印更方便后续分析、排序或可视化
内容的提问来源于stack exchange,提问作者Gerard
相关产品推荐
相关产品推荐

