第3章 11条数据化运营不得不知道的数据预处理经验

数据预处理是数据化运营过程中的重要环节,它直接决定了后期所有数据工作的质量和价值输出。从数据预处理的主要内容看,包括数据清洗、转换、归约、聚合、抽样等。本章将摒弃理论和方法说教,直接介绍内容本身可能遇到的问题及应对方法。

3.1 数据清洗:缺失值、异常值和重复值的处理

在数据清洗过程中,主要处理的是缺失值、异常值和重复值。所谓清洗,是对数据集进行丢弃、填充、替换、去重等操作,实现去除异常、纠正错误、补足缺失的目的。

3.1.1 数据列缺失的4种处理方法

数据缺失分为两种:一是行记录的缺失,这种情况又称数据记录丢失;二是数据列值的缺失,即由于各种原因导致的数据记录中某些列的值空缺,不同的数据存储和环境中对于缺失值的表示结果也不同,例如,数据库中是Null, Python返回对象是None, Pandas或Numpy中是NaN。

注意

在极少数情况下,部分缺失值也会使用空字符串来代替,但空字符串绝对不同于缺失值。从对象的实体来看,空字符串是有实体的,实体为字符串类型;而缺失值其实没有实体的,即没有数据类型。

丢失的数据记录通常无法找回,这里重点讨论数据列类型缺失值的处理,通常有四种思路:

1.丢弃

这种方法简单明了,直接删除带有缺失值的行记录(整行删除)或者列字段(整列删除),减少缺失数据记录对总体数据的影响。但丢弃意味着会消减数据特征,以下任意一种场景都不宜采用该方法:

❑ 数据集总体中存在大量的数据记录不完整情况且比例较大,例如超过10%,删除这些带有缺失值的记录意味着将会损失过多有用信息。

❑ 带有缺失值的数据记录大量存在着明显的数据分布规律或特征,例如带有缺失值的数据记录的目标标签(即分类中的Label变量)主要集中于某一类或几类,如果删除这些数据记录将使对应分类的数据样本丢失大量特征信息,导致模型过拟合或分类不准确。

2.补全

相对丢弃而言,补全是更加常用的缺失值处理方式,通过一定的方法将缺失的数据补上,从而形成完整的数据记录对于后续的数据处理、分析和建模至关重要。常用的补全方法包括:

❑ 统计法:对于数值型的数据,使用均值、加权均值、中位数等方法补足;对于分类型数据,使用类别众数最多的值补足。

❑ 模型法:更多时候我们会基于已有的其他字段,将缺失字段作为目标变量进行预测,从而得到最为可能的补全值。如果带有缺失值的列是数值变量,采用回归模型补全;如果是分类变量,则采用分类模型补全。

❑ 专家补全:对于少量且具有重要意义的数据记录,专家补足也是非常重要的一种途径。

❑ 其他方法:例如随机法、特殊值法、多重填补等。

3.真值转换法

某些情况下,我们可能无法得知缺失值的分布规律,并且无法对于缺失值采用上述任何一种方法做处理;或者我们认为数据缺失也是一种规律,不应该轻易对缺失值随意处理,那么还有一种缺失值处理思路——真值转换。

该思路的根本观点是,我们承认缺失值的存在,并且把数据缺失也作为数据分布规律的一部分,这将变量的实际值和缺失值都作为输入维度参与后续数据处理和模型计算。但是变量的实际值可以作为变量值参与模型计算,而缺失值通常无法参与运算,因此需要对缺失值进行真值转换。

以用户性别字段为例,很多数据库集都无法对会员的性别进行补足,但又舍不得将其丢弃,那么我们将选择将其中的值,包括男、女、未知从一个变量的多个值分布状态转换为多个变量的真值分布状态。

❑ 转换前:性别(值域:男、女、未知)。

❑ 转换后:性别_男(值域1或0)、性别_女(值域1或0)、性别_未知(值域1或0)。

然后将这3列新的字段作为输入维度用以替换原来的1个字段参与后续模型计算。有关真值转换的具体方法和知识话题,会在3.2节具体介绍。

4.不处理

