ML.NET库学习006:成人人口普查数据分析与分类预测
文章目录
- ML.NET库学习006:成人人口普查数据分析与分类预测
- 概述
- 数据集
- 数据字段解释
- 为何数据准备很重要
- 主要功能与模块
- 数据准备
- 机器学习工作流
- 代码结构说明
- 数据准备模块
- 机器学习工作流
- 数据加载与分割
- 特征工程与模型训练
- 模型评估与预测
- 实现细节与注意事项
- 数据准备模块
- 机器学习工作流
- 性能优化
- 项目优势
- LightGBM 分类器原理说明
- 总结
ML.NET库学习006:成人人口普查数据分析与分类预测
概述
本项目使用 C# 和 ML.NET 对美国成人人口普查数据进行分析和分类预测。目标是根据输入的数据特征(如年龄、职业、教育程度等)预测个人的收入是否超过 50,000 美元。
数据集
此示例演示如何通过使用 IEnumerable 将数据库用作 ML.NET 管道的数据源。由于数据库被视为任何其他数据源,因此可以查询数据库并将其结果用于训练和预测场景。
企业用户需要使用其公司数据库中的现有数据集来训练和预测 ML.NET 模型。尽管在大多数情况下,在训练机器学习模型之前都需要清理和准备数据,但许多企业对数据库非常熟悉,并且更喜欢将集中化和安全的数据保留在数据库服务器中,而不是处理导出的纯文本文件。
age, workclass, fnlwgt, education, education-num, marital-status, occupation, relationship, ethnicity, sex, capital-gain, capital-loss, hours-per-week, native-country, label(IsOver50K)
39, State-gov, 77516, Bachelors, 13, Never-married, Adm-clerical, Not-in-family, White, Male, 2174, 0, 40, United-States, 0
50, Self-emp-not-inc, 83311, Bachelors, 13, Married-civ-spouse, Exec-managerial, Husband, White, Male, 0, 0, 13, United-States, 0
38, Private, 215646, HS-grad, 9, Divorced, Handlers-cleaners, Not-in-family, White, Male, 0, 0, 40, United-States, 0
53, Private, 234721, 11th, 7, Married-civ-spouse, Handlers-cleaners, Husband, Black, Male, 0, 0, 40, United-States, 0
28, Private, 338409, Bachelors, 13, Married-civ-spouse, Prof-specialty, Wife, Black, Female, 0, 0, 40, Cuba, 0
37, Private, 284582, Masters, 14, Married-civ-spouse, Exec-managerial, Wife, White, Female, 0, 0, 40, United-States, 0
数据字段解释
-
age:
表示个人的年龄。这是一个数值型字段。 -
workclass:
表示工作类型或职业类别,如“Private”(私营)、“Self-emp-not-inc”(自雇但无公司)、“Federal-gov”(联邦政府)等。 -
fnlwgt:
这是“final weight”的缩写,表示人口普查中的家庭权重。这个字段用于调整抽样数据的代表性,确保结果能够反映总体情况。 -
education:
表示教育程度,如“Bachelors”(学士学位)、 “Some college”(完成部分大学课程)、“HS-grad”(高中毕业)等。 -
education-num:
表示教育程度的编号,通常是对教育层次进行量化后的数值。例如,“HS-grad”可能被编码为9,“Bachelors”为13。 -
marital-status:
表示婚姻状况,如“Married-civ-spouse”(已婚且有合法配偶)、“Never-married”(未婚)、“Divorced”(离婚)等。 -
occupation:
表示职业类型,如“Tech-support”(技术支持)、 “Sales”(销售)、“Managerial”(管理职位)等。 -
relationship:
表示家庭关系,如“Husband”(丈夫)、 “Wife”(妻子)、 “Child”(子女)、 “Own-child”(自己孩子)等。 -
ethnicity:
表示种族或民族背景,常见的包括“White”(白人)、 “Black”(黑人)、 “Asian”(亚洲人)、 “Hispanic”(西班牙裔)等。 -
sex:
表示性别,通常分为“Male”(男性)和“Female”(女性)两类。 -
capital-gain:
表示资本收益,即来自投资、股票等的收入。 -
capital-loss:
表示资本损失,与资本收益相反,指投资上的亏损。 -
hours-per-week:
表示每周工作小时数,通常用于衡量工作强度或兼职/全职状态。 -
native-country:
表示原籍国,即个人的国籍或出生地,如“United-States”(美国)、 “Mexico”(墨西哥)、 “Germany”(德国)等。 -
label(IsOver50K):
这是目标字段,通常是一个二分类变量,表示该个体的年收入是否超过5万美元。例如,“>50K”表示收入超过5万美元,“<=50K”表示不超过5万美元。
为何数据准备很重要
你不能直接对事务表执行简单的联接查询? - 即使技术上可以从任何联接查询创建 IEnumerable,但在大多数实际情况下,这对于机器学习算法/训练器来说并不奏效。
数据准备之所以重要,是因为大多数机器学习训练器/算法需要数据以非常特定的方式格式化或输入特征列必须是特定的数据类型,因此数据集通常在训练模型之前需要进行一些准备。你还需要清理数据,有些数据源可能包含缺失值(空值、未定义),或者无效值(数据可能需要转换为不同的比例,你可能需要对特征中的数值进行上采样或归一化等),从而使训练过程要么失败,要么产生不准确的结果,甚至产生误导性的结果。因此,在几乎所有情况下都需要在训练 ML 模型之前进行数据准备。
主要功能与模块
数据准备
- 下载数据集:从指定的 URL 下载成人人口普查数据。
- 数据清洗与解析:将原始数据解析为结构化的对象,并进行必要的数据转换和验证。
- 数据存储:将解析后的数据存储到本地数据库中,便于后续的数据处理和分析。
机器学习工作流
- 数据加载:从数据库中加载数据,并将其转换为 ML.NET 可用的数据视图。
- 数据分割:将数据集划分为训练集和测试集,用于模型的训练和评估。
- 特征工程:
- 对分类变量(如婚姻状况、职业等)进行独热编码(One-Hot Encoding),将其转换为二进制特征向量。
- 将多个独热编码后的特征拼接成一个连续的特征向量,用于后续的模型训练。
- 模型训练:使用 LightGBM 分类器对数据进行训练,构建分类模型。
- 模型评估:在测试集上使用训练好的模型进行预测,并计算模型的各项性能指标(如准确率、召回率等)。
代码结构说明
数据准备模块
- 下载数据集
public static void CreateDatabase(string url) { var dataset = ReadRemoteDataset(url); // ... 数据清洗与存储逻辑 ... }
- 数据清洗与解析
var data = dataset .Skip(1) // 跳过表头行 .Select(l => l.Split(',')) .Where(row => row.Length > 1) .Select(row => new AdultCensus() { Age = int.Parse(row[0]), Workclass = row[1], Education = row[3], MaritalStatus = row[5], Occupation = row[6], Relationship = row[7], Race = row[8], Sex = row[9], CapitalGain = row[10], CapitalLoss = row[11], HoursPerWeek = int.Parse(row[12]), NativeCountry = row[13], Label = (int.Parse(row[14]) == 1) ? true : false });
- 数据存储
db.AdultCensus.AddRange(data); var count = db.SaveChanges(); Console.WriteLine($"Total count of items saved to database: {count}");
机器学习工作流
数据加载与分割
var mlContext = new MLContext(seed: 1);
// 加载数据并划分训练集和测试集
var dataView = mlContext.Data.LoadFromEnumerable(QueryData());
var trainTestData = mlContext.Data.TrainTestSplit(dataView);
特征工程与模型训练
// 构建特征工程管道:对分类变量进行独热编码,并拼接特征向量
var pipeline = mlContext.Transforms.Categorical.OneHotEncoding(new[] {
new InputOutputColumnPair("MsOHE", "MaritalStatus"),
new InputOutputColumnPair("OccOHE", "Occupation"),
new InputOutputColumnPair("RelOHE", "Relationship"),
new InputOutputColumnPair("SOHE", "Sex"),
new InputOutputColumnPair("NatOHE", "NativeCountry")
}, OneHotEncodingEstimator.OutputKind.Binary)
.Append(mlContext.Transforms.Concatenate("Features", "MsOHE", "OccOHE", "RelOHE", "SOHE", "NatOHE"))
.Append(mlContext.BinaryClassification.Trainers.LightGbm());
// 训练模型
Console.WriteLine("Training model...");
var model = pipeline.Fit(trainTestData.TrainSet);
模型评估与预测
// 使用训练好的模型进行预测并计算性能指标
var prediction = model.Transform(trainTestData.TestSet);
var metrics = mlContext.BinaryClassification.Evaluate(prediction);
Console.WriteLine($"Accuracy: {metrics.Accuracy}");
Console.WriteLine($"Recall: {metrics.Recall}");
// ... 其他评估指标 ...
实现细节与注意事项
数据准备模块
- 数据下载:使用
HttpClient
下载数据集,并将其内容转换为字符串流。 - 异常处理:在数据解析过程中,需要对可能出现的格式错误进行验证和处理,确保数据清洗过程的健壮性。
- 数据库存储:可以使用 Entity Framework Core 等 ORM 工具简化数据库操作,提高代码可维护性和执行效率。
机器学习工作流
- 独热编码:对分类变量进行独热编码是特征工程的重要步骤,能够将类别信息转化为模型可理解的数值形式。
- 特征拼接:通过拼接多个独热编码后的特征向量,可以构建更丰富的特征表示,有助于提升模型性能。
- LightGBM 分类器:选择 LightGBM 作为分类器是因为其高效的训练速度和优秀的模型性能,在处理大规模数据时表现尤为突出。
性能优化
- 数据预处理:在数据准备阶段,尽量减少数据冗余和重复,确保数据的干净和一致。
- 特征选择与降维:可以根据领域知识或统计方法进行特征选择,去除无关特征,降低模型复杂度。
- 超参数调优:通过网格搜索等方法对 LightGBM 的超参数(如学习率、树深度等)进行调优,进一步提升模型性能。
项目优势
- 代码结构清晰:整个项目的代码分为数据准备和机器学习两个主要模块,每个模块内部逻辑明确,便于理解和维护。
- 可扩展性高:通过使用数据库存储中间结果,使得数据处理过程具备良好的扩展性和复用性。
- 性能优化:通过合理的特征工程和模型选择,确保了模型在预测准确率和训练效率之间的良好平衡。
LightGBM 分类器原理说明
1. 梯度提升框架
LightGBM 是一个基于梯度提升(Gradient Boosting)的框架。梯度提升是一种集成学习的方法,通过训练多个弱分类器(如决策树),然后将其组合起来形成一个强分类器。
-
基本思想: 每个新模型都试图拟合前一个模型的残差(即预测值与真实值之间的误差)。通过不断迭代,逐步优化模型的预测能力。
-
优势:
- 高准确性:通过多棵决策树的组合,能够捕捉复杂的模式。
- 可解释性:每一棵决策树都是简单的规则集,整体模型可以通过特征重要性进行解释。
2. 基于直方图的算法
LightGBM 使用了一种基于直方图(Histogram-based)的优化方法来提升训练效率。这种方法将特征值分桶处理,减少了计算量。
-
实现步骤:
- 将每个特征的取值范围离散化为若干个桶。
- 对于每一个节点,计算不同桶对目标函数的贡献。
- 根据这些贡献选择最佳的分割点和分割特征。
-
优势:
- 计算速度快:通过分桶减少计算量,使得每棵决策树的训练时间大大缩短。
- 内存占用低:直方图方法在内存中更高效地存储和处理数据。
3. Leaf-wise 的生长策略
与传统的基于节点(Node-wise)的分裂不同,LightGBM 使用了Leaf-wise的策略来生成新的叶子节点。这种策略能够更好地控制树的深度,并且有助于防止过拟合。
-
工作原理:
- 新增的叶子节点只在当前叶子的条件下进行分割,而不是在整个树中寻找最优的分割点。
- 这种方式可以逐步优化每一层的叶子节点,使得树的生长更加灵活和高效。
-
优势:
- 更好的控制树的深度,减少过拟合的风险。
- 提高模型训练效率,特别是在大数据集上。
4. 混合策略
LightGBM 结合了基于直方图的算法和Leaf-wise的生长策略,形成了高效的训练方法。
- 优势:
- 直方图方法提升了计算速度。
- Leaf-wise 策略优化了树的结构,提高了模型性能。
5. 分布式训练
LightGBM 支持分布式训练,能够在多台机器上并行处理数据,适用于大规模数据集。
-
实现机制:
- 将数据分片到不同的工作节点。
- 各节点独立地进行直方图构建和树的生长。
- 定期同步各节点的结果,确保模型的一致性。
-
优势:
- 处理大数据集时效率更高。
- 支持弹性扩展,适应不同规模的数据量。
6. 正则化与防止过拟合
LightGBM 提供了多种正则化机制来防止过拟合,确保模型的泛化能力。
-
L1 和 L2 正则化:
- L1 正则化:对叶子节点的权重绝对值进行惩罚。
- L2 正则化:对叶子节点的权重平方进行惩罚。
-
其他参数控制:
- max_depth: 控制树的最大深度,防止模型过于复杂。
- min_split_gain: 设置分割点的最小增益,避免不必要的分裂。
-
优势:
- 平衡模型的复杂度和拟合能力,提高泛化性能。
7. 参数调优
LightGBM 提供了许多参数来控制模型的行为,选择合适的参数组合对模型性能至关重要。
-
关键参数:
- learning_rate: 学习率,控制每棵决策树的影响程度。
- n_estimators: 决策树的数量,增加数量可能会提高性能但也会增加计算时间。
- max_depth: 树的最大深度,防止过拟合。
-
调优方法:
- 使用网格搜索(Grid Search)或随机搜索(Random Search)进行参数组合的优化。
- 利用交叉验证评估不同参数组合的效果。
8. 特征工程
LightGBM 对特征数据有一定的要求,良好的特征工程可以提升模型性能。
- 独热编码: 对类别变量进行独热编码转换,以便模型处理。
- 数值标准化: 对数值型特征进行标准化或归一化处理。
- 缺失值处理: 填补缺失值或在模型中显式地引入缺失标记。
9. 缺失值与类别变量处理
LightGBM 能够有效地处理缺失值和类别变量,增强了其适用性。
-
缺失值处理:
- LightGBM 内部可以自动处理缺失值,默认将缺失值视为一个独立的类别。
-
类别变量处理:
- 对类别变量进行编码(如独热编码或标签编码),或者利用LightGBM内部的类别特征处理方法。
10. 与其他梯度提升框架的比较
-
XGBoost:
- 使用基于节点的分裂策略,计算速度相对较慢。
-
CatBoost:
- 特别适合处理类别变量,提供了内置的类别处理机制。
-
LightGBM 的优势:
- 训练速度快:基于直方图和Leaf-wise策略。
- 内存占用低:高效的分桶方法减少内存消耗。
- 支持分布式训练:适用于大规模数据集。
-
劣势:
- 参数调整较为复杂,需要仔细调优才能获得最佳性能。
-
适用场景:
- 需要快速训练模型且对计算资源有限的情况下。
- 处理大数据集时,特别是分布式的环境中。
LightGBM 是一个高效、强大的梯度提升框架,基于直方图和Leaf-wise策略,能够在保证高准确性的同时实现快速的训练。其分布式支持使其适用于处理大规模数据集。在实际应用中,合理调优参数和进行有效的特征工程能够进一步提升模型性能。理解其工作原理和优化机制,对于最大化利用LightGBM的优势、避免常见问题是非常重要的。
总结
本项目展示了如何利用 ML.NET 进行从数据准备到模型构建与评估的完整机器学习流程。通过将成人人口普查数据存储于数据库,并使用 LightGBM 分类器进行收入预测,该项目为实际应用中类似的数据分析任务提供了一个参考实现。在后续开发中,可以进一步优化特征工程步骤,尝试其他分类算法,并对模型性能进行更全面的评估。