数据预处理流程

数据预处理流程总结

下面分享一下自己通常会用到的一些数据预处理的方法和步骤,用Kaggle平台上的elo用户忠诚度预测的数据集作为应用案例。

数据预处理流程_第1张图片

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
merchant = pd.read_csv(r'\原始数据\elo-merchant-category-recommendation\merchants.csv', header=0)

一、初步探索

拿到一份数据,首先要确定样本大小、特征个数、字段类型这些基本信息。用.info()可以初步得到数据集的这些信息

merchant.info()

RangeIndex: 334696 entries, 0 to 334695
Data columns (total 22 columns):
 #   Column                       Non-Null Count   Dtype  
---  ------                       --------------   -----  
 0   merchant_id                  334696 non-null  object 
 1   merchant_group_id            334696 non-null  int64  
 2   merchant_category_id         334696 non-null  int64  
 3   subsector_id                 334696 non-null  int64  
 4   numerical_1                  334696 non-null  float64
 5   numerical_2                  334696 non-null  float64
 6   category_1                   334696 non-null  object 
 7   most_recent_sales_range      334696 non-null  object 
 8   most_recent_purchases_range  334696 non-null  object 
 9   avg_sales_lag3               334683 non-null  float64
 10  avg_purchases_lag3           334696 non-null  float64
 11  active_months_lag3           334696 non-null  int64  
 12  avg_sales_lag6               334683 non-null  float64
 13  avg_purchases_lag6           334696 non-null  float64
 14  active_months_lag6           334696 non-null  int64  
 15  avg_sales_lag12              334683 non-null  float64
 16  avg_purchases_lag12          334696 non-null  float64
 17  active_months_lag12          334696 non-null  int64  
 18  category_4                   334696 non-null  object 
 19  city_id                      334696 non-null  int64  
 20  state_id                     334696 non-null  int64  
 21  category_2                   322809 non-null  float64
dtypes: float64(9), int64(8), object(5)
memory usage: 56.2+ MB

用.info()搞清楚哪些是分类变量,哪些是数值型变量,分类进行处理。可以先把变量名分类放入category_cols、numeric_cols两个列表中,等待后续操作。

由于object类型变量中有一些离散型变量,之后要把它们的取值映射到数值上(比如category_1有3个取值,分别是A 、B、C,无法直接对它们进行建模计算,要把它们分别转化成0、1、2),也可以把这样的object型变量名存放起来。

category_cols = ['merchant_id', 'merchant_group_id', 'merchant_category_id',
       'subsector_id', 'category_1',
       'most_recent_sales_range', 'most_recent_purchases_range',
       'category_4', 'city_id', 'state_id', 'category_2']
numeric_cols = ['numerical_1', 'numerical_2',
     'avg_sales_lag3', 'avg_purchases_lag3', 'active_months_lag3',
       'avg_sales_lag6', 'avg_purchases_lag6', 'active_months_lag6',
       'avg_sales_lag12', 'avg_purchases_lag12', 'active_months_lag12']
object_cols = ['category_1','most_recent_sales_range','most_recent_purchases_range','category_4' ]

二、正确性校验

2.1 样本重复性检验

一般多用于数据中的样本ID重复性检验,有些数据里面的样本id是不允许重复的,比如订单ID在电商系统中是不会重复使用的,这样的数据集中就不该有重复的样本id,没有重复的订单ID,才算是一份比较漂亮的数据。电商数据中,重复的订单ID可能说明以下两个事实:(1)样本中有大量重复数据(2)数据中的每条样本并不是订单,而是订单中的一个商品,因此标签中的异常实际上可能是“这笔交易的异常”,而不是整个订单的异常(如果是这种情况,数据预处理就会比较困难了)

而有些情况下,样本id重复是被允许的,比如在本文使用的这个例子当中,商户信息数据集中,商户id有重复,因为一些商户进行了业务更新;在一些信用卡交易记录数据中,每张信用卡可以交易多次,所以数据集中出现多个样本具有同样的id,也是一件正常的事情,还是要结合具体业务背景来看样本重复性是否被允许。但是样本重复性检验的确是不可缺失的一个步骤。

这一个步骤常用到.unique()和.nunique()

.unique()返回某一列中所有不同的值。
.nunique()返回某一列中不同取值的个数。

merchant.nunique()
merchant_id                    334633
merchant_group_id              109391
merchant_category_id              324
subsector_id                       41
numerical_1                       954
numerical_2                       947
category_1                          2
most_recent_sales_range             5
most_recent_purchases_range         5
avg_sales_lag3                   3372
avg_purchases_lag3             100003
active_months_lag3                  3
avg_sales_lag6                   4507
avg_purchases_lag6             135202
active_months_lag6                  6
avg_sales_lag12                  5009
avg_purchases_lag12            172917
active_months_lag12                12
category_4                          2
city_id                           271
state_id                           25
category_2                          5
dtype: int64
merchant.nunique()==merchant.shape[0]
merchant_id                    False
merchant_group_id              False
merchant_category_id           False
subsector_id                   False
numerical_1                    False
numerical_2                    False
category_1                     False
most_recent_sales_range        False
most_recent_purchases_range    False
avg_sales_lag3                 False
avg_purchases_lag3             False
active_months_lag3             False
avg_sales_lag6                 False
avg_purchases_lag6             False
active_months_lag6             False
avg_sales_lag12                False
avg_purchases_lag12            False
active_months_lag12            False
category_4                     False
city_id                        False
state_id                       False
category_2                     False
dtype: bool