在数据预处理阶段,对于具有缺失值的数据记录不做任何处理,也是一种思路。这种思路主要看后期的数据分析和建模应用,很多模型对于缺失值有容忍度或灵活的处理方法,因此在预处理阶段可以不做处理。常见的能够自动处理缺失值的模型包括:KNN、决策树和随机森林、神经网络和朴素贝叶斯、DBSCAN(基于密度的带有噪声的空间聚类)等。这些模型对于缺失值的处理思路是:

❑ 忽略,缺失值不参与距离计算,例如KNN。

❑ 将缺失值作为分布的一种状态,并参与到建模过程,例如各种决策树及其变体。

❑ 不基于距离做计算,因此基于值的距离做计算,本身的影响就消除,例如DBSCAN。

提示

在数据建模前的数据归约阶段,有一种归约的思路是降维,降维中又有一种直接选择特征的方法。假如我们通过一定方法确定带有缺失值(无论缺少字段的值缺失数量有多少)的字段对于模型的影响非常小,那么我们根本就不需要对缺失值进行处理。因此,后期建模时对字段或特征的重要性判断也是决定是否处理字段缺失值的重要参考因素之一。

对于缺失值的处理思路是先通过一定方法找到缺失值,接着分析缺失值在整体样本中的分布占比以及缺失值是否具有显著的无规律分布特征,然后考虑后续要使用的模型中是否能满足缺失值的自动处理,最后决定采用哪种缺失值处理方法。在选择处理方法时,注意投入的时间、精力和产出价值,毕竟,处理缺失值只是整个数据工作的冰山一角而已。

注意

在数据采集时,可在采集端针对各个字段设置一个默认值。以MySQL为例,在设计数据库表时,可通过default指定每个字段的默认值,该值必须是常数。在这种情况下,假如原本数据采集时没有采集到数据,字段的值应该为Null,但由于在建立库表时设置了默认值,这会导致“缺失值”看起来非常正常,但本质上还是缺失的。对于这类数据需要尤其注意。

3.1.2 不要轻易抛弃异常数据

异常数据是数据分布的常态,处于特定分布区域或范围之外的数据通常会被定义为异常或“噪音”。产生数据“噪音”的原因很多,例如业务运营操作、数据采集问题、数据同步问题等。对异常数据进行处理前,需要先辨别出到底哪些是真正的数据异常。从数据异常的状态看分为两种:

❑ 一种是“伪异常”,这些异常是由于业务特定运营动作产生,其实是正常反映业务状态,而不是数据本身的异常规律。

❑ 一种是“真异常”,这些异常并不是由于特定的业务动作引起的,而是客观地反映了数据本身分布异常的个案。

大多数数据挖掘或数据工作中,异常值都会在数据的预处理过程中被认为是噪音而剔除,以避免其对总体数据评估和分析挖掘的影响。但在以下几种情况下,无须对异常值做抛弃处理。

1.异常值正常反映了业务运营结果

该场景是由业务部门的特定动作导致的数据分布异常,如果抛弃异常值将导致无法正确反馈业务结果。

例如:公司的A商品正常情况下日销量为1000台左右。由于昨日举行优惠促销活动导致总销量达到10000台,由于后端库存备货不足导致今日销量又下降到100台。在这种情况下,10000台和100台都正确反映了业务运营的结果,而非数据异常。

2.异常检测模型

异常检测模型是针对整体样本中的异常数据进行分析和挖掘以便找到其中的异常个案和规律,这种数据应用围绕异常值展开,因此异常值不能做抛弃处理。

异常检测模型常用于客户异常识别、信用卡欺诈、贷款审批识别、药物变异识别、恶劣气象预测、网络入侵检测、流量作弊检测等。在这种情况下,异常数据本身是目标数据,如果被处理掉将损失关键信息。

3.包容异常值的数据建模

如果数据算法和模型对异常值不敏感,那么即使不处理异常值也不会对模型本身造成负面影响。例如在决策树中,异常值本身就可以作为一种分裂节点。

提示

除了抛弃和保留,还有一种思路可对异常值进行处理,例如使用其他统计量、预测量进行替换,但不推荐使用这种方法,原因是这会将其中的关键分布特征消除,从而改变原始数据集的分布规律。

