当前位置: 首页 > 后端技术 > Python

使用Python进行数据清洗,这7个方法你必须掌握

时间:2023-03-26 00:15:01 Python

作者|ChangGuozhen,ZhaoRenqian,ZhangQiujian资料来源|不符合分析要求的数据,如重复、错误、缺失、异常数据。01重复值处理数据录入过程和数据整合过程中可能会产生重复数据,直接删除是重复数据处理的主要方式。Pandas提供了duplicated和drop_duplicates方法来查看和处理重复数据。以下数据为例:>sample=pd.DataFrame({'id':[1,1,1,3,4,5],'name':['Bob','Bob','Mark','Miki','Sully','Rose'],'score':[99,99,87,77,77,np.nan],'group':[1,1,1,2,1,2],})>samplegroupidnamescore011Bob99.0111Bob99.0211Mark87.0323Miki77.0414Sully77.0525RoseNaN通过duplicated方法找到重复数据,如下图,可以用这个查看重复数据的方法。>sample[sample.duplicated()]groupidnamescore111Bob99.0要删除重复项,请使用drop_duplicates方法:>sample.drop_duplicates()groupidnamescore011Bob99.0211Mark87.0323Miki77.0414Sully77.0525RoseNaNdrop_duplicates方法也可以根据某列去除重复,例如去除id列的所有重复记录:>sample.drop_duplicates('id')groupidnamescore011Bob99.0323miki77.0414Sully77.0525RoseNaN02缺失值处理缺失值是数据清洗中比较常见的问题。缺失值一般用NA表示,处理缺失值时必须遵循一定的原则。首先,你需要根据业务理解来处理缺失值,找出缺失值的原因是故意的还是随机的,然后用一些业务经验来填充。一般来说,当缺失值小于20%时,连续变量可以用均值或中位数填充;分类变量不用填,单独统计一个类别即可,也可以用众数填充分类变量。当缺失值在20%~80%之间时,填充方法同上。另外,每个有缺失值的变量都可以生成一个指标虚拟变量参与后续建模。当缺失值大于80%时,每个有缺失值的变量生成一个指标虚拟变量,参与后续建模,不使用原始变量。缺失值和缺失值指示变量的中位数插补的生成过程如下图所示。▲图5-8:缺失值填充示例Pandas提供了fillna方法来替换缺失值数据。它的功能类似于前面的replace方法。例如,对于下面的数据:>samplegroupidnamescore01.01.0Bob99.011.01.0BobNaN2NaN1.0Mark87.032.03.0Miki77.041.04.0Sully77.05NaNNaNNaNNaN如下一步步检查和填充缺失值:1.检查丢失情况。在数据分析之前,您通常需要了解缺失数据。在Python中,您可以构造一个lambda函数来查看缺失值。在这个lambda函数中,sum(col.isnull())表示当前列有多少个缺失值,col.size表示当前列总共有多少行数据:>sample.apply(lambdacol:sum(col.isnull())/col.size)group0.333333id0.166667name0.166667score0.333333dtype:float642。用指定值填充pandas数据框提供fillna方法完成缺失值的填充,比如为样本表的列score值填充缺失值,填充方法为mean:>sample.score.fillna(sample.score.mean())099.0185.0287.0377.0477.0585.0Name:score,dtype:float64当然也可以填充分位数等方法:>sample.score.fillna(sample.score.median())099.0182.0287.0377.0477.0582.0名称:分数,数据类型:float643。缺失值指示变量pandas数据框对象可以直接调用isnull方法生成缺失值指示变量,比如score变量的缺失值指示变量:>sample.score.isnull()0False1True2False3False4False5TrueName:score,dtype:bool如果要转换成值0,类型1的指示变量,可以使用apply方法,int表示将列替换成int类型>sample.score.isnull().apply(int)001120304051Name:score,dtype:int6403噪声值处理噪声值是指数据中的一个或几个值与其他值相差较大,也称为离群值、离群值(outlier)。对于大多数模型,噪声值会严重干扰模型的结果,使结论不真实或有偏差,如图5-9所示。数据预处理时需要去除所有噪声值。处理噪声值的方法有很多种。对于单变量,常用的方法有capping法和binning法;对于多变量处理,使用聚类方法。下面是详细介绍:▲图5-9:噪声值示例(离群值,离群值):年龄数据,圆圈为噪声值1.Capping方法capping方法记录3次范围外的记录将连续变量的均值的标准差替换为均值上下三个标准差的值,即封顶处理(图5-10)。▲图5-10:capping方法处理噪声值的例子capping方法可以通过Python中的用户自定义函数来完成。如下图,参数x表示一个pd.Series列,quantile指的是block的范围区间。默认情况下,所有小于1个百分位和大于99个百分位的值都会被第1个百分位数和第99个百分位替换:>defcap(x,quantile=[0.01,0.99]):"""cappingmethodtohandleoutliersargs:x:pd.Seriescolumn,continuousvariablequantile:specifycappingmethod上下分位数范围"""#生成分位数Q01,Q99=x.quantile(quantile).values.tolist()#替换异常具有指定分位数的值ifQ01>x.min():x=x.copy()x.loc[xQ99]=Q99return(x)现在生成一组服从正态分布的随机数,sample.hist表示生成直方图,更多的绘制方法在下一章讲解:>sample=pd.DataFrame({'normal':np.random.randn(1000)})>sample.hist(bins=50)▲图5-11:未处理噪声时的变量直方图pandas数据框的所有列均采用capping方式转换,即可以写成如下,极值从直方图比较可以看出封顶后频率的变化。>new=sample.apply(cap,quantile=[0.01,0.99])>new.hist(bins=50)▲图5-12:噪声处理后的变量直方图2.Binning方法Binning方法通过检验“最近邻”的数据来平滑有序数据的值。有序的值被分配到一些桶或容器中。分箱方法包括等深分箱:每个分箱内的样本大小相同;等宽分箱:每个分箱中的取值范围相同。直方图其实就是先把数据分成等宽的bin,然后计算频数,绘制图形。例如价格排序后的数据为:4、8、15、21、21、24、25、28、34,分为(等深)框:框1:4、8、15框2:21,21,24bin3:25,28,34将其分成(等宽)bins:bin1:4,8bin2:15,21,21,24bin3:25,28,34binning以包含异常数据在盒子里,建模的时候并没有直接输入到模型中,所以可以达到处理异常值的目的。pandas的qcut函数提供了分箱的实现方法。下面介绍如何实现它。等宽分箱:qcut函数可以直接进行等宽分箱。这时候需要两个参数:待分箱的列和分箱数。如下图,样本数据的int列遵循标准正态从10分布的随机数:>sample=pd.DataFrame({'normal':np.random.randn(10)})>samplenormal00.0651081-0.59703120.6354323-0.4919304-1.89400751.62368461.7237117-0.2259498-0.2136859-0.309789分数为5箱,可以看出结果按照宽度分成了5份。在下限中,cut函数自动选取一个小于该列最小值的值作为下限,最大值为上限,分成五等份。结果产生一列类Categories,类似于R中的因子,表示一列分类变量。另外weak数据缺失,缺失值在binning后会继续缺失,如下图:>pd.cut(sample.normal,5)0(-0.447,0.277]1(-1.17,-0.447]2(0.277,1.0]3(-1.17,-0.447]4(-1.898,-1.17]5(1.0,1.724]6(1.0,1.724]7(-0.447,0.277]8(-0.447,0.277]9(-0.447,0.277]名称:正常,dtype:类别类别(5,间隔[float64]):[(-1.898,-1.17]<(-1.17,-0.447]<(-0.447,0.277]<(0.277,1.0]<(1.0,1.724]]这里也可以使用labels参数指定分箱后各level的标签,如下图,此时对应的区间值被标签值代替:>pd.cut(sample.normal,bins=5,labels=[1,2,3,4,5])01112232435364748595Name:normal,dtype:categoryCategories(5,int64):[1<2<3<4<5]标签可以设置except可以设置为一个值,也可以设置为一个字符,如下图,将数据分成两个等宽的bin,标签分别为'bad'和'好':>pd.cut(样品.normal,bins=2,labels=['bad','good'])0bad1bad2bad3bad4bad5good6good7good8good9goodName:normal,dtype:categoryCategories(2,object):[badsample.normal.quantile([0,0.5,1])0.00.00.54.51.09.0Name:normal,dtype:float64inthebinsparameter设置分位数间隔,完成分箱如下图。include_lowest=True参数表示边界的最小值包括包含数据的最小值:>pd.cut(sample.normal,bins=sample.normal.quantile([0,0.5,1]),include_lowest=真)0[0,4.5]1[0,4.5]2[0,4.5]3[0,4.5]4[0,4.5]5(4.5,9]6(4.5,9]7(4.5,9]8(4.5,9]9(4.5,9]Name:normal,dtype:categoryCategories(2,object):[[0,4.5]<(4.5,9)]另外还可以加一个label参数指定标签如下:>pd.cut(sample.normal,bins=sample.normal.quantile([0,0.5,1]),include_lowest=True)0bad1bad2bad3bad4bad5good6good7good8good9goodName:normal,dtype:categoryCategories(2,object):[bad