merchant.shape[0]是样本量,上面这一个命令是检查每个变量中的取值个数是否等于样本数量,若不等于(返回False),那就是有重复值出现.

若等于(返回True),就说明该变量里面没有重复值。

merchant数据集中所有的变量都是含有重复值的,并没有哪个变量里面的取值完全不一样

2.2 缺失值、无穷值处理

缺失值处理

查看每一个变量中所含有缺失值的样本个数:data.isnull().sum()

merchant.isnull().sum()
merchant_id                        0
merchant_group_id                  0
merchant_category_id               0
subsector_id                       0
numerical_1                        0
numerical_2                        0
category_1                         0
most_recent_sales_range            0
most_recent_purchases_range        0
avg_sales_lag3                    13
avg_purchases_lag3                 0
active_months_lag3                 0
avg_sales_lag6                    13
avg_purchases_lag6                 0
active_months_lag6                 0
avg_sales_lag12                   13
avg_purchases_lag12                0
active_months_lag12                0
category_4                         0
city_id                            0
state_id                           0
category_2                     11887
dtype: int64

处理缺失值几个可以思考的方向:

(1) 缺失是否与异常相关?(在样本不平衡场景下可以使用,比如:异常订单识别、患者筛查等等)

  • 看一下有缺失值的样本和异常样本之间的交集,交集越大说明样本缺失与异常越紧密,这时就一定不能删除缺失样本。 还要看两个比例:交集部分/缺失值样本、交集部分/缺失值样本。

    • 交集部分/缺失值样本:若该比例较大,说明缺失样本大多数是异常样本。

    • 交集部分/异常值样本:异常值样本是珍稀物种,如果该比例较大,直接删除缺失值样本,就加重了样本不平衡问题让异常值更加难以捕捉。如果该比例小,直接删去缺失值样本,影响也不会太大。

(2)众数、均值填补

(3)算法填补

(4)直接删掉:.dropna(),删除之后一定要恢复索引:data.index=range(data.shape[0])

当然也可以把四种方法都尝试一下,看看在四份数据集上面建起来的模型谁的表现更好一些。

填补之前可以大致看一下数据分布,缺失值较少的情况下,就直接用均值、众数、中位数来填补;如果连续型变量的缺失值较多,可以考虑用算法填补(比如随机森林);如果是离散型变量缺失值很多的情况,可以先用一个数字来标记这些缺失值。

avg_sales_lag3=merchant['avg_sales_lag3'].value_counts().sort_index()
avg_sales_lag3
-82.13         1
-0.72          1
-0.40          1
 0.33         42
 0.34         99
              ..
 360107.00     1
 385833.00     1
 608433.00     1
 624741.00     1
 851844.64     1
Name: avg_sales_lag3, Length: 3372, dtype: int64

统计不同取值的样本个数,并从大到小排序发现取值范围非常大,但是极度偏态,较大的取值之间非常离散。再来用可视化的方法看一下数据分布状况。用到的画图函数是自定义函数,代码在这篇博客里面,可以直接调用数据分布探索函数。

for i in ['avg_sales_lag3','avg_sales_lag6','avg_sales_lag12']:
    data_distribution_explore(merchant,i,va_type='numeric')
data_distribution_explore(merchant,'category_2',va_type='category')

数据预处理流程_第2张图片

数据预处理流程_第3张图片数据预处理流程_第4张图片数据预处理流程_第5张图片

一共四个变量含有缺失值,离散变量’category_2’有许多缺失值(11887个),连续型数值变量‘avg_sales_lag3’、‘avg_sales_lag6’、‘avg_sales_lag12’都只有13个缺失值,数量较少。

因此,对于’category_2’,用-1来填补这些缺失值;对于‘avg_sales_lag3’、‘avg_sales_lag6’、‘avg_sales_lag12’,直接用中位数来填补,或者删掉也无妨。

#填补缺失值(分类型变量)
merchant['category_2'] = merchant['category_2'].fillna(-1)
  • 方案一:中位数填补(连续型数值变量)
numeric_fill=['avg_sales_lag3','avg_sales_lag6','avg_sales_lag12']
for i in numeric_fill:
    merchant[i] = merchant[i].fillna(merchant[i].median())
numeric_fill=['avg_sales_lag3','avg_sales_lag6','avg_sales_lag12']
for i in numeric_fill:
    merchant[i] = merchant[i].fillna(merchant[i].median())
  • 方案二:直接删掉少数缺失的样本(副本上操作)。切记!养成好习惯:删除样本后,立刻恢复索引,否则dataframe里面会有空样本。