3.1.3 数据重复就需要去重吗

数据集中的重复值包括以下两种情况:

❑ 数据值完全相同的多条数据记录。这是最常见的数据重复情况。

❑ 数据主体相同但匹配到的唯一属性值不同。这种情况多见于数据仓库中的变化维度表,同一个事实表的主体会匹配同一个属性的多个值。

去重是重复值处理的主要方法,主要目的是保留能显示特征的唯一数据记录。但当遇到以下几种情况时,请慎重(不建议)执行数据去重。

1.重复的记录用于分析演变规律

以变化维度表为例。例如在商品类别的维度表中,每个商品对应了同1个类别的值应该是唯一的,例如苹果iPhone7属于个人电子消费品,这样才能将所有所有商品分配到唯一类别属性值中。但当所有商品类别的值重构或升级时(大多数情况下随着公司的发展都会这么做),原有的商品可能被分配了类别中的不同值。表3-1展示了这种变化。

表3-1 商品类别归属的变化

此时,我们在数据中使用Full join做跨重构时间点的类别匹配时,会发现苹果iPhone7会同时匹配到个人电子消费品和手机数码两条记录。对于这种情况,需要根据具体业务需求处理:

❑ 如果跟业务沟通,两条数据需要做整合,那么需要确定一个整合字段用来涵盖2条记录。其实就是将2条数据再次映射到一个类别主体中。

❑ 如果跟业务沟通,需要同时保存2条数据,那么此时不能做任何处理。后续的具体处理根据建模需求而定。

相关知识点:变化维度表

变化维度表是数据仓库中的概念。维度表类似于匹配表,用来存储静态的维度、属性等数据,而这些数据一般都不会改变。但是变与不变是一个相对的概念,随着企业的不断发展,很多时候维度也会发生变化。因此在某个时间内的维度是不变的,而从整体来看维度是变化的。

对于维度的变化,有3种方式进行处理:

直接覆盖原有值。这种情况下每个唯一ID就只对应一个属性值,这样做虽然简单粗暴也容易实现,但是无法保留历史信息。

添加新的维度行。此时同一个ID会得到两条匹配记录。

增加新的属性列。此时不会新增数据行记录,只是在原有的记录中新增一列用于标记不同时期的值。

具体到企业内使用哪种方式,通常是由数据库管理员根据实际情况来决定。

注意

真正的变化维度表或维度表不会以中文做主键,通常都会使用数字或字符串类作为唯一关联ID,本节的示例仅做说明之用。

2.重复的记录用于样本不均衡处理

在开展分类数据建模工作时,样本不均衡是影响分类模型效果的关键因素之一,解决分类方法的一种方法是对少数样本类别做简单过采样,通过随机过采样采取简单复制样本的策略来增加少数类样本。经过这种处理方式后,也会在数据记录中产生相同记录的多条数据。此时,我们不能对其中重复值执行去重操作。

有关样本不均衡的相关内容将在3.4节中介绍。

3.重复的记录用于检测业务规则问题

对于以分析应用为主的数据集而言,存在重复记录不会直接影响实际运营,毕竟数据集主要用来做分析;但对于事务型的数据而言,重复数据可能意味着重大运营规则问题,尤其当这些重复值出现在与企业经营中金钱相关的业务场景中,例如重复的订单、重复的充值、重复的预约项、重复的出库申请等。

这些重复的数据记录通常是由于数据采集、存储、验证和审核机制的不完善等问题导致的,会直接反映到前台生产和运营系统。以重复订单为例,假如前台的提交订单功能不做唯一性约束,那么在一次订单中重复点击提交订单按钮,就会触发多次重复提交订单的申请记录,如果该操作审批通过后,会联动带动运营后端的商品分拣、出库、送货,如果用户接收重复商品则会导致重大损失;如果用户退货则会增加反向订单,并影响物流、配送和仓储相关的各个运营环节,导致运营资源无端消耗、商品损耗增加、仓储物流成本增加等问题。

因此,这些问题必须在前期数据采集和存储时就通过一定机制解决和避免。如果确实产生了此类问题,那么数据工作者或运营工作者可以基于这些重复值来发现规则漏洞,并配合相关部门最大限度降低给企业带来的运营风险。

