Python案例如何用Scikit-learn做互信息选择

wen python案例 2

本文目录导读:

Python案例如何用Scikit-learn做互信息选择

  1. 什么是互信息?
  2. 基础案例
  3. 实际应用案例
  4. 实际数据应用案例
  5. 重要参数说明
  6. 注意事项

我来为你详细介绍如何使用Scikit-learn进行互信息(Mutual Information)特征选择。

什么是互信息?

互信息用于衡量两个变量之间的依赖性,可以捕捉线性和非线性关系,值越大表示特征与目标变量的关联越强。

基础案例

示例1:分类问题的互信息选择

import numpy as np
import pandas as pd
from sklearn.feature_selection import mutual_info_classif, SelectKBest
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
feature_names = iris.feature_names
# 计算互信息分数
mi_scores = mutual_info_classif(X, y, random_state=42)
# 创建DataFrame直观显示
mi_df = pd.DataFrame({
    'feature': feature_names,
    'mi_score': mi_scores
})
mi_df = mi_df.sort_values('mi_score', ascending=False)
print("互信息分数(降序):")
print(mi_df)
print("\n" + "="*50)
# 选择Top-K特征
selector = SelectKBest(score_func=mutual_info_classif, k=2)
X_selected = selector.fit_transform(X, y)
# 显示选中的特征
selected_indices = selector.get_support(indices=True)
print(f"\n选中的特征索引:{selected_indices}")
print(f"选中的特征名称:{[feature_names[i] for i in selected_indices]}")
print(f"原始特征维度:{X.shape}")
print(f"选择后特征维度:{X_selected.shape}")
# 可视化互信息分数
plt.figure(figsize=(10, 6))
plt.bar(mi_df['feature'], mi_df['mi_score'])'互信息特征重要性', fontsize=14)
plt.xlabel('特征', fontsize=12)
plt.ylabel('互信息分数', fontsize=12)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

示例2:回归问题的互信息选择

from sklearn.feature_selection import mutual_info_regression
from sklearn.datasets import load_diabetes
# 加载糖尿病数据集(回归问题)
diabetes = load_diabetes()
X, y = diabetes.data, diabetes.target
feature_names = diabetes.feature_names
# 计算互信息分数(回归用mutual_info_regression)
mi_scores_reg = mutual_info_regression(X, y, random_state=42)
# 可视化
mi_df_reg = pd.DataFrame({
    'feature': feature_names,
    'mi_score': mi_scores_reg
}).sort_values('mi_score', ascending=True)
plt.figure(figsize=(10, 8))
plt.barh(mi_df_reg['feature'], mi_df_reg['mi_score'])
plt.xlabel('互信息分数')'回归问题 - 互信息特征重要性')
plt.tight_layout()
plt.show()

实际应用案例

示例3:完整的特征选择流程

import warnings
warnings.filterwarnings('ignore')
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
# 生成样本数据
X, y = make_classification(n_samples=1000, n_features=20, n_informative=5,
                          n_redundant=5, n_repeated=5, random_state=42)
# 分割数据
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
print(f"原始特征数量:{X.shape[1]}")
# 1. 计算互信息
mi_scores = mutual_info_classif(X_train, y_train, random_state=42)
# 2. 设置阈值选择特征
threshold = np.percentile(mi_scores, 50)  # 选择分数前50%的特征
selected_features = np.where(mi_scores > threshold)[0]
print(f"选择的特征数量:{len(selected_features)}")
print(f"互信息分数范围:{mi_scores.min():.4f} - {mi_scores.max():.4f}")
print(f"选择阈值:{threshold:.4f}")
# 3. 特征选择
X_train_selected = X_train[:, selected_features]
X_test_selected = X_test[:, selected_features]
# 4. 训练和评估
rf_clf = RandomForestClassifier(random_state=42)
rf_clf.fit(X_train_selected, y_train)
y_pred = rf_clf.predict(X_test_selected)
accuracy_full = accuracy_score(y_test, y_pred)
# 与全部特征的对比
rf_clf_full = RandomForestClassifier(random_state=42)
rf_clf_full.fit(X_train, y_train)
y_pred_full = rf_clf_full.predict(X_test)
accuracy_selected = accuracy_score(y_test, y_pred_full)
print(f"\n全部特征准确率:{accuracy_full:.4f}")
print(f"选择特征准确率:{accuracy_selected:.4f}")

示例4:自动确定最佳特征数量

