此任务主要是对数据进清洗,包括缺失值、重复值的处理;特征观察与处理:分箱、分类变量的one-hot编码处理。此外还涉及到了从Name中提取Titles的特征。
1缺失值观察与处理
1.1缺失值观察
检查缺失值:
df.isnull()
,返回与原数据行数相同的矩阵,矩阵元素为bool类型检查列/行是否有缺失值:
df.isnull().any()
,判断每列是否有缺失值,需要用any方法,axis=0默认表示列,axis=1表示判断每行是否有缺失值计算每个特征缺失值的个数:
df.isnull().sum(axis=0)
计算每个特征缺失值的比例:
df.isnull.sum(axis=0)/df.shape[0]
及缺失值数量/总样本量,shape方法返回数据集的行数和列数,shape[0]返回行数判断数据行中是否存在缺失值:
df.isnull().any(axis=1).any()
。两次使用any
综合判断所有数据行中是否包含缺失数据缺失观测的行数:
df.isnull().any(axis=1).sum()
1.2缺失值处理
-
缺失类型:
完全随机缺失MCAR:Missing completely at random。数据缺失完全随机,不依赖于任何完全变量或不完全变量。即某个变量是否缺失与它自身的值无关,也与其他变量的值无关。例如PM2.5缺失是由于仪器故障没有记录到数据。所以此时缺失是独立的,直接删除数据对建模影响不大,但一般缺失数量要小于数据总量的5%。
随机缺失MAR:missing at random,数据的缺失不是完全随机的,数据的缺失依赖于其他完全变量(即没有缺失值的)。即在控制了其他变量之后,某个变量的是否缺失与它自身的取值无关。例如,被调查者是否透露收入与年龄职业有关。
完全非随机缺失MNAR:missing not at random,数据的缺失依赖于不完全变量(即有缺失值的),与缺失值本身存在某种关联。即在控制了其他变量之后,某个变量是否缺失仍与它自身的取值有关。例如,在控制了年龄职业等因素之后,收入是否缺失还依赖于收入本身取值的高低。
非随机缺失数据会产生有偏估计,处理也比较困难。
-
缺失数据的处理思路
-
行删除:删除所有含有缺失数据的行。行删除法假定数据是完全随机缺失的,即完整的观测值只是全数据集的一个随机样本。
- 如果缺失比例比较小,改方法有效。但样本量较小时,可能不太适用。
- Python中:
df.dropna(how='any')
-
均值插补法:Mean imputation如果缺失数据是数值型的,则跟俊平均值来填充;如果缺失值是非数值型的,则根据众数来填充。
- 对该变量的均值不会产生影响。但是该方法时建立在完全随机缺失的假设上,当缺失比例较高时会嘀咕该变量的方差。同时,这种方法会产生有偏估计。
- python中:
df['列名'].fillna(df['列名'].mean())
;df['列名'].fillna(df['列名'].median)
多重插补法:Multiple imputation,它从一个包含缺失值的数据集中生成一组完整的数据集。每隔模拟的数据集中,缺失数据都用蒙特卡洛方法来填补。多重插补法不是用单一值来替换缺失值,而是试图产生缺失值的一个随机样本,反映出由于数据缺失而导致的不稳定性。
热卡填补,K最近距离邻法,拟合缺失值等方法。具体可查看缺失值
-
-
处理缺失值的常用方法:
df.dropna()
和df.fillna()
-
df.dropna(self,axis=0,how='any',thresh=None,subset=None,inplace=False)
- 默认:删除含有NA的行,axis=0表示删除行,how='any'表示有一个NA就删除整行/列
- axis:默认为0,删除行,=1或'columns'删除列
- how:=any默认有一个NA就删除整行/整列,=all表示当所有行/列都是NA时才删除
- thresh:阈值,既NA的数量大于这个阈值时才删除
- subset:设置判断的子集,即待判断的行/列名,这些行/列中有NA值则所在行或列删除
- inplace:=true处理后的df替代原df,=false生成一个新的df,原来的也还存在
-
df.fillna(self,value=None,method=None,axis=None,inplace=False,limit=None,downcast=None,**kwargs)
- 默认,传入参数,填充所有NA,如df.fillna(0)用0填重所有NA
- value:每列NA的填充值,为字典格式,如value={'列名':填充值,...}
- method:=‘pad/ffill’表示用前一个非缺失值取填充该缺失值,=‘backfill/bfill’表示用下一个非缺失值填充该缺失值,=‘None’指定一个值取替换缺失值
- limit:限制填充个数,=1表示每行/列仅填充一个NA
- inplace和dropna一样
-
-
检索空缺值用
np.nan
,None
以及.isnull()
哪个更好,这是为什么?如果其中某个方式无法找到缺失值,原因又是为什么?- is.null最好,能够识别所有类型的,包括数值和字符型。
- None:==None最不好,连NaN都判断不了,无法找到缺失值。原因在于None是Python自带的,类型为NoneType。
- np.nan:只能判断由Numpy模块生成的nan值,不能判断字符串类型。
2重复值观察与处理
2.1重复值观察
df.duplicated(self,subset=None,keep='first')
-
subset
:用于识别重复的列表前或行标签序列,默认所有列标签 -
keet
:first,除了第一次出现外,其余相同的被标记为重复;last除了最后一次出现外,其余相同的被标记为重复;False所有相同的都被标记为重复
2.2处理重复值
- 删除重复值:
df.drop_duplicates(self,subset=None,keep='first',inplace=False)
- inplace表示是否覆盖原来的df,默认不覆盖生成新的df,其他参数与df.duplicated一样。
3特征观察与处理
特征:数值型特征,文本型特征。数值型特征一般可直接用于模型的训练,有时为了模型的稳定性及鲁棒性会对连续变量进行离散化。文本型特征往往需要转换成数值型特征才能用于建模分析。
3.1分箱(离散化处理)
即第一种:数值型特征离散化处理。
-
分箱时一种将数据排序并分组的方法,分为等宽分箱和等频分享。
- 等宽分箱是用同等大小的各自来将数据范围分成N个间隔,箱宽为
.等宽分享比较直观和容易操作,但是对于偏态分布的数据,等宽分箱并不是太好,因为可能出现箱中没有样本点的情况。
- 等频分箱是将数据分成N个间隔,每个间隔包含大致相同的数据样本个数,这种分箱方法有着比较好的可扩展性。将数据分箱后,可以用箱均值,箱中位数和箱边界来对数据进行平滑,平滑可以在一定程度上削弱离群点对数据的影响。
- 等宽分箱是用同等大小的各自来将数据范围分成N个间隔,箱宽为
- 具体方法:
pd.cut(x,bins,right=True,labels=None,retbins=False,precision=3,include_lowest=False,duplicate='raise')
- x:一维数组
- bins:整数,标量序列或者间隔索引,是进行分组的依据
- 整数n,则表示将数值分为等宽的n份
- 标量序列,序列中的数值表示用来分档的分界值
- 间隔索引:bins的间隔索引必须不重叠
- right:布尔值,默认为true表示包含最右侧的数值,如bins=[1,2,3,4]表示(1,2],(2,3],(3,4].当bins为间隔索引,则该参数被忽略
- labels:数值或布尔值,可选指定分箱的标签
- retbins:是否显示分箱的分界值。默认false,当bins取整数时可以设置=true以显示分界值
- precision:整数,默认3,存储和显示分箱标签的精度
- include_lowest:布尔值,表示区间的左边是开还是闭,默认是false,即不包含区间左边
- duplicates:如果分箱临界值不唯一,则引发ValueError或丢弃非唯一
3.2文本特征处理
-
查看类别文本变量名及种类:
df['列名'].value_counts()
df['列名'].unique()
-
将类别文本转换为数字,如12345
-
df['列名'].replace(['类别1名字','类别2名字',...],[1,2,....])
,数字自定义 -
df.['列名'].map({'类别1':1,'类别2':2,...})
,数字自定义 - 使用LabelEncoder
-
One-hot编码
3.3从文本Name中提取出Titles的特征
df['Name'].str.extract('([A-Za-z]+)\.', expand=False)
4datawhale例子
# 检查缺失值
train.isnull() # 返回与原数据行列数相同的矩阵,矩阵元素为bool类型的值,true为缺失
# 检查是否有缺失值,检查行列是否有缺失需要用any方法,且axis=0表示列,axis=1表示行
train.isnull().any() # 判断每列是否有缺失值,返回false没有缺失值,返回true有缺失值
train.isnull().any(axis=1) # 判断每行是否有缺失值,返回false没有缺失值,返回true有缺失值
# 计算每个特征缺失值个数
print(train.isnull().sum(axis=0))
# 计算每个特征缺失值的比例
train.isnull().sum(axis=0)/train.shape[0]
# 即缺失值数量/总样本量,shape方法返回数据集的行数和列数,[0]表示去除对应的数据行数
#两次使用any()方法
# 判断数据行中是否存在缺失值
train.isnull().any(axis=1).any()
# train.isnull()返回矩阵,每个元素是否缺失
# train.isnull().any(axis=1),判断每行是否有缺失元素
# train.isnull().any(axis=1).any()综合判断所有数据行中是否包含缺失值
# 缺失观测的行数
train.isnull().any(axis=1).sum() # 计算有缺失的行数的总数目
# 缺失观测的比例
train.isnull().any(axis=1).sum()/train.shape[0] # 有缺失数据的行数所占的比例
#尝试对age列的缺失值进行处理
# age列缺失值有177个,所以尝试用均值进行处理
train['Age'].fillna(train['Age'].mean()).head(10)
#尝试用不同的方法对整表的缺失值进行处理
# 直接删除缺失值
df.dropna().head(10)
# 用0来填补
df.fillna(0).head(10)
#查看重复值
train[train.duplicated()]
# 删除重复值
train = train.drop_duplicates()
train.head(10)
# 保存数据
train.to_csv('test_clear.csv')
#将连续变量Age平均分箱成5个年龄段,并分别用类别变量12345表示
train['AgeBand'] = pd.cut(train['Age'], 5,labels = [1,2,3,4,5])
train.head(10)
train.to_csv('test1.csv') # 保存数据
#将连续变量Age划分为(0,5] (5,15] (15,30] (30,50] (50,80]五个年龄段,并分别用类别变量12345表示
train['AgeBand'] = pd.cut(train['Age'],[0,5,15,30,50,80],labels = [1,2,3,4,5])
train.head(10)
train.to_csv('test2.csv')
#将连续变量Age按10% 30% 50 70% 90%五个年龄段,并用分类变量12345表示
train['AgeBand'] = pd.qcut(train['Age'],[0,0.1,0.3,0.5,0.7,0.9],labels = [1,2,3,4,5])
train.head(10)
train.to_csv('test3.csv')
# 查看类别文本变量名及种类
train['Sex'].value_counts()
train['Cabin'].uique()
train['Embarked'].unique()
# 类别文本转换成12345数字
train['Sex_num'] = train['Sex'].replace(['male','female'],[1,2])
# 使用LabelEncoder
from sklearn.preprocessing import LabelEncoder
for feat in ['Cabin', 'Ticket']:
lbl = LabelEncoder()
label_dict = dict(zip(train[feat].unique(), range(train[feat].nunique())))
train[feat + "_labelEncode"] = train[feat].map(label_dict)
train[feat + "_labelEncode"] = lbl.fit_transform(train[feat].astype(str))
train['Title'] = train.Name.str.extract('([A-Za-z]+)\.', expand=False)
train.head()