3.1.4 代码实操:Python数据清洗

1.缺失值处理

对于缺失值的处理,主要配合使用sklearn.preprocessing中的Imputer类、Pandas和Numpy。其中由于Pandas对于数据探索、分析和探查的支持较为良好,因此围绕Pandas的缺失值处理较为常用。

        import pandas as pd  # 导入Pandas库
        import numpy as np  # 导入Numpy库
        from sklearn.preprocessing import Imputer  # 导入sklearn.preprocessing中的Imputer库
        # 生成缺失数据
        df =  pd.DataFrame(np.random.randn(6,  4),  columns=['col1',  'col2',  'col3',
            'col4'])  # 生成一份数据
        df.iloc[1:2, 1] = np.nan  # 增加缺失值
        df.iloc[4, 3] = np.nan  # 增加缺失值
        print (df)
        # 查看哪些值缺失
        nan_all = df.isnull()  # 获得所有数据框中的N值
        print (nan_all)  # 打印输出
        # 查看哪些列缺失
        nan_col1 = df.isnull().any()  # 获得含有NA的列
        nan_col2 = df.isnull().all()  # 获得全部为NA的列
        print (nan_col1)  # 打印输出
        print (nan_col2)  # 打印输出
        # 丢弃缺失值
        df2 = df.dropna()  # 直接丢弃含有NA的行记录
        print (df2)  # 打印输出
        # 使用sklearn将缺失值替换为特定值
        nan_model = Imputer(missing_values='NaN', strategy='mean', axis=0)   # 建立替换规
            则:将值为Nan的缺失值用均值做替换
        nan_result = nan_model.fit_transform(df)  # 应用模型规则
        print (nan_result)  # 打印输出
        # 使用Pandas将缺失值替换为特定值
        nan_result_pd1 = df.fillna(method='backfill')  # 用后面的值替换缺失值
        nan_result_pd2 = df.fillna(method='bfill', limit=1)   # 用后面的值替换缺失值,限制每列
            只能替换一个缺失值
        nan_result_pd3 = df.fillna(method='pad')  # 用前面的值替换缺失值
        nan_result_pd4 = df.fillna(0)  # 用0替换缺失值
        nan_result_pd5 = df.fillna({'col2': 1.1, 'col4': 1.2})  # 用不同值替换不同列的缺失值
        nan_result_pd6 = df.fillna(df.mean()['col2':'col4'])  # 用平均数代替,选择各自列的均值
            替换缺失值
        # 打印输出
        print (nan_result_pd1)  # 打印输出
        print (nan_result_pd2)  # 打印输出
        print (nan_result_pd3)  # 打印输出
        print (nan_result_pd4)  # 打印输出
        print (nan_result_pd5)  # 打印输出
        print (nan_result_pd6)  # 打印输出

上述代码用空行分为6个部分。

第一部分为导入库,该代码示例中用到了Pandas、Numpy和Sklearn。

第二部分生成缺失数据,通过Pandas生成一个6行4列,列名分别为’col1'、'col2'、'col3'、'col4’的数据框。同时,数据框中增加两个缺失值数据。除了示例中直接通过pd.DataFrame来创建数据框外,还可以使用数据框对象的df.from_records、df.from_dict、df.from_items来从元组记录、字典和键值对对象创建数据框,或使用pandas.read_csv、pandas.read_table、pandas.read_clipboard等方法读取文件或剪贴板创建数据框。该代码段执行后返回了定义的含有缺失值的数据框,结果如下:

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      1-1.777315       NaN -0.166615-0.628756
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
        4  0.703394-0.764552-1.214379       NaN
        5  1.928313-1.376593-1.557721  0.289643

第三部分通过df.null()方法找到所有数据框中的缺失值(默认缺失值是NaN格式),然后使用any()或all()方法来查找含有至少1个或全部缺失值的列,其中any()方法用来返回指定轴中的任何元素为True,而all()方法用来返回指定轴的所有元素都为True。该代码段执行后返回如下结果。

