复杂的数据处理过程(含清洗) 1. 数据解读 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 merchant = pd.read_csv('./eloData/merchants.csv' , header=0 ) merchant.head(5 ) merchant.info() ''' Output exceeds the size limit. Open the full output data in a text editor <class 'pandas.core.frame.DataFrame'> 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 ''' df = pd.read_excel('./eloData/Data_Dictionary.xlsx' , header=2 , sheet_name='merchant' ) df 
 
2. 数据探索 
查看id出现次数是否唯一
1 2 3 4 5 6 7 8 print (merchant.shape, merchant['merchant_id' ].nunique())''' (334696, 22) 334633 能够看出,该表并不是一个id对应一条数据,存在一个商户有多条记录的情况。 ''' print (pd.Series(merchant.columns.tolist()).sort_values().values ==  pd.Series([va[0 ] for  va in  df.values]).sort_values().values)
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 ''' 
 
能够发现,第二个匿名分类变量存在较多缺失值,而avg_sales_lag3/6/12缺失值数量一致,则很有可能是存在13个商户同时确实了这三方面信息。其他数据没有缺失,数据整体来看较为完整。
3. 数据预处理 3.1 离散/连续字段标注 由于商户数据集中特征同时存在分类变量和离散变量,因此我们首先可以根据字段的说明对不同属性特征进行统一的划分:
1 2 3 4 5 6 7 8 9 10 11 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' ] assert  len (category_cols) + len (numeric_cols) == merchant.shape[1 ]
 
3.2 离散数据处理 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 merchant[category_cols].nunique() ''' merchant_id                    334633 merchant_group_id              109391 merchant_category_id              324 subsector_id                       41 category_1                          2 most_recent_sales_range             5 most_recent_purchases_range         5 category_4                          2 city_id                           271 state_id                           25 category_2                          5 dtype: int64 ''' merchant[category_cols].dtypes ''' merchant_id                     object merchant_group_id                int64 merchant_category_id             int64 subsector_id                     int64 category_1                      object most_recent_sales_range         object most_recent_purchases_range     object category_4                      object city_id                          int64 state_id                         int64 category_2                     float64 dtype: object ''' merchant[category_cols].isnull().sum () ''' merchant_id                        0 merchant_group_id                  0 merchant_category_id               0 subsector_id                       0 category_1                         0 most_recent_sales_range            0 most_recent_purchases_range        0 category_4                         0 city_id                            0 state_id                           0 category_2                     11887 dtype: int64 ''' 注意到离散变量中的category_2存在较多缺失值,由于该分类变量取值水平为1 -5 ,因此可以将缺失值先标注为-1 ,方便后续进行数据探索 merchant['category_2' ].unique() merchant['category_2' ] = merchant['category_2' ].fillna(-1 ) 
 
接下来对离散变量进行字典编码,即将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类型转化为数值型。==(object类型转换类型)==
1 2 3 4 5 def  change_object_cols (se ):    value = se.unique().tolist()     value.sort()     return  se.map (pd.Series(range (len (value)), index=value)).values 
 
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 merchant['category_1' ] ''' 0         N 1         N 2         N 3         Y 4         Y          .. 334691    N 334692    Y 334693    N 334694    Y 334695    N Name: category_1, Length: 334696, dtype: object ''' change_object_cols(merchant['category_1' ]) 
 
3.3 连续变量数据探索 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 merchant[numeric_cols].dtypes ''' numerical_1            float64 numerical_2            float64 avg_sales_lag3         float64 avg_purchases_lag3     float64 active_months_lag3       int64 avg_sales_lag6         float64 avg_purchases_lag6     float64 active_months_lag6       int64 avg_sales_lag12        float64 avg_purchases_lag12    float64 active_months_lag12      int64 dtype: object ''' merchant[numeric_cols].isnull().sum () merchant[numeric_cols].describe() 
 
据此我们发现连续型变量中存在部分缺失值,并且部分连续变量还存在无穷值inf,需要对其进行简单处理。
1 2 3 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 ()) 
 
不同于无穷值的处理,缺失值处理方法有很多。但该数据集缺失数据较少,33万条数据中只有13条连续特征缺失值,此处我们先简单采用均值进行填补处理,后续若有需要再进行优化处理。
1 2 3 for  col in  numeric_cols:    merchant[col] = merchant[col].fillna(merchant[col].mean()) merchant[numeric_cols].describe()`