data=merchant.copy()
data.dropna(inplace=True)
data.index=range(data.shape[0])
merchant.isnull().sum()
merchant_id                    0
merchant_group_id              0
merchant_category_id           0
subsector_id                   0
numerical_1                    0
numerical_2                    0
category_1                     0
most_recent_sales_range        0
most_recent_purchases_range    0
avg_sales_lag3                 0
avg_purchases_lag3             0
active_months_lag3             0
avg_sales_lag6                 0
avg_purchases_lag6             0
active_months_lag6             0
avg_sales_lag12                0
avg_purchases_lag12            0
active_months_lag12            0
category_4                     0
city_id                        0
state_id                       0
category_2                     0
dtype: int64

缺失值填补完毕

无穷值处理

查看哪些变量里面含有inf值,直接.describe(),看均值和最大值

merchant.describe()

数据预处理流程_第6张图片

可以看到还是有一些变量(avg_purchases_lag3、avg_purchases_lag6、avg_purchases_lag12)的最大值、均值出现了inf,说明这些变量里面存在inf值,无法直接建模。可以使用天花板盖帽法的方式对其进行修改,即将inf改为最大的显式数值。代码实现流程如下:

inf_cols = ['avg_purchases_lag3', 'avg_purchases_lag6', 'avg_purchases_lag12']
merchant[inf_cols] = merchant[inf_cols].replace(np.inf, merchant[inf_cols].replace(np.inf, -99).max().max())
merchant.describe()
merchant_group_id merchant_category_id subsector_id numerical_1 numerical_2 avg_sales_lag3 avg_purchases_lag3 active_months_lag3 avg_sales_lag6 avg_purchases_lag6 active_months_lag6 avg_sales_lag12 avg_purchases_lag12 active_months_lag12 city_id state_id category_2
count 334696.000000 334696.000000 334696.000000 334696.000000 334696.000000 334696.000000 334696.000000 334696.000000 3.346960e+05 334696.000000 334696.000000 3.346960e+05 334696.000000 334696.000000 334696.000000 334696.000000 334696.000000
mean 31028.736143 423.131663 25.116404 0.011476 0.008103 13.832494 2.145143 2.994108 2.164999e+01 2.441947 5.947397 2.522677e+01 2.633572 11.599335 102.917926 11.860942 2.259958
std 31623.043426 252.898046 9.807371 1.098154 1.070497 2395.443478 213.955844 0.095247 3.947031e+03 209.439373 0.394936 5.251740e+03 205.206198 1.520138 107.090673 6.176889 1.657263
min 1.000000 -1.000000 -1.000000 -0.057471 -0.057471 -82.130000 0.333495 1.000000 -8.213000e+01 0.167045 1.000000 -8.213000e+01 0.098330 1.000000 -1.000000 -1.000000 -1.000000
25% 3612.000000 222.000000 19.000000 -0.057471 -0.057471 0.880000 0.923650 3.000000 8.500000e-01 0.902247 6.000000 8.500000e-01 0.898333 12.000000 -1.000000 9.000000 1.000000
50% 19900.000000 373.000000 27.000000 -0.057471 -0.057471 1.000000 1.016667 3.000000 1.010000e+00 1.026961 6.000000 1.020000e+00 1.043361 12.000000 69.000000 9.000000 1.000000
75% 51707.250000 683.000000 33.000000 -0.047556 -0.047556 1.160000 1.146522 3.000000 1.230000e+00 1.215575 6.000000 1.290000e+00 1.266480 12.000000 182.000000 16.000000 4.000000
max 112586.000000 891.000000 41.000000 183.735111 182.079322 851844.640000 61851.333333 3.000000 1.513959e+06 61851.333333 6.000000 2.567408e+06 61851.333333 12.000000 347.000000 24.000000 5.000000

数据中已经没有无穷值了

2.3 数据类型转变

  • 离散变量字典编码

  接下来对离散变量进行字典编码,即将object对象类型按照sort顺序进行数值化(整数)编码。例如原始category_1取值为Y/N,通过sort排序后N在Y之前,因此在重新编码时N取值会重编码为0、Y取值会重编码为1。以此类推。

  需要注意的是,从严格角度来说,变量类型应该是有三类:连续性变量、名义型变量以及有序变量。

名义变量:没有数值大小意义的分类变量,例如用1表示女、0表示男,0、1只是作为性别的指代,而没有1>0的含义。

有序变量:离散型变量,但却有数值大小含义,如上述most_recent_purchases_range字段,销售等级中A>B>C>D>E,该离散变量的5个取值水平是有严格大小意义的,该变量就被称为有序变量。

下面自定义一个编码函数,可以将object型变量转化成离散型变量

# 字典编码函数
def change_object_cols(se):
    value = se.unique().tolist()
    value.sort()#从小到大排序
    return se.map(pd.Series(range(len(value)), index=value)).values
for col in object_cols:
    merchant[col] = change_object_cols(merchant[col])

你可能感兴趣的:(数据预处理,机器学习,python,数据挖掘)