sklearn——pipeline.py文件解读

博客介绍了pipeline模块,该模块可通过建立一系列转化和算法形成复合算法。其主要组成部分有Pipeline类(管道)、make_pipeline函数、FeatureUnion类(联合特征)以及make_union函数。

The :mod:sklearn.pipeline module implements utilities to build a composite
estimator, as a chain of transforms and estimators.

pipeline模块通过建立一系列的转化和算法,形成一个复合的算法。主要组成部分包括:

  • class Pipeline(_BaseComposition) 管道
  • def make_pipeline(*steps, **kwargs)
  • class FeatureUnion(_BaseComposition, TransformerMixin) 联合特征
  • def make_union(*transformers, **kwargs)

未完待续

<think>这个错误是因为在SimpleImputer中使用'mean'策略时,数据中包含非数值类型(字符串)的列。 我们需要先确保所有特征都是数值类型,或者对分类特征进行编码转换。 解决方案: 1. 检查数据中非数值列,并将其转换为数值(例如通过独热编码或标签编码)。 2. 或者,在填充缺失值之前先进行编码(但注意:缺失值可能出现在分类特征中,所以需要先处理缺失值?这里有一个循环依赖问题,通常的做法是:先分离数值和非数值列,然后分别处理缺失值,再进行编码)。 然而,Lasso本身要求输入是数值型。因此,我们需要将分类特征转换为数值。 修改计划: 步骤1:读取数据后,分离特征和标签。 步骤2:将特征分为数值特征和分类特征(通过数据类型判断)。 步骤3:对数值特征用均值(或中位数)填充缺失值,对分类特征用众数(或指定常量)填充缺失值。 步骤4:对分类特征进行编码(独热编码或标签编码,但注意Lasso对于高基数分类特征可能不太稳定,且独热编码会增加特征维度)。 步骤5:将处理后的数值特征和编码后的分类特征合并。 步骤6:标准化特征(可选,但Lasso通常需要标准化,因为正则化对特征尺度敏感)。 步骤7:使用LassoCV进行特征选择。 但是,由于我们使用了管道,我们可以使用ColumnTransformer来处理不同的列。 另一种方案:如果数据中确实有非数值特征,而我们的任务要求必须使用Lasso,那么我们需要将这些特征转换为数值。如果这些特征是分类特征,则进行编码;如果是文本特征,则需要更复杂的处理(但题目没有说明,我们假设是分类特征)。 这里我们使用ColumnTransformer来分别处理数值和分类特征。 注意:如果数据量很大,独热编码可能会导致特征维度爆炸。我们可以考虑使用其他编码方式(如目标编码),但这里为了简单,使用独热编码。 修改后的代码: 步骤: 1. 分离特征和标签 2. 将特征分为数值特征和分类特征(通过数据类型判断) 3. 创建两个转换器管道:一个用于数值特征(填充+标准化),一个用于分类特征(填充+独热编码) 4. 使用ColumnTransformer组合 5. 然后连接LassoCV 但是注意:ColumnTransformer的输出是一个矩阵,特征名称会改变(独热编码后特征名会扩展),所以我们需要记录特征名称以便后续输出。 由于我们最终需要知道哪些特征被选中,而独热编码后的特征名是组合的,所以我们需要从ColumnTransformer中获取特征名称。 另外,由于LassoCV在独热编码后可能会选择某个类别的虚拟变量(而不是整个分类特征),所以解释结果时需要注意。 如果希望按原始分类特征进行选择(即整个特征是否重要),我们可以这样做:如果一个分类特征的任何一个虚拟变量被选中,则认为该原始特征被选中。但这样会丢失细节(具体哪个类别重要)。这里根据需求选择。 考虑到后续输出到Excel,我们可能需要保留独热编码后的特征选择结果,但也可以进行汇总。 这里我们按独热编码后的结果输出,因为这样能保留更详细的信息。 但是,由于我们使用了管道,获取特征名称需要额外步骤。 实现: 我们将使用ColumnTransformer,然后创建一个包含所有特征名称的列表。 由于独热编码会扩展特征,我们可以通过ColumnTransformer的get_feature_names_out方法来获取处理后的特征名称。 修改后的代码: 注意:由于LassoCV在管道中,我们需要在整个管道拟合之后才能获取系数,然后根据系数不为0的特征索引找到对应的特征名称。 具体步骤: 1. 定义预处理管道(使用ColumnTransformer分别处理数值和分类特征) 2. 将预处理和LassoCV组合成新管道 3. 拟合管道 4. 从LassoCV模型中获取系数,然后根据非零系数得到特征名称(通过ColumnTransformer的get_feature_names_out) 但是,在管道中,ColumnTransformer在拟合之后才能输出特征名称,所以我们可以在拟合后获取特征名称。 代码调整: 由于我们使用make_pipeline,管道步骤的名称是自动生成的,所以我们需要通过索引或名称获取ColumnTransformer步骤。 另一种方式:我们拆分管道,先进行预处理,然后获取特征名称,再训练LassoCV。但这样会破坏管道的封装,交叉验证时会有数据泄露风险。因此,我们使用管道,但拟合后从管道中提取ColumnTransformer,然后获取特征名称。 修改后的代码: 我们将使用命名步骤,这样更容易访问。 由于ColumnTransformer在管道中,我们可以在拟合后通过步骤名称获取它。 但是,我们使用make_pipeline不会自动命名,所以我们可以使用Pipeline并指定步骤名称。 详细步骤: 1. 定义数值特征和分类特征的转换器 2. 使用ColumnTransformer组合,并指定名称 3. 创建包含ColumnTransformer和LassoCV的管道 4. 拟合 5. 从管道中获取ColumnTransformer,然后调用get_feature_names_out获取所有特征名称 6. 从LassoCV步骤中获取系数,选择非零系数的特征 但是注意:在交叉验证中,特征选择是在整个预处理后的数据上进行的,所以这样是安全的。 代码实现: 假设我们的特征中有数值型和分类型。我们首先自动识别分类特征:即数据类型为'object'或'category'的列。 注意:可能有些数值型特征被误读为字符串,所以最好先检查数据。但这里我们按照数据类型自动判断。 如果数据中没有分类特征,则跳过分类转换器。 我们使用以下方法: 数值特征:填充缺失值+标准化 分类特征:填充缺失值(用众数)+独热编码 代码: 由于错误信息中出现了字符串'v3.1.0',说明该列是字符串类型,我们将其视为分类特征。 修改后的完整代码(包括输出到Excel):</think>这个错误表明您的数据中包含非数值类型(如字符串),而`SimpleImputer`的`mean`策略只能处理数值数据。让我们修改代码,使其能正确处理混合数据类型(数值和分类特征): ```python import pandas as pd import numpy as np from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.linear_model import LassoCV from sklearn.model_selection import KFold import openpyxl from sklearn.exceptions import ConvergenceWarning import warnings # 忽略Lasso收敛警告 warnings.filterwarnings("ignore", category=ConvergenceWarning) # 1. 读取数据 df = pd.read_excel('F.xlsx') # 2. 分离特征和标签 X = df.iloc[:, :-1] # 所有特征列 y = df.iloc[:, -1] # 最后一列是类别标签View # 3. 自动识别数值和分类特征 numeric_features = X.select_dtypes(include=['int64', 'float64']).columns.tolist() categorical_features = X.select_dtypes(include=['object', 'category']).columns.tolist() print(f"检测到数值特征: {len(numeric_features)}个") print(f"检测到分类特征: {len(categorical_features)}个") # 4. 创建预处理转换器 preprocessor = ColumnTransformer( transformers=[ ('num', Pipeline(steps=[ ('imputer', SimpleImputer(strategy='median')), # 数值特征用中位数填充 ('scaler', StandardScaler()) # 标准化 ]), numeric_features), ('cat', Pipeline(steps=[ ('imputer', SimpleImputer(strategy='most_frequent')), # 分类特征用众数填充 ('onehot', OneHotEncoder(handle_unknown='ignore')) # 独热编码 ]), categorical_features) ]) # 5. 创建完整管道 pipeline = Pipeline(steps=[ ('preprocessor', preprocessor), ('lassocv', LassoCV(cv=5, random_state=42, max_iter=10000)) # 增加最大迭代次数 ]) # 6. 训练模型 pipeline.fit(X, y) lasso_model = pipeline.named_steps['lassocv'] # 7. 获取特征名称(包括独热编码后的分类特征) # 获取数值特征名称 numeric_feature_names = numeric_features # 获取分类特征名称(独热编码后) if categorical_features: cat_encoder = pipeline.named_steps['preprocessor'].named_transformers_['cat'].named_steps['onehot'] cat_feature_names = cat_encoder.get_feature_names_out(categorical_features).tolist() else: cat_feature_names = [] # 合并所有特征名称 all_feature_names = numeric_feature_names + cat_feature_names # 8. 提取重要特征和系数 feature_coefs = lasso_model.coef_ selected_features = np.where(np.abs(feature_coefs) > 0.001)[0] # 使用小阈值避免浮点误差 selected_feature_names = [all_feature_names[i] for i in selected_features] selected_coefs = feature_coefs[selected_features] # 9. 创建结果DataFrame results_df = pd.DataFrame({ '特征名称': selected_feature_names, 'Lasso系数': selected_coefs, '系数绝对值': np.abs(selected_coefs) }).sort_values(by='系数绝对值', ascending=False) # 10. 添加模型信息表 model_info = pd.DataFrame({ '指标': ['最佳alpha', '筛选特征数', '原始特征数', '交叉验证折数', '最大迭代次数'], '值': [lasso_model.alpha_, len(selected_features), len(all_feature_names), 5, 10000] }) # 11. 导出到Excel with pd.ExcelWriter('特征筛选结果.xlsx') as writer: # 特征筛选结果表 results_df.to_excel(writer, sheet_name='重要特征', index=False) # 模型信息表 model_info.to_excel(writer, sheet_name='模型信息', index=False) # 原始数据表(带筛选标记) df_out = df.copy() # 标记原始特征是否被选中 for col in df_out.columns[:-1]: if col in selected_feature_names or any(s.startswith(col + '_') for s in selected_feature_names): df_out[col + '_选中'] = '是' else: df_out[col + '_选中'] = '否' df_out.to_excel(writer, sheet_name='原始数据', index=False) # 获取Excel工作簿和工作表对象 workbook = writer.book worksheet = writer.sheets['重要特征'] # 设置列宽 worksheet.column_dimensions['A'].width = 35 worksheet.column_dimensions['B'].width = 15 worksheet.column_dimensions['C'].width = 15 # 添加条件格式 red_fill = openpyxl.styles.PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid') green_fill = openpyxl.styles.PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid') for row in range(2, len(results_df) + 2): cell = worksheet[f'B{row}'] if cell.value > 0: cell.fill = green_fill elif cell.value < 0: cell.fill = red_fill print("="*50) print(f"结果已成功导出到: 特征筛选结果.xlsx") print(f"包含三个工作表: 1.重要特征 2.模型信息 3.原始数据") print(f"筛选出 {len(selected_features)} 个重要特征(共 {len(all_feature_names)} 个特征)") print(f"最佳正则化参数 alpha: {lasso_model.alpha_:.6f}") print("="*50) ``` ### 问题修复说明: 1. **数据类型处理**: - 使用`select_dtypes`自动识别数值特征和分类特征 - 数值特征:`int64`和`float64`类型 - 分类特征:`object`和`category`类型 2. **分别处理不同特征类型**: - 数值特征: - 使用`median`策略填充缺失值(对异常值更鲁棒) - 标准化处理(`StandardScaler`) - 分类特征: - 使用`most_frequent`策略填充缺失值(众数填充) - 独热编码(`OneHotEncoder`)转换为数值形式 3. **特征名称处理**: - 自动获取独热编码后的特征名称(格式:`原特征名_类别值`) - 合并所有特征名称用于结果输出 4. **Lasso优化**: - 增加`max_iter=10000`确保收敛 - 添加`ConvergenceWarning`忽略避免警告干扰 - 使用小阈值(0.001)而非严格零避免浮点误差 5. **结果标记优化**: - 在原始数据表中为每个特征添加`_选中`列 - 智能识别分类特征是否被选中(检查特征名前缀) ### 使用说明: 1. **安装必要库**: ```bash pip install pandas numpy scikit-learn openpyxl ``` 2. **处理特殊值**: - 如果数据中有特殊字符串(如'v3.1.0'),会被识别为分类特征 - 每个唯一值会生成一个新的独热编码特征 3. **结果解读**: - 分类特征会以`原特征名_类别值`形式显示 - 系数正负表示特征与目标的正/负相关性 - 系数绝对值大小表示特征重要性 4. **自定义选项**: - 调整阈值:修改`np.abs(feature_coefs) > 0.001`中的0.001 - 更改填充策略:修改`SimpleImputer`的`strategy`参数 - 增加迭代次数:修改`max_iter`值(如果收敛困难) ### 输出示例: ``` ================================================== 结果已成功导出到: 特征筛选结果.xlsx 包含三个工作表: 1.重要特征 2.模型信息 3.原始数据 筛选出 12 个重要特征(共 45 个特征) 最佳正则化参数 alpha: 0.023145 ================================================== ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值