ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

机器学习数据处理的基石:均值、中位数、众数的原理与Python实战

机器学习数据处理的基石:均值、中位数、众数的原理与Python实战 1. 从“算数”到“洞察”为什么机器学习绕不开这三个基础统计量刚接触机器学习的朋友可能会被各种炫酷的算法名词吸引——神经网络、随机森林、梯度提升……恨不得立刻上手调包跑模型。但干了这么多年我越来越觉得那些最基础、最不起眼的东西往往才是决定项目成败的关键。今天要聊的“平均、中位数、模式”就是最典型的例子。它们听起来像是小学数学课的内容但在Python机器学习的实战中从数据清洗、特征工程到模型评估几乎每一步都离不开它们。如果你只是把它们当作简单的“求和除以个数”、“中间那个数”和“出现最多的数”那可能错过了数据中隐藏的绝大部分信息。为什么这三个统计量如此重要因为数据从来都不是完美的。现实世界的数据集里充满了离群值、缺失值、偏态分布和测量误差。平均、中位数和模式就是我们从不同角度“打量”数据分布的三把尺子。平均均值告诉你数据的“重心”在哪但对极端值异常敏感中位数告诉你数据的“中心位置”能抵抗极端值的干扰模式则告诉你数据最“常见”的样子尤其在分类数据中至关重要。在Python的机器学习流程里pandas和numpy让计算它们变得轻而易举但难点从来不在计算本身而在于理解何时该用哪一个以及如何解读它们背后的故事。比如当你发现某个特征的平均值和标准差都很大但中位数却很小这很可能意味着数据中存在少数几个极大的异常值这时盲目使用均值进行标准化或填充缺失值就可能把整个模型带偏。2. 深入原理三把尺子如何刻画数据“肖像”在动手写代码之前我们必须先搞清楚这三个统计量到底在衡量什么以及它们各自的“脾气秉性”。这决定了我们在后续的机器学习流水线中该如何正确地使用它们。2.1 均值敏感的“平衡点”均值或者说算术平均是大家最熟悉的概念。它的计算方式是把所有数值加起来除以个数。在概率论中均值对应着数学期望是数据分布的中心趋势最直观的度量。但均值的核心特性是它对极端值离群值极其敏感。假设我们有一个代表居民收入的样本[3000, 3200, 3500, 3800, 4000, 4200, 100000]。前六个值在3000-4200之间波动但最后一个值高达10万。计算均值约为16414元这个数字远远偏离了大多数人的收入水平3000-4200元。这个10万的值就像一个巨大的砝码轻易地把平衡点拉向了自己一端。在机器学习中这种敏感性是一把双刃剑。利在于当数据分布近似对称且没有严重离群值时均值是描述中心位置最有效的统计量很多基于距离的算法如K-Means聚类、线性回归的损失函数天然地使用均值概念。弊在于一旦数据中存在离群值均值就会失真基于均值进行的后续计算如Z-score标准化都会产生偏差。注意除了算术平均在特定场景下还会用到几何平均适用于增长率类数据和调和平均适用于速率类数据。但在一般机器学习特征处理中除非特别说明提到“平均”默认指算术平均。2.2 中位数稳健的“中间人”中位数是另一个中心趋势的度量定义为将数据集按大小排序后位于正中间的那个数。如果数据量是偶数则取中间两个数的平均值。还是用上面的收入数据为例排序后为[3000, 3200, 3500, 3800, 4000, 4200, 100000]。中位数是3800元。看即使存在一个10万的极端值中位数依然稳稳地落在大多数数据所在的区间内。这种对离群值不敏感的特性称为“稳健性”。在机器学习中当我们面对的数据可能存在测量错误、录入错误或本身就是长尾分布如电商用户的消费金额、文章阅读量时使用中位数来描述数据的典型水平要比均值可靠得多。例如在数据探索阶段我通常会同时计算特征列的均值和中位数如果两者差异巨大就是一个强烈的信号提示我需要检查该特征是否存在离群值或者分布严重偏斜。2.3 众数揭示“共性”的标签众数是指数据集中出现频率最高的值。它主要用于分类数据名义数据或离散的数值数据。比如一个数据集中“城市”字段出现最多的是“上海”那么“上海”就是该字段的众数。在机器学习中众数的应用非常广泛处理分类特征对于缺失的分类特征一个最常用的填充策略就是用该特征的众数即最常见的类别来填充。理解数据分布对于某些数值特征如果其众数非常突出可能意味着数据采集过程存在默认值、常见值或某种系统性的偏好。例如一个“年龄”字段的众数是18岁可能意味着很多用户在注册时选择了默认选项。简单预测在一些最简单的基准模型中比如零规则分类器它的预测结果就是目标变量的众数。众数的一个特点是一个数据集可能有多个众数多峰分布也可能没有众数所有值出现次数相同。在Python中scipy.stats.mode()函数默认返回最小的众数使用时需要注意。统计量定义优点缺点机器学习中的典型应用场景均值所有数值之和除以数量充分利用所有数据信息数学性质优良对离群值极度敏感数据对称无离群时的中心估计Z-score标准化线性模型中位数排序后位于中间的值对离群值稳健抗干扰性强忽略了数据的具体数值只利用排序信息存在离群值或偏态分布时的中心估计Robust Scaling众数出现频率最高的值适用于分类数据直观可能不唯一对数值数据有时意义不大分类特征缺失值填充理解数据分布形态建立基准模型3. Python实战用pandas和numpy高效计算与探索理论清楚了我们来看看在Python里怎么玩转这三个量。pandas的DataFrame和Series以及numpy提供了极其便捷的接口。3.1 基础计算一行代码的事假设我们有一个简单的DataFramedf包含‘age’和‘salary’两列。import pandas as pd import numpy as np # 创建一个示例DataFrame其中salary列故意加入一个离群值 data { age: [25, 30, 35, 40, 45, 50, 55, 22, 28, 60], salary: [50000, 55000, 60000, 65000, 70000, 75000, 80000, 48000, 52000, 200000] # 注意最后一个值 } df pd.DataFrame(data) # 计算均值 mean_age df[age].mean() mean_salary df[salary].mean() print(f平均年龄: {mean_age:.2f}) print(f平均薪资: {mean_salary:.2f}) # 会被200000拉高 # 计算中位数 median_age df[age].median() median_salary df[salary].median() print(f\n年龄中位数: {median_age}) print(f薪资中位数: {median_salary}) # 不受200000影响 # 计算众数 # pandas的mode()返回一个Series因为可能有多众数 mode_age df[age].mode() print(f\n年龄众数: {mode_age.values}) # 如果没有重复值则返回所有值不pandas的mode()在无重复时会返回整个序列但通常意义不大。 # 对于分类数据更常用 df[city] [北京,上海,上海,广州,北京,上海,深圳,北京,上海,广州] mode_city df[city].mode() print(f城市众数: {mode_city.values[0]}) # 输出上海对于数值型数据直接调用.mean()和.median()即可。.mode()需要注意它返回的是一个Series即使只有一个众数因为理论上可能存在多个。3.2 进阶探索describe()与分布可视化在实际项目中我们很少单独看这三个值而是结合其他描述性统计量一起看。pandas的.describe()函数是我们的第一道利器。print(df[[age, salary]].describe())输出会包含计数、均值、标准差、最小值、25%分位数Q1、中位数50%分位数、75%分位数Q3和最大值。一眼就能对比出均值和中位数的差异。如果salary的mean远大于50%如上例离群值警报就响了。可视化能提供更直观的感受。结合matplotlib或seabornimport matplotlib.pyplot as plt import seaborn as sns fig, axes plt.subplots(1, 2, figsize(12, 4)) # 绘制薪资的直方图与核密度估计并标记均值和中位数 sns.histplot(df[salary], kdeTrue, axaxes[0]) axes[0].axvline(mean_salary, colorr, linestyle--, labelfMean: {mean_salary:.0f}) axes[0].axvline(median_salary, colorg, linestyle-, labelfMedian: {median_salary}) axes[0].set_title(Salary Distribution with Mean Median) axes[0].legend() # 绘制箱线图可以清晰看到离群值 sns.boxplot(xdf[salary], axaxes[1]) axes[1].set_title(Salary Boxplot (Outlier Visible)) plt.tight_layout() plt.show()箱线图会明确标出那个200000的薪资点是一个“圆圈”离群值。直方图上红色的均值线明显偏右而绿色的中位数线则位于主体数据内部。这个对比图是给业务方或项目伙伴解释数据问题时的绝佳材料。3.3 处理偏态与离群值基于统计量的策略当我们通过均值和中心数的差异确认了数据偏态或存在离群值时常用的处理策略包括用中位数填充缺失值对于偏态分布的数值特征用中位数填充比用均值更稳健。# 假设df[salary]有缺失值 median_salary df[salary].median() df[salary_filled] df[salary].fillna(median_salary)中位数绝对偏差MAD标准化这是一种稳健的标准化方法使用中位数和MAD代替均值标准差。from scipy.stats import median_abs_deviation median df[salary].median() mad median_abs_deviation(df[salary], scalenormal) # scalenormal使其与标准差对正态数据估计一致 df[salary_robust_scaled] (df[salary] - median) / mad缩尾处理将超出特定分位数如1%和99%的值用该分位数的值替代而不是直接删除。lower_bound df[salary].quantile(0.01) upper_bound df[salary].quantile(0.99) df[salary_winsorized] df[salary].clip(lowerlower_bound, upperupper_bound) # 此时再计算均值会更接近中位数4. 在机器学习全流程中的应用场景拆解这三个基础统计量贯穿了机器学习项目的始终。下面我们按照一个典型的流程走一遍。4.1 数据理解与探索性数据分析这是它们大显身手的第一个阶段。拿到数据后我习惯性会做以下几件事整体概览对每个数值特征调用df.describe()重点关注mean和50%的差异。对于分类特征用df[‘column’].value_counts()查看频率分布其最大值对应的类别就是众数。发现数据问题偏态分布均值 中位数表示右偏正偏尾部在右侧均值 中位数表示左偏负偏。这会影响许多假设数据正态分布的模型如线性回归、逻辑回归。潜在离群值如前所述均值与中位数严重偏离是红灯信号。默认值/常见值如果某个数值特征的众数占比极高比如“年龄0”或“收入999999”很可能代表缺失值或无效值被编码成了某个特定数字。制定清洗策略基于上述发现决定是进行对数变换处理右偏、缩尾、分箱还是直接使用基于中位数的填充和缩放方法。4.2 特征工程创造与转换在构造新特征或转换现有特征时统计量是核心工具。聚合特征在基于时间序列或分组的数据中常需要聚合。例如计算用户历史购买金额的均值、中位数、众数最常购买的品类作为新特征。中位数能避免偶尔的大额消费扭曲用户的“典型”消费水平。# 假设df是订单数据有user_id和amount user_stats df.groupby(user_id)[amount].agg([mean, median, count]).reset_index() user_stats.columns [user_id, avg_amount, median_amount, order_count]处理缺失值这是众数和中位数最直接的应用。分类列用众数填充偏态的数值列用中位数填充对称且无离群值的数值列可以考虑用均值填充。数据标准化/归一化Z-score标准化(x - mean) / std。前提是数据近似正态分布。对离群值敏感。Robust Scaling(x - median) / IQRIQR是四分位距。使用中位数和IQR对离群值不敏感更稳健。分箱有时会将连续变量按统计量分箱。例如按均值±标准差将数据分为“低”、“中”、“高”三档。4.3 模型训练与评估隐形的基石统计量的思想渗透在许多算法内部。损失函数回归任务中最常用的均方误差其最优解就是目标值的条件均值。平均绝对误差其最优解是条件中位数。集成算法随机森林回归模型对于一棵树叶子节点内样本的预测值通常取的是样本目标值的均值。而一些增强鲁棒性的变体可能会使用中位数。评估指标除了MSE、MAE在分类问题中我们常看的是模型预测的众数类别即预测的类别是否与真实类别一致。基线模型在开始复杂建模前建立一个简单的基线模型至关重要。对于回归问题一个朴素的基线模型就是始终预测目标变量的均值或中位数。对于分类问题基线模型就是始终预测众数类别。如果你的复杂模型不能显著超越这个基线那它的价值就存疑。4.4 结果分析与解释模型上线后分析预测结果时同样需要它们。分析预测误差计算预测误差真实值-预测值的均值。如果均值显著不为0说明模型存在系统性偏差整体高估或低估。计算误差的中位数可以了解典型误差的大小且不受极端预测误差的影响。理解预测分布观察模型对测试集预测值的分布计算其均值、中位数并与真实目标值的分布进行对比。这有助于发现模型是否存在分布偏移或特定区间的预测能力不足。模型监控在生产环境中持续监控模型预测结果的均值、中位数是否发生漂移。如果发现明显变化可能意味着数据分布发生了变化需要触发模型重训练。5. 避坑指南实战中容易忽略的细节与误区掌握了基本用法下面分享几个我踩过坑才明白的细节。5.1 误区一盲目使用均值进行标准化这是新手最常见的错误之一。看到教程里说“特征标准化”就直接上StandardScaler基于均值标准差。如果特征存在严重的离群值标准化后的数据不仅不会更好反而可能更糟因为离群值的存在会夸大标准差导致大多数“正常”数据被压缩在一个很小的范围内。正确做法先做探索性数据分析绘制箱线图或直方图。对于明显偏态或有离群值的特征优先考虑先进行数据变换如对数变换np.log1p使其更对称。或者直接使用RobustScaler进行标准化。或者先处理离群值如缩尾再进行Z-score标准化。5.2 误区二忽略众数在数值特征中的意义很多人认为众数只对分类特征有用。其实不然。例如在一个“用户登录次数”的特征里如果众数是1且占比超过50%这说明超过一半的用户只登录了一次这对于理解用户活跃度至关重要。再比如在问卷调查的评分数据1-5分中众数能直观反映最集中的评价倾向。忽略它可能会错过数据中最普遍的“声音”。5.3 细节一分组聚合时缺失值的处理使用groupby后接.agg(‘mean’)时pandas默认会跳过该组内的NaN值计算均值。这通常是我们想要的。但你需要明确知道这一点因为如果某组数据全部为NaN那么聚合结果就是NaN。有时你可能希望用0或全局均值来填充这些全NaN组的聚合结果这就需要额外的处理。# 默认行为跳过NaN df.groupby(group)[value].mean() # 如果需要用0填充全NaN组的结果 df.groupby(group)[value].mean().fillna(0) # 如果需要用全局均值填充 global_mean df[value].mean() df.groupby(group)[value].mean().fillna(global_mean)5.4 细节二scipy.stats.mode与pandas.Series.mode的差异两者都能计算众数但行为有细微差别容易混淆。scipy.stats.mode(a)返回众数值和出现次数。默认情况下当存在多个众数时它返回最先遇到的那个众数取决于数组顺序。它还有一个keepdims参数需要注意。pandas.Series.mode()返回一个Series包含所有的众数如果有多众数。这是一个更安全、信息更完整的选择尤其是在自动化脚本中。from scipy import stats arr np.array([1, 2, 2, 3, 3, 4]) print(stats.mode(arr)) # ModeResult(mode2, count2) 只返回了2 print(pd.Series(arr).mode().values) # [2 3] 返回了2和3在自动化特征工程中如果使用众数填充缺失值使用pandas的.mode()并取第一个值df[‘col’].mode()[0]通常是更通用的做法因为它明确处理了多众数的情况。5.5 性能考量大数据集下的计算当数据集非常大时即使是一个简单的求均值操作如果写法不当也可能成为瓶颈。pandas的向量化操作已经很快但仍有优化空间。对于单列操作df[‘col’].mean()和df[‘col’].median()是高效的。避免在循环中逐行计算统计量。如果需要进行复杂的滑动窗口统计如滑动平均、滑动中位数优先使用pandas的.rolling()方法它底层是优化过的。# 计算时间序列的7天滑动平均和滑动中位数 df[value_rolling_mean] df[value].rolling(window7).mean() df[value_rolling_median] df[value].rolling(window7).median()对于超大规模数据可以考虑使用Dask或Spark等分布式计算框架它们也提供了类似的统计量计算接口。6. 超越基础滑动平均、指数平均与更广阔的视野当我们谈论“平均”时在时间序列和深度学习等领域还有两个非常重要的变体滑动平均和指数移动平均。它们不再是描述静态数据集的中心而是用于平滑序列、观察趋势。6.1 滑动平均滤波从噪声中提取信号滑动平均也叫移动平均是时间序列分析中最常用的平滑技术之一。它的思想是计算一个固定窗口内数据的平均值并让这个窗口在时间轴上滑动。这在处理带有噪声的传感器数据、金融价格序列时非常有用可以过滤短期波动观察长期趋势。# 使用pandas计算简单滑动平均 window_size 5 df[sma] df[value].rolling(windowwindow_size, centerTrue).mean() # centerTrue使窗口居中 # 计算滑动中位数更稳健 df[sma_median] df[value].rolling(windowwindow_size, centerTrue).median()为什么用中位数在滤波场景下如果窗口内混入了极端的脉冲噪声算术平均会被严重干扰而中位数滤波则能很好地抑制这种脉冲噪声保留信号的边缘特征。这在图像处理中值滤波去椒盐噪声和实时信号处理中应用广泛。6.2 指数移动平均给予近期数据更高权重指数移动平均是另一种平滑方法它通过一个衰减因子让近期数据拥有更高的权重远期的权重呈指数衰减。这在金融分析如MACD指标和深度学习模型训练如优化器中的动量项、模型权重的EMA影子参数中极为常见。pandas提供了便捷的ewm方法# 计算指数移动平均span可以理解为近似的窗口期 span 5 df[ema] df[value].ewm(spanspan, adjustFalse).mean()在深度学习训练中例如使用TensorFlow或PyTorch我们常会维护模型权重的一个EMA版本这个版本在验证集上往往表现更稳定因为平滑了训练过程中的权重震荡。6.3 联邦学习中的联邦平均算法这是一个将“平均”思想应用到分布式机器学习范式中的高级例子。在联邦学习中数据分布在大量客户端设备上且不能集中。联邦平均算法的核心步骤是服务器将全局模型下发到客户端。各客户端用本地数据训练模型得到模型更新权重差值。客户端将更新上传至服务器。服务器对所有客户端的模型更新进行加权平均得到新的全局模型。这里的“平均”操作是联邦学习能够协同工作、保护隐私的基石。它要求我们深入思考平均的权重如何设置按数据量加权、如何防御恶意客户端上传的恶意更新使用中位数等稳健聚合规则这又将我们带回了对均值和中位数本质特性的思考。从这三个最基础的统计量出发我们一路走到了机器学习的核心流程、时间序列分析和前沿的分布式学习范式。它们就像三原色看似简单却能组合出理解数据世界的丰富色彩。下次当你调用df.mean()时不妨多想一想这个均值真的能代表我的数据吗我是不是该看看中位数众数又告诉了我什么故事养成这个习惯你在数据科学道路上的洞察力会远超那些只盯着复杂模型的同行。
返回列表