Task02:数据清洗及特征处理

此任务主要是对数据进清洗,包括缺失值、重复值的处理;特征观察与处理:分箱、分类变量的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个间隔,每个间隔包含大致相同的数据样本个数,这种分箱方法有着比较好的可扩展性。将数据分箱后,可以用箱均值,箱中位数和箱边界来对数据进行平滑,平滑可以在一定程度上削弱离群点对数据的影响。
  • 具体方法: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()

你可能感兴趣的:(Task02:数据清洗及特征处理)