目录
4、数据清洗与特征处理
4.1缺失值观察与处理
4.1.1 任务一:缺失值观察
4.1.2 任务二:对缺失值进行处理
4.2重复值观察与处理
4.2.1 任务一:查看数据中的重复值
4.2.2 任务二:处理重复值
4.2.3 任务三:保存清洗的数据为csv格式
4.3特征值观察与处理
4.3.1 任务一:对年龄进行分箱(离散化)处理
4.3.2 任务二:对文本变量进行转换
4.3.2 任务三(附加):从纯文本Name特征里提取出Titles的特征(所谓的Titles就是Mr,Miss,Mrs等)
4、数据清洗与特征处理
4.1缺失值观察与处理
4.1.1 任务一:缺失值观察
(1)查看缺失值个数:
# 将空值形式的缺失值转换成可识别的类型
titanic_train = titanic_train.replace(' ', np.NaN)
(2)查看'Age', 'Cabin', 'Embarked'列的数据
titanic_train.isnull().sum() # 汇总各列缺失值数目
4.1.2 任务二:对缺失值进行处理
(1) 处理缺失值一般有几种思路
(2) 请尝试对Age列的数据的缺失值进行处理
(3) 请尝试使用不同的方法直接对整张表的缺失值进行处理
①直接删除:
--查看有缺失值的行占总行数的比例,如果小,则可直接删除
# 输出有缺失值的行
null_age = titanic_train[pd.isnull(titanic_train['Age'])]
null_cabin = titanic_train[pd.isnull(titanic_train['Cabin'])]
null_embarked = titanic_train[pd.isnull(titanic_train['Embarked'])]
# 有缺失值的行占总行比例
ratio_age = len(null_age)/len(titanic_train)
ratio_cabin = len(null_cabin)/len(titanic_train)
ratio_embarked = len(null_embarked)/len(titanic_train)
print(ratio_age, ratio_cabin, ratio_embarked)
--如Embarked列中有缺失值的行占比较小,可删除
# ‘any’删除该列有缺失值的行
titanic_train = titanic_train.dropna(axis=0, how='any', subset=['Embarked'])
②使用一个常量填充(利用fillna函数)
--利用一个常数填充缺失值,计算机会自动认为其很有趣,但十分不可靠
titanic_train['Cabin'].fillna(0, inplace=True) # 以0填补缺失值
③就近填充
titanic_train = titanic_train.fillna(axis=0, method='ffill') # 就近填充
--axis=0,按行填充,=1,按列填充;method='ffill'或'pad',按前一个值填充,='backfill'或'bfill',按后一个值填充
④均值、中位数、众数填充
--当分布近似正态,用均值;当分布偏态或包含离群点,用中位数;当变量为分类变量,则用众数
# 用该列众数填充(非数值型数据)
titanic_train['Cabin'].fillna(titanic_train['Cabin'].mode())
# 用该列中值填充
titanic_train['Age'].fillna(titanic_train['Age'].median())
⑤插值法、KNN填充
--插值法interpolate():用缺失值前后均值填充
# 缺失值前后值的均值填充
titanic_train['Age'].interpolate()
--KNN填充:利用邻近的K个样本训练模型,预估缺失值
⑥随机森林填充算法
思考:
--dropna():
dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
--axis:0或'index',按行删除;1或'columns',按列删除。
--how:‘any’,该行/列只要有一个以上的空值,就删除该行/列;‘all’,该行/列全部都为空值,就删除该行/列。
--thresh:int型,默认为None。若该行/列中非空元素数量小于这个值,就删除该行/列。
--subset:(根据axis决定为)行/列的索引。由subset限制的子区域,是判断是否删除该行/列的条件判断区域。
--inplace:布尔值,默认为False。如果为True,则在原DataFrame上进行操作,返回值为None
--fillna():
fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
--value:用于填充空值的值。
--method:填充空值的方法, 'ffill'或'pad',按前一个值填充;'backfill'或'bfill',按后一个值填充
--axis:=0,按行填充,=1,按列填充。
--inplace:布尔值,默认为False。如果为True,则在原DataFrame上进行操作,返回值为None
--limit:int, default None。限制最多填充前 limit 个空值
4.2重复值观察与处理
4.2.1 任务一:查看数据中的重复值
(1)查看重复值行(是则返回True):
titanic_train.duplicated() # 查看重复值的行
(2)查看重复值的行的个数:
titanic_train.duplicated().sum() # 统计重复值行的个数
4.2.2 任务二:处理重复值
# 直接在原数据上删除重复数据
titanic_train.drop_duplicates(inplace=True)
# 删除行以后需重置索引
titanic_train.reset_index()
4.2.3 任务三:保存清洗的数据为csv格式
titanic_train.to_csv('train_clear.csv', encoding='gbk')
4.3特征值观察与处理
4.3.1 任务一:对年龄进行分箱(离散化)处理
(1) 分箱操作是什么?
--按照特定的条件,将不同的数据放在特定的容器里(分类)
--分箱操作主要针对连续变量
--分箱操作原因:
①对于异常值具有很强鲁棒性:如果特征没有被离散化,异常数据会对模型造成干扰
②在逻辑回归中,单变量离散变成n个哑变量后,每个都有单独权重,相当于引入非线性,增加模型对数据的拟合程度
③缺失值作为一组特殊的变量引入模型
④降低数据复杂度,提升运算速度
--分箱操作分为无序变量分箱,有序变量分箱及连续变量分箱(包含监督和无监督【前者根据人为医院划分,后者代码自己划分】)
--监督常用cut()——等宽划分(按宽度分,受异常值影响大):
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise')
--x::类array对象,且必须为一维,待切割的原形式
--bins:整数、序列尺度、或间隔索引。如果bins是一个整数,它定义了x宽度范围内的等宽面元数量,但是在这种情况下,x的范围在每个边上被延长1%,以保证包括x的最小值或最大值。如果bin是序列,它定义了允许非均匀in宽度的bin边缘。在这种情况下没有x的范围的扩展。
--right:布尔值。是否是左开右闭区间
--labels:用作结果箱的标签。必须与结果箱相同长度。如果FALSE,只返回整数指标面元。
--retbins:布尔值。是否返回面元
--precision:整数。返回面元的小数点几位
--include_lowest:布尔值。第一个区间的左端点是否包含
--无监督调常用卡方分箱
(2) 将连续变量Age平均分箱成5个年龄段,并分别用类别变量12345表示
--数值平均分为5个年龄段,属于等宽,采用cut():
titanic_train['AgeBand'] = pd.cut(titanic_train['Age'], 5, labels = [1,2,3,4,5])
# 等宽分类(将数值范围均分为数段)
(3) 将连续变量Age划分为(0,5] (5,15] (15,30] (30,50] (50,80]五个年龄段,并分别用类别变量12345表示
--数值区间分类,采用cut():
titanic_train['AgeBand'] = pd.cut(titanic_train['Age'],[0,5,15,30,50,80],labels = [1,2,3,4,5])
# 按区间分类
(4) 将连续变量Age按10% 30% 50% 70% 90%五个年龄段,并用分类变量12345表示
--按样本数量百分比分类,尽量保证每个区间数目相同,采用qcut():
titanic_train['AgeBand'] = pd.qcut(titanic_train['Age'],[0,0.1,0.3,0.5,0.7,0.9],labels = [1,2,3,4,5])
# 等数分类(每组数目相同,常使用百分比分类)
--总结:
使用qcut()还是cut(),根本区别在于是否保证分类区间数目一致,若一致,则选用qcut()
4.3.2 任务二:对文本变量进行转换
(1) 查看文本变量名及种类
--①可使用value_counts(),对各类别统计:
value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)
--normalize : 默认false,如为true,则以百分比的形式显示
--sort :默认为true,会对结果进行排序
--ascending :默认false,降序排序
--bins : integer,格式(bins=1),把它们数据分成半开放的集合,只适用于数字数据
--dropna :默认True,删除na值
--注意:输入及输出的都是series,因此对于dataframe数据,需要先提取series
titanic_train['Sex'].value_counts() # 统计series中不同类的数目
--②可使用unique(),去除series中的重复值,按照出现的顺序返回唯一
titanic_train['SibSp'].unique() # 统计series中不同值有哪些
--③可使用nunique(),去除series中的重复值,返回唯一值的个数(据参数设置,是否包含None值)
titanic_train['SibSp'].nunique() # 统计series中不同值的数目
--注意:以上方法都是对series统计
(2) 将文本变量Sex, Cabin ,Embarked用数值变量12345表示
--类别变量转化为数字,需分有序及无序,对于定类尺度数据(如男女),不能用有序(会对后续处理造成误导)
--replace():
--对原类别赋值,但不改变原数据,可利用赋值产生新的列表(由于顺序一致,因此表现相当于贴上数值标签)
titanic_train['Sex_num1'] = titanic_train['Sex'].replace(['male', 'female'],[1,2])
# 对类别赋值;注意str.replace(old, new[, max])并不会改变原有的数据
--map():
--map()属于字典映射型的类别编码,对字典中的key与value映射
titanic_train['Sex_num2'] = titanic_train['Sex'].map({'male':1, 'female':2})
# 利用字典映射类别和数值的对应关系
--注意:类别过多时,挨个标签效率低下,可采用枚举法将标签编码(由于特征无序,故采用整数与类别的对应关系无所谓,如男女可为【0,1】或【1,0】)
--scikit-learn库整数编码:
from sklearn.preprocessing import LabelEncoder # 导入库
# 获取一个LabelEncoder
imp_model = LabelEncoder()
# 运用训练集进行模型训练
Cabin_label = imp_model.fit_transform(titanic_train['Sex'])
# 追溯对应关系,并将原数据更改成数字编码
titanic_train['Sex'] = Cabin_label
--注意:encoder要求输入数据为统一的数据类型(字符串或数值),而在数据清洗过程中,对Cabin列进行了0值填充,因此出现多种类型,使用该模型会报错
(3) 将文本变量Sex, Cabin, Embarked用one-hot编码表示
--one-hot编码是将类别变量转化为机器学习算法中易于利用的一种形式的过程,即分辨非此即彼
--上述编码都是类别编码,会假定类别值越高,类别越好,在模型预测中会产生大量误差(当然可以提前对类别编码处理,避免此类情况)
--one-hot编码会创建虚拟特征,每一列各代表标称数据的一个值,但不适合于有序数据(其只输出二进制特征,无法分辨大小)
--方法:
①pd.get_dummies()转码(只对字符串列转换,数值列不变):
pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False)[source]
--data:输入的数据
--prefix:转换后,列名的前缀,默认为None
--columns:指定需要实现类别转换的列名,否则转换所有类别列
--dummy_na:默认False,增加一列表示空缺值,如果False就忽略空缺值
--drop_first:默认False,获得k中的k-1个类别值,去除第一个,防止出现多重共线性
for feat in ["Age", "Embarked"]:
# 对feat列转成onehot码并生成相应的x列
x = pd.get_dummies(titanic_train[feat], prefix=feat)
# 将生成的列与原数据合并在一起
titanic_train = pd.concat([titanic_train, x], axis=1)
# 以上两行可合并:titanic_train = pd.get_dummies(titanic_train, columns=['feat'])
②OneHotEncoder():(暂时还未找到对某列的编码方案,后期补充)
import pandas as pd
Movies = pd.DataFrame([
['爱情','内地',2,'是'],
['恐怖','欧美',4,'否'],
['动作','日本',3,'否'],
['搞笑','港台',5,'是']
],
columns=['类型','地区','评星','适宜儿童'])
Movies
# out
类型 地区 评星 适宜儿童
0 爱情 内地 2 是
1 恐怖 欧美 4 否
2 动作 日本 3 否
3 搞笑 港台 5 是
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
ohe.fit_transform(Movies.values).toarray()
# out
array([[0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0., 0., 0., 1.],
[0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 1., 0., 1., 0.],
[1., 0., 0., 0., 0., 1., 0., 0., 0., 1., 0., 0., 1., 0.],
[0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 1., 0., 1.]])
--注意:在最新版本的OneHotEncoder中,已将参数categorical_features弃用
4.3.2 任务三(附加):从纯文本Name特征里提取出Titles的特征(所谓的Titles就是Mr,Miss,Mrs等)
--参数:
Series.str.extract(pat, flags=0, expand=True)
--pat : str,具有捕获组的正则表达式模式。
--flags : int,默认为0(无标志)
--expand : 默认为True,返回DataFrame,每个捕获组一列。如果为False,如果有一个捕获组,则返回系列/索引;如果有多个捕获组,则返回DataFrame。
titanic_train['Title'] = titanic_train.Name.str.extract('([A-Za-z]+)\.', expand=False)
# out
0 Mr
1 Mrs
2 Miss
3 Mrs
4 Mr
...
886 Rev
887 Miss
888 Miss
889 Mr
890 Mr
Name: Title, Length: 889, dtype: object