1)判断元素是否是缺失值(第2行第2列和第5行第4列):

          col1   col2   col3   col4
      0  False  False  False  False
      1  False  True   False  False
      2  False  False  False  False
      3  False  False  False  False
      4  False  False  False   True
      5  False  False  False  False

2)列出至少有一个元素含有缺失值的列(该示例中为col2和col4):

        col1    False
        col2     True
        col3    False
        col4     True
        dtype:  bool

3)列出全部元素含有缺失值的列(该示例中没有):

        col1    False
        col2    False
        col3    False
        col4    False
        dtype:  bool

第四部分通过Pandas默认的dropna()方法丢弃缺失值,返回无缺失值的数据记录。该代码段执行后返回如下结果(第2行、第5行数据记录被删除):

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
      5  1.928313-1.376593-1.557721  0.289643

第五部分通过Sklearn的数据预处理方法对缺失值进行处理。首先通过Imputer方法创建一个预处理对象,其中strategy为默认缺失值的字符串,默认为NaN;示例中选择缺失值替换方法是均值(默认),还可以选择使用中位数和众数进行替换,即strategy值设置为median或most_frequent;后面的参数axis用来设置输入的轴,默认值为0,即使用列做计算逻辑。然后使用预处理对象的fit_transform方法对df(数据框对象)进行处理,该方法是将fit和transform组合起来使用。代码执行后返回如下结果:

        [[-0.11241503-0.76818022-0.08485904  0.29669147]
          [-1.77731513-0.44946793-0.16661458-0.62875601]
          [-0.62946127  1.89278959-1.85000643  0.15756702]
          [ 0.54486026-1.23080434  0.836615   -0.9457117 ]
          [ 0.70339369-0.76455205-1.21437918-0.16611331]
          [ 1.92831315-1.37659263-1.55772092  0.28964265]]

代码中的第2行第2列和第5行第4列分别被各自列的均值替换。为了验证我们手动计算各自列的均值,通过使用df['col2'].mean()和df['col4'].mean()分别获得这两列的均值,即-0.449467 928903 206 8和-0.166113 312596 647 91,跟Sklearn返回的结果一致。

第六部分使用Pandas做缺失值处理。Pandas对缺失值的处理方法是df.fillna(),该方法中最主要的两个参数是value和method。前者通过固定(或手动指定)的值替换缺失值,后者使用Pandas提供的默认方法替换缺失值,以下是method支持的方法:

❑ pad和ffill:使用前面的值替换缺失值,示例中nan_result_pd1和nan_result_pd2使用了该方法。

❑ backfill和bfill:使用后面的值替换缺失值,示例中nan_result_pd3使用了该方法。

❑ None:无。

在示例中nan_result_pd4、nan_result_pd5、nan_result_pd6分别使用0、不同的值、平均数替换缺失值。需要注意的是,如果要使用不同值替换,需要使用scalar、dict、Series或DataFrame的格式定义。

上述代码执行后返回如下结果。

1)用后面的值(method='backfill')替换缺失值:

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      1-1.777315  1.892790-0.166615-0.628756
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
      4  0.703394-0.764552-1.214379  0.289643
      5  1.928313-1.376593-1.557721  0.289643

2)用后面的值(method='bfill', limit = 1)替换缺失值:

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      1-1.777315  1.892790-0.166615-0.628756
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
      4  0.703394-0.764552-1.214379  0.289643
      5  1.928313-1.376593-1.557721  0.289643

3)用前面的值替换缺失值(method='pad'):

          col1      col2      col3      col4
        0-0.112415-0.768180-0.084859  0.296691
        1-1.777315-0.768180-0.166615-0.628756
        2-0.629461  1.892790-1.850006  0.157567
        3  0.544860-1.230804  0.836615-0.945712
        4  0.703394-0.764552-1.214379-0.945712
        5  1.928313-1.376593-1.557721  0.289643

4)用0替换缺失值:

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      1-1.777315  0.000000-0.166615-0.628756
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
      4  0.703394-0.764552-1.214379  0.000000
      5  1.928313-1.376593-1.557721  0.289643

5)手动指定两个缺失值分布为1.1和1.2:

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      1-1.777315  1.100000-0.166615-0.628756
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
      4  0.703394-0.764552-1.214379  1.200000
      5  1.928313-1.376593-1.557721  0.289643

