好的,让我们动手操作吧!理论很有帮助,但将这些数据准备技术付诸实践能让它们记忆更深。在本节中,我们将通过一个实际例子来处理一个小型、混乱的数据集,使其为机器学习算法做好准备。“假设我们有一个包含二手车信息的数据集,我们希望预测它们的价格。数据通常看起来不那么完美,就像这个样本一样:”原始汽车数据集里程 (公里)车龄 (年)发动机类型车况价格 ($)500003PetrolGood150001200008DieselFair8000800005PetrolGood11000NaN10DieselExcellent9500650004NaNGood1300015000012PetrolFairNaN950006HybridExcellent18000我们可以立即看出算法会不喜欢的一些问题:缺失值: 在“里程”、“发动机类型”和“价格”列中存在 NaN(非数字)条目。混合数据类型: 我们有数值数据(“里程”、“车龄”、“价格”)和类别数据(“发动机类型”、“车况”)。算法通常要求所有输入特征都是数值型的。不同量纲: “里程”的值是数万或数十万,而“车龄”是个位数或两位数。这种量纲差异有时会给某些算法带来问题。让我们一步步处理这些问题。步骤 1:处理缺失值首先,我们需要处理 NaN 条目。如前所述,常见策略包括删除行/列或填充(补齐缺失值)。由于我们的数据集较小,删除行可能会丢弃过多信息。我们来尝试填充。数值特征(“里程”、“价格”): 我们可以使用列的均值或中位数来填充缺失的数值。如果数据可能存在异常值(极端值)而导致均值出现偏差,通常更倾向于使用中位数。让我们根据非缺失值计算“里程”和“价格”的中位数:现有里程:50000, 120000, 80000, 65000, 150000, 95000。排序后:50000, 65000, 80000, 95000, 120000, 150000。中位数(中间两个数的平均值)= (80000 + 95000) / 2 = 87500。现有价格:15000, 8000, 11000, 9500, 13000, 18000。排序后:8000, 9500, 11000, 13000, 15000, 18000。中位数 = (11000 + 13000) / 2 = 12000。我们将用 87500 填充缺失的“里程”,用 12000 填充缺失的“价格”。类别特征(“发动机类型”): 对于类别数据,我们可以用众数(最常出现的值)填充缺失值。现有发动机类型:Petrol, Diesel, Petrol, Diesel, Petrol, Hybrid。计数:Petrol (3), Diesel (2), Hybrid (1)。众数是“Petrol”。我们将用“Petrol”填充缺失的“发动机类型”。处理缺失值后的数据集如下:填充后数据集里程 (公里)车龄 (年)发动机类型车况价格 ($)500003PetrolGood150001200008DieselFair8000800005PetrolGood110008750010DieselExcellent9500650004PetrolGood1300015000012PetrolFair12000950006HybridExcellent18000注意:“价格”列通常是我们的目标变量(我们希望预测的值)。根据情况,如果目标值缺失,我们可能会选择完全删除该行,因为填充目标值可能会扭曲模型的学习。在此示例中,我们对其进行了填充以演示该技术,但请记住这个考虑因素。步骤 2:编码类别特征机器学习算法处理数字。我们需要将类别特征(“发动机类型”、“车况”)转换为数值格式。一种常用方法是独热编码。发动机类型: 这包括“Petrol”、“Diesel”、“Hybrid”等类别。独热编码为每个类别创建一个新的二进制(0或1)列。车况: 这包括“Good”、“Fair”、“Excellent”等类别。同样,我们为每个类别创建一个新的二进制列。请注意,“车况”可能具有固有的顺序(例如,Fair < Good < Excellent)。独热编码会忽略此顺序,但如果模型认为此顺序重要,其他编码方法(如序数编码)可以保留它。为简单起见,这里我们使用独热编码。应用独热编码后,数据集结构发生变化:独热编码后数据集里程 (公里)车龄 (年)发动机_汽油发动机_柴油发动机_混合动力车况_良好车况_一般车况_优秀价格 ($)5000031001001500012000080100108000800005100100110008750010010001950065000410010013000150000121000101200095000600100118000现在,我们的所有特征列都是数值型的了。步骤 3:特征缩放请看“里程”和“车龄”列。“里程”范围从 50,000 到 150,000,而“车龄”范围从 3 到 12。某些算法对这种量纲上的巨大差异很敏感。让我们对数值特征(“里程”、“车龄”)应用缩放。我们将使用归一化(最小-最大缩放),它使用以下公式将数据缩放到 0 到 1 的范围: $$ x' = \frac{x - \text{最小值}(x)}{\text{最大值}(x) - \text{最小值}(x)} $$让我们将此应用于“里程”和“车龄”:里程: 最小值=50000,最大值=150000。范围 = 100000。50000 -> (50000 - 50000) / 100000 = 0.0120000 -> (120000 - 50000) / 100000 = 0.780000 -> (80000 - 50000) / 100000 = 0.387500 -> (87500 - 50000) / 100000 = 0.37565000 -> (65000 - 50000) / 100000 = 0.15150000 -> (150000 - 50000) / 100000 = 1.095000 -> (95000 - 50000) / 100000 = 0.45车龄: 最小值=3,最大值=12。范围 = 9。3 -> (3 - 3) / 9 = 0.08 -> (8 - 3) / 9 ≈ 0.565 -> (5 - 3) / 9 ≈ 0.2210 -> (10 - 3) / 9 ≈ 0.784 -> (4 - 3) / 9 ≈ 0.1112 -> (12 - 3) / 9 = 1.06 -> (6 - 3) / 9 ≈ 0.33“价格”列是我们的目标变量。是否缩放目标变量取决于具体的模型和情境。通常情况下,它不进行缩放。我们在此将其保留为未缩放状态。独热编码的特征已经是二进制(0或1),因此通常不需要缩放。我们最终的、预处理过的特征集(不包括目标“价格”)如下:缩放后数据集(仅特征)里程 (归一化后)车龄 (归一化后)发动机_汽油发动机_柴油发动机_混合动力车况_良好车况_一般车况_优秀0.00.01001000.70.560100100.30.221001000.3750.780100010.150.111001001.01.01000100.450.33001001让我们可视化“里程”和“车龄”缩放后的效果。{"data":[{"x":[50000,120000,80000,87500,65000,150000,95000],"y":[3,8,5,10,4,12,6],"mode":"markers","type":"scatter","name":"原始数据","marker":{"color":"#4263eb"}},{"x":[0.0,0.7,0.3,0.375,0.15,1.0,0.45],"y":[0.0,0.5555555555555556,0.2222222222222222,0.7777777777777778,0.1111111111111111,1.0,0.3333333333333333],"mode":"markers","type":"scatter","name":"归一化后","marker":{"color":"#f76707"},"xaxis":"x2","yaxis":"y2"}],"layout":{"grid":{"rows":1,"columns":2,"pattern":"independent"},"xaxis":{"title":"里程 (公里)","domain":[0,0.45]},"yaxis":{"title":"车龄 (年)"},"xaxis2":{"title":"里程 (归一化后)","domain":[0.55,1.0]},"yaxis2":{"title":"车龄 (归一化后)"},"title":"归一化(最小-最大缩放)的效果","showlegend":true,"legend":{"x":0.5,"y":-0.15,"orientation":"h","xanchor":"center"}, "height": 450, "width": 700}}“里程”与“车龄”在归一化前(左侧,蓝色)和归一化后(右侧,橙色)的比较。请注意,缩放后的特征现在在两个坐标轴上都处于 0 到 1 之间。步骤 4:数据分割(下一步)回顾前一节和第 2 章,训练之前的最后一步通常是将数据分割成训练集和测试集。我们会取我们完全清洗和准备好的数据(上面的特征表和对应的“价格”列)进行分割,通常保留大约 70-80% 用于模型训练,20-30% 用于在未见过的数据上测试其表现。我们在此不执行分割,但这是在将数据输入到线性回归或 KNN 等算法之前的紧接下一步操作。总结在本次动手实践中,我们处理了一个带有常见问题的原始数据集,并应用了基本清洗步骤:处理缺失值: 对数值特征使用中位数填充,对类别特征使用众数填充。编码类别数据: 使用独热编码将“发动机类型”和“车况”转换为数值表示。缩放数值特征: 对“里程”和“车龄”应用归一化(最小-最大缩放),使其进入共同范围(0到1)。这些处理过的数据现在对于大多数机器学习算法来说,处于更好的格式。尽管这些是基本技术,但它们是数据准备工作的重要部分,也是任何机器学习项目的重要组成部分。