当前位置: 首页 > 科技观察

使用Python进行数据清理的完整指南

时间:2023-03-16 18:21:17 科技观察

你一定听过这句著名的数据科学名言:在数据科学项目中,80%的时间都花在了数据处理上。如果您还没有听说过,请记住:数据清理是数据科学工作流程的基础。机器学习模型会根据你提供的数据执行,杂乱的数据会导致性能不佳甚至错误的结果,而干净的数据是良好模型性能的前提。当然,干净的数据并不代表一直都有好的表现,模型的正确选择(剩下的20%)也很重要,但是没有干净的数据,再强大的模型也达不到预期的水平。在本文中,我们将列出数据清洗中需要解决的问题,并展示可能的解决方案。通过本文,您可以逐步了解如何进行数据清洗。缺失值当数据集包含缺失数据时,可以在填充前做一些数据分析。因为空单元格的位置本身就可以告诉我们一些有用的信息。例如:NA值只出现在数据集的尾部或中间。这意味着在数据收集过程中可能出现了技术问题。可能有必要分析特定样本序列的数据收集过程,并尝试确定问题的根源。如果列中NA的数量超过70-80%,则可以删除该列。如果NA值作为可选问题出现在表单的一列中,则该列可以额外编码为用户回答(1)或未回答(0)。可以使用python库missingno来查看以上情况,使用起来非常简单。比如下图中的白线是NA:importmissingnoasmsnomsno.matrix(df)缺失值的填充和计算方法有很多,比如:mean,median,modekNNzeroorconstant等不同的方法各有优势和劣势,并没有适用于所有情况的“最佳”技术。详情请参考我们之前发表的文章异常值异常值是相对于数据集中其他点非常大或非常小的值。它们的存在极大地影响了数学模型的性能。让我们看一下这个简单的例子:在左边的图中没有异常值,我们的线性模型非常适合数据点。在右边的图中有一个离群值,当模型试图覆盖数据集的所有点时,这个离群值的存在会改变模型的拟合方式,并使我们的模型至少不能拟合一半的点。对于离群值,我们有必要介绍下如何判断异常值,也就是从数学的角度明确什么是极大或者极小。任何大于Q3+1.5xIQR或小于Q1-1.5xIQR的值都可以视为异常值。IQR(InterquartileRange)是Q3和Q1之间的差值(IQR=Q3-Q1)。以下函数可用于检查数据集中异常值的数量:defnumber_of_outliers(df):df=df.select_dtypes(exclude='object')Q1=df.quantile(0.25)Q3=df.quantile(0.75)IQR=Q3-Q1return((df<(Q1-1.5*IQR))|(df>(Q3+1.5*IQR))).sum()处理异常值的一种方法是使它们等于Q3或Q1。下面的lower_upper_range函数使用pandas和numpy库找出范围之外的是离群值,然后使用clip函数将值裁剪到指定范围内。deflower_upper_range(datacolumn):sorted(datacolumn)Q1,Q3=np.percentile(datacolumn,[25,75])IQR=Q3-Q1lower_range=Q1-(1.5*IQR)upper_range=Q3+(1.5*IQR)回报lower_range,upper_rangeforcolincolumns:lowerbound,upperbound=lower_upper_range(df[col])df[col]=np.clip(df[col],a_min=lowerbound,a_max=upperbound)数据不一致异常值问题是关于数字特征,现在让我们看看字符类型(分类)特征。不一致的数据意味着列的唯一类具有不同的表示形式。例如,在性别栏中,既有男/女,也有男/女。在这种情况下,会有4个类,但实际上有两个类。这个问题目前没有自动解决方案,需要人工分析。pandas的独特功能就是为这个分析准备的。让我们看一个汽车品牌的例子:df['CarName']=df['CarName'].str.split().str[0]print(df['CarName'].unique())maxda-mazda、Nissan-nissan、porcshce-porsche、toyouta-toyota等都可以合并。df.loc[df['CarName']=='maxda','CarName']='mazda'df.loc[df['CarName']=='Nissan','CarName']='nissan'df.loc[df['CarName']=='porcshce','CarName']='porsche'df.loc[df['CarName']=='toyouta','CarName']='toyota'df.loc[df['CarName']=='vokswagen','CarName']='volkswagen'df.loc[df['CarName']=='vw','CarName']='volkswagen'invaliddatainvaliddatarepresentationA逻辑上根本不正确的值。比如某人的年龄是560;手术耗时-8小时;一个人的身高是1200厘米等;对于数值列,可以使用pandas的describe函数来识别此类错误:df.describe()ofinvaliddata可能有两种原因:1.数据采集错误:比如输入的时候没有判断范围,1799cm是输入身高的时候错误输入了179cm,但是程序没有判断数据的范围。2.数据操作错误数据集的某些列可能被某些函数处理了。例如,一个函数根据生日计算年龄,但是这个函数中的一个错误导致输出不正确。上述两种随机误差都可以视为空值并与其他NA一起估算。重复数据当数据集中存在相同的行时,就会出现重复数据问题。这可能是由于不正确的数据组合(来自多个来源的同一行)或重复操作(用户可能两次提交他或她的答案)等。处理此问题的理想方法是删除重复的行。可以使用pandasduplicated函数查看重复数据:df.loc[df.duplicated()]识别出重复数据后,可以使用pandasdrop_duplicate函数删除:df.drop_duplicates()数据泄露问题建立模型前,数据集分为训练集和测试集。测试集是用于评估模型性能的看不见的数据。如果模型在数据清理或数据预处理步骤中以某种方式“看到”了测试集,这称为数据泄漏。所以在清洗和预处理步骤之前应该对数据进行拆分:以缺失值插补为例。数值列中的NA,使用均值法估计。在拆分之前完成时,使用整个数据集的平均值,但如果在拆分之后完成,则使用单独的训练和测试方法。第一种情况的问题是测试集中的估算值将与训练集相关,因为平均值是针对整个数据集的。因此,当使用训练集构建模型时,它也“看到”了测试集。但是我们拆分的目的是让测试集完全独立出来,把它当作新数据来进行性能评估。所以在操作之前必须对数据集进行拆分。虽然单独处理训练集和测试集效率不高(因为需要执行两次相同的操作),但它可能是正确的。因为数据泄露问题很重要,为了解决代码重复问题,可以使用sklearn库的pipeline。简单的说,流水线就是将所有发送数据作为输入的操作步骤组合起来,这样只要我们设置好操作,无论是训练集还是测试集,我们都可以使用相同的步骤来处理,减少代码开发的同时也可以减少出错的概率。