6)用平均数代替,选择各自列的均值替换缺失值:

          col1      col2      col3      col4
      0-0.112415-0.768180-0.084859  0.296691
      1-1.777315-0.449468-0.166615-0.628756
      2-0.629461  1.892790-1.850006  0.157567
      3  0.544860-1.230804  0.836615-0.945712
      4  0.703394-0.764552-1.214379-0.166113
      5  1.928313-1.376593-1.557721  0.289643

以上示例中,直接指定method的方法适用于大多数情况,较为简单直接;但使用value的方法则更为灵活,原因是可以通过函数的形式将缺失值的处理规则写好,然后直接赋值即可。限于篇幅,这里不对所有方法做展开讲解。

另外,如果是直接替换为特定值的应用,也可以考虑使用Pandas的replace功能。本示例的df(原始数据框),可直接使用df.replace(np.nan,0),这种用法更加简单粗暴,但也能达到效果。当然,replace的出现是为了解决各种替换应用的,缺失值只是其中的一种应用而已。

上述过程中,需要考虑的关键点是:缺失值的替换策略,可指定多种方法替换缺失值,具体根据实际需求而定,但大多数情况下均值、众数和中位数的方法较为常用。如果场景固定,也可以使用特定值(例如0)替换。

2.异常值处理

有关异常值的确定有很多规则和方法,这里使用Z标准化得到的阈值作为判断标准:当标准化后的得分超过阈值则为异常。完整代码如下:

        import pandas as pd  # 导入Pandas库
        # 生成异常数据
        df = pd.DataFrame({'col1': [1, 120, 3, 5, 2, 12, 13],
                        'col2': [12, 17, 31, 53, 22, 32, 43]})
        print (df)  # 打印输出
        # 通过Z-Score方法判断异常值
        df_zscore = df.copy()  # 复制一个用来存储Z-score得分的数据框
        cols = df.columns  # 获得数据框的列名
        for col in cols:  # 循环读取每列
            df_col = df[col]  # 得到每列的值
            z_score = (df_col - df_col.mean()) / df_col.std()  # 计算每列的Z-score得分
            df_zscore[col] = z_score.abs() > 2.2  # 判断Z-score得分是否大于2.2,如果是则为True,
                否则为False
        print (df_zscore)  # 打印输出

示例代码用空行分为3个部分:

第一部分导入本例需要的Pandas库。

第二部分生成异常数据。直接通过DataFrame创建一个7行2列的数据框,打印输出结果如下:

          col1  col2
      0     1    12
      1   120    17
      2     3    31
      3     5    53
      4     2    22
      5    12    32
      6    13    43

第三部分为缺失值判断过程。本过程中,先通过df.copy()复制一个原始数据框的副本用来存储Z-Score标准化后的得分,再通过df.columns获得原始数据框的列名,接着通过循环来判断每一列中的异常值。在判断逻辑中,对每一列的数据使用自定义的方法做Z-Score值标准化得分计算,然后跟阈值2.2做比较,如果大于阈值则为异常。标准化的计算还有更多自动化的方法和场景,有关数据标准化的话题,将在3.9节中具体介绍。本段代码返回结果如下:

            col1   col2
        0  False  False
        1   True  False
        2  False  False
        3  False  False
        4  False  False
        5  False  False
        6  False  False

本示例方法中,阈值的设定是确定异常与否的关键,通常当阈值大于2时,已经是相对异常的表现值。

上述过程中,主要需要考虑的关键点是:如何判断异常值。对于有固定业务规则的可直接套用业务规则,而对于没有固定业务规则的,可以采用常见的数学模型进行判断,即基于概率分布的模型(例如正态分布的标准差范围)、基于聚类的方法(例如KMeans)、基于密度的方法(例如LOF)、基于分类的方法(例如KNN)、基于统计的方法(例如分位数法)等,此时异常值的定义带有较强的主观判断色彩,具体需要根据实际情况选择。

3.重复值处理