from sklearn.feature_selection import SelectPercentile
# 使用SelectPercentile选择百分比特征
selector_percent = SelectPercentile(score_func=mutual_info_classif, percentile=30)
X_percent = selector_percent.fit_transform(X_train, y_train)
print(f"保留30%的特征后维度:{X_percent.shape}")
# 通过交叉验证选择最佳k值
from sklearn.model_selection import cross_val_score
def find_best_k(X, y, k_range=[5, 10, 15, 20]):
    """通过交叉验证找到最佳的K值"""
    best_score = 0
    best_k = k_range[0]
    for k in k_range:
        selector = SelectKBest(score_func=mutual_info_classif, k=k)
        X_selected = selector.fit_transform(X, y)
        # 交叉验证
        scores = cross_val_score(RandomForestClassifier(), 
                                X_selected, y, cv=3)
        mean_score = scores.mean()
        print(f"K={k}: CV准确率={mean_score:.4f} (±{scores.std():.4f})")
        if mean_score > best_score:
            best_score = mean_score
            best_k = k
    return best_k, best_score
print("\n寻找最佳特征数量:")
best_k, best_score = find_best_k(X_train, y_train)
print(f"\n最佳特征数量:{best_k},准确率:{best_score:.4f}")

实际数据应用案例

示例5:处理真实世界数据

import seaborn as sns
from sklearn.impute import SimpleImputer
# 加载Titanic数据集
titanic = sns.load_dataset('titanic')
print("原始数据形状:", titanic.shape)
# 数据预处理
# 选择数值特征
numeric_features = ['pclass', 'age', 'sibsp', 'parch', 'fare']
categorical_features = ['sex', 'embarked', 'class', 'who', 'adult_male', 'deck', 'embark_town']
# 处理目标变量
y_titanic = titanic['survived']
# 处理数值特征
X_numeric = titanic[numeric_features].copy()
# 处理缺失值
imputer = SimpleImputer(strategy='median')
X_numeric_imputed = imputer.fit_transform(X_numeric)
# 处理类别特征
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
X_categorical = pd.DataFrame()
for col in categorical_features:
    if col in titanic.columns:
        # 填充缺失值
        temp = titanic[col].fillna('Unknown')
        X_categorical[col] = le.fit_transform(temp)
# 合并特征
X_titanic = np.hstack([X_numeric_imputed, X_categorical])
print(f"处理后特征数量:{X_titanic.shape[1]}")
# 计算互信息
mi_scores_titanic = mutual_info_classif(X_titanic, y_titanic, random_state=42)
# 特征重要性排序
feature_names_titanic = numeric_features + [col for col in categorical_features if col in titanic.columns]
mi_titanic_df = pd.DataFrame({
    'feature': feature_names_titanic,
    'mi_score': mi_scores_titanic
}).sort_values('mi_score', ascending=False)
print("\n特征重要性排名(前10):")
print(mi_titanic_df.head(10))
# 选择Top-5特征
selector_titanic = SelectKBest(score_func=mutual_info_classif, k=5)
X_titanic_selected = selector_titanic.fit_transform(X_titanic, y_titanic)
selected_features_titanic = np.array(feature_names_titanic)[selector_titanic.get_support()]
print(f"\n选择的Top-5特征:{selected_features_titanic}")

重要参数说明

# mutual_info_classif的主要参数
mi_scores = mutual_info_classif(
    X,                    # 特征矩阵
    y,                    # 目标变量
    discrete_features='auto',  # 是否将特征视为离散特征
    n_neighbors=3,        # 用于估计的邻居数
    copy=True,           # 是否复制数据
    random_state=42      # 随机种子
)
# SelectKBest的主要参数
selector = SelectKBest(
    score_func=mutual_info_classif,  # 评分函数
    k=10,                           # 选择特征数量
)

注意事项

# 1. 数据标准化不影响互信息
# 互信息不依赖数据分布,无需标准化
# 2. 处理离散特征
# 对于离散特征,设置discrete_features参数
mi_scores_mixed = mutual_info_classif(
    X, y,
    discrete_features=[True, True, False, False],  # 指定哪些特征是离散的
    random_state=42
)
# 3. 互信息值范围
# 理论范围:[0, +∞)
# 实际中通常较小,需要进行归一化处理
mi_normalized = mi_scores / mi_scores.max()  # 归一化到[0,1]
print(f"归一化互信息分数:{mi_normalized[:5]}")

互信息特征选择的优势:

  1. 可以捕捉非线性关系
  2. 不依赖数据缩放
  3. 可处理多种数据类型
  4. 理论解释性强

适用场景:

  • 特征数量多,需要降维
  • 特征与目标关系复杂
  • 需要了解特征重要性

通过以上案例,你可以根据实际问题选择合适的互信息特征选择方法。

抱歉,评论功能暂时关闭!