前言
之前学习了将数据加载进来并观察一些数据特征。这次进一步学习将数据进行清洗以及特征处理,包括空值处理以及数值特征以及文本特征的处理。
#加载所需的库
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
df = pd.read_csv('train.csv')
df.head(10)
一、数据清洗
查看缺失值
因为拿到的数据可能会存在缺失值的问题,所以可以先观察数据,看看那些行列是包含空值的。
df.isnull().head(3) # isnull会判断该df的所有值是否是NaN并给一个布尔值
df.isnull().sum() # 利用sum方法可以求得每列的空值数的和.
df.isnull().any() # any方法是如果某一列有一个true,就会返回true. 通过这个可以看出那一列存在缺失值.
df[(df.isnull().values == True).any(axis=1)] # 取有空值属性的行
values
取的是df的值组成的ndarray
,而如果不用values
,用df.isnull()==True
来做判断返回的其实是一个Series
的bool
.
这里在实验的时候发现了一个问题,就是用any(axis=1)
与不用的区别。当不使用时,无论是df.isnull()==True
还是df.isnull().values == True
的判断其实都是返回的一个二维bool,维度是(行, 列)。而二维的在给df
时,对于每一行的判断就会判断列
次,所以就导致有的行会不止出现一次,因为该行可能存在不止一个缺失值的情况。
df.head(10)[(df.isnull().head(10).values == True).any(axis=1)] # 传的是一个(10,)bool数组
这里由于any(axis=1)
的作用,使得返回的是一个一维的bool
(无论是用values
的array
还是Series
),长度为(行,)。所以传给df
去做判断时每行就只会执行一次判断,不会出现重复值。
df.head(10)[df.head(10).isnull().values == True] # 5有俩空值,就会给两次? 传的是(10,12)bool数组 每行都会执行12次比较.
而这里没有使用any
来做判断,所以其实是二维的,而二维给df
去判断时,每行会判断“1”维度的次数。这就导致5所在的行有两个缺失值,所以在给df
时,有两次是True
。
缺失值处理
在判断了那些行列是有缺失值后,就需要对其进行处理。处理缺失值的方法常用的有删除所在行列以及给缺失值填值。
df[df['Cabin'].isnull()]=0 # 这个0直接把空值所在行的所有值都置为o了。
df
df.dropna().shape ## (183, 12)
可以通过pd.dropna()
方法来删掉有空值的行。不过这样子会导致如果存在空值比较多的表,会删掉好多数据。比如这个,删掉后只有183行可用了。
df.fillna(0).head() # 常用value method limit 参数
除了删掉存在空值的行的方法,还可以用fillna()
方法来给空值填值。其中, value
为填充值,可以是标量,也可以是索引到元素的字典映射; method
为填充方法,有用前面的元素填充 ffill
和用后面的元素填充 bfill
两种类型, limit
参数表示连续缺失值的最大填充次数,如果为1表示连续缺失的话只填充1次。
重复值处理
还会存在一些行重复的情况,这个时候可以考虑删掉多余的行。
# 取重复的行
df[df.duplicated()] # df.duplicated()会给出一个包含 bool的Series,对应每行是否是重复值(第一行默认为False)
# 删掉重复的行
df = df.drop_duplicates() # 可以传一个列表,判断该列索引下重复值
二、特征处理
数据存在离散数值连续数值的特征,还有一些是文本特征,纯文本的。数值型特征一般可以直接用于模型的训练,但有时候为了模型的稳定性及鲁棒性会对连续变量进行离散化。文本型特征往往需要转换成数值型特征才能用于建模分析。
数值特征
这里考虑对数值特征做离散化,也就是分箱处理。
分箱操作其实就是将数据划分到几个离散化的箱子中,然后用箱子的类别来代表原数据。
以Age
为例
(2) 将连续变量Age平均分箱成5个年龄段,并分别用类别变量12345表示
df['Ageband'] = pd.cut(df['Age'], 5, labels=[1,2,3,4,5]) # 根据数据平均划分为5个bin 中间是个整数
df.head()
(3) 将连续变量Age划分为[0,5) [5,15) [15,30) [30,50) [50,80)五个年龄段,并分别用类别变量12345表示
df['Ageband'] = pd.cut(df['Age'], [0, 5, 15, 30, 50, 80], labels=[1,2,3,4,5])
df.head()
主要用到了pd.cut()
其中常见三个参数,第一个x
是对哪一列做处理;第二个bin
是分几个,可以是一个整数,就代表取平均了;也可以是一个序列,左闭右开区间,代表每个箱子的范围。第三个label
代表每个箱子的类别,就是用这个来代表原数据。
(4) 将连续变量Age按10% 30% 50% 70% 90%五个年龄段,并用分类变量12345表示
df['Ageband'] = pd.qcut(df['Age'],[0,0.1,0.3,0.5,0.7,0.9] ,labels=[1,2,3,4,5])
这里因为只给了百分比所以需要让数据自己去判断自己是属于百分之几的,所以其实是一个无监督的过程。用到qcut()
。
文本特征
需要将文本变量变为数值型的才能进行后续建模。
(2) 将文本变量Sex, Cabin ,Embarked用数值变量12345表示
# 使用sklearn.preprocessing的LabelEncoder 可以将n个类别编码为0~n-1之间的整数(包含0和n-1)
for feat in ['Sex', 'Cabin', 'Embarked']:
lbl = LabelEncoder()
label_dict = dict(zip(df[feat].unique(), range(df[feat].nunique()))) # 建立一个该列唯一值与数字的映射
df[feat+'_Encoder'] = df[feat].map(label_dict) # 用map也行
df[feat+'_Encoder'] = lbl.fit_transform(df[feat].astype(str)) # 将构建与转化写在一个方法里执行了
df.head()
(3) 将文本变量Sex, Cabin, Embarked用one-hot编码表示
x = pd.get_dummies(df['Sex'], prefix='sex') # prefix指明列名前缀
pd.get_dummies()
方法可以根据某一列的值将其one-hot编码。如果需要加在原df
里作为新特征列,需要拼接起来。可以用join()
根据行索引做关系型连接,也可以用concat()
做方向连接。
pd.concat([df, x],axis=1)
axis=1
指明纵向拼接.通常是作为加特征用,把x继续加在后面 默认为0是横向拼接,看作加数据用.
从纯文本Name特征里提取出Titles的特征(所谓的Titles就是Mr,Miss,Mrs等)
df['Title'] = df.Name.str.extract('([A-Za-z]+)\.', expand=False)
pd.str.extract()
方法根据正则去在某列数据中选出匹配的。
总结
本次学习了解到了加载数据,从数据整体观察特征分布以及某些特征与预测的关系后,对于缺失值与重复值该如何处理。查看缺失数据后可以选择删掉,也可以选择用相关数据来填充,0也好,该列数据的mean
也好,总之可以选择相应的值来填充;对于重复行,可以选择删掉。此外,数据特征包含数值的也包含文本的,对于数值特征可以做离散化处理;以离散化箱子来代表原数据,对于文本数据要转化为数值型;这里了解到一种方法是转换为整数类别,另一种是one-hot
编码。