有关重复值的处理代码示例如下:

        import pandas as pd  # 导入Pandas库
        # 生成重复数据
        data1 = ['a', 3]
        data2 = ['b', 2]
        data3 = ['a', 3]
        data4 = ['c', 2]
        df = pd.DataFrame([data1, data2, data3, data4], columns=['col1', 'col2'])
        print (df)
        # 判断重复数据
        isDuplicated = df.duplicated()  # 判断重复数据记录
        print (isDuplicated)  # 打印输出
        # 删除重复值
        new_df1 = df.drop_duplicates()  # 删除数据记录中所有列值相同的记录
        new_df2 = df.drop_duplicates(['col1'])  # 删除数据记录中col1值相同的记录
        new_df3 = df.drop_duplicates(['col2'])  # 删除数据记录中col2值相同的记录
        new_df4 = df.drop_duplicates(['col1', 'col2'])  # 删除数据记录中指定列(col1/col2)值
            相同的记录
        print (new_df1)  # 打印输出
        print (new_df2)  # 打印输出
        print (new_df3)  # 打印输出
        print (new_df4)  # 打印输出

上述代码以空行分为4个部分。

第一部分为将数据导入用到的Pandas库。

第二部分生成重复数据,该数据是一个4行2列数据框,数据结果如下:

          col1  col2
        0    a     3
        1    b     2
        2    a     3
        3    c     2

第三部分判断数据记录是否为重复值,返回每条数据记录是否重复的结果,取值为True或False。判断方法为df.duplicated(),该方法中两个主要的参数是subset和keep:

❑ subset:要判断重复值的列,可以指定特定列或多个列。默认使用全部列。

❑ keep:当重复时不标记为True的规则,可设置为第一个(first)、最后一个(last)和全部标记为True(False)。默认使用first,即第一个重复值不标记为True。

结果如下:

        0    False
        1    False
        2     True
        3    False
        dtype: bool

第四部分为删除重复值的操作。该操作的核心方法是df.drop_duplicates(),该方法的作用是基于指定的规则判断为重复值之后,删除重复值,其参数跟df.duplicated()完全相同。在该部分方法示例中,依次使用默认规则(全部列相同的数据记录)、col1列相同、col2列相同以及指定col1和col2完全相同四种规则进行去重。返回结果如下:

1)删除数据记录中所有列值相同的记录:

          col1  col2
        0    a     3
        1    b     2
        3    c     2

2)删除数据记录中col1值相同的记录:

          col1  col2
        0    a     3
        1    b     2
        3    c     2

3)删除数据记录中col2值相同的记录:

          col1  col2
        0    a     3
        1    b     2

4)删除数据记录中指定列(col1和col2)值相同的记录:

          col1  col2
        0    a     3
        1    b     2
        3    c     2

提示

由于数据是通过随机数产生,因此读者操作的结果可能跟上述示例的数据结果不同。

除了Pandas可用来做重复值判断和处理外,也可以使用Numpy中的unique()方法,该方法返回其参数数组中所有不同的值,并且按照从小到大的顺序排列。Python自带的内置函数set方法,也能返回唯一元素的集合。

上述过程中,需要考虑的关键点是:如何对重复值进行处理。重复值的判断相对简单,而判断之后如何处理往往不是一个技术特征明显的工作,而是侧重于业务和建模需求的工作。

本小节示例中,主要用了几个知识点:

❑ 通过pd.DataFrame新建数据框;

❑ 通过df.iloc[]来选择特定的列或对象;

❑ 使用Pandas的isnull()判断值是否为空;

❑ 使用all()和any()判断每列是否包含至少1个为True或全部为True的情况;

❑ 使用Pandas的dropna()直接删除缺失值;

❑ 使用Sklearn.preprocessing中的Imputer方法对缺失值进行填充和替换,支持3种填充方法;

❑ 使用Pandas的fillna填充缺失值,支持更多自定义的值和常用预定义方法;

❑ 通过copy()获得一个对象副本,常用于原始对象和复制对象同时进行操作的场景;

❑ 通过for循环遍历可迭代的列表值;

❑ 自定义了Z-Score计算公式;

❑ 通过Pandas的duplicated()判断重复数据记录;

❑ 通过Pandas的drop_duplicates()删除数据记录,可指定特定列或全部。