在数据分析的旅途中,经常会遇到各种挑战,比如数据缺失、异常值处理等。本文将带了解如何使用Python和Pandas库来解决这些问题,让能够独立探索世界,发现新知。如果一直在关注这个系列,那么这篇文章将为提供一双跑鞋,帮助开始奔跑。
通过本教程的学习,将掌握使用Python进行数据分析的所有必要工具。将回顾基础知识,包括Python的安装设置、有用的库和数据结构,以及如何使用Pandas进行探索性分析。
在之前的系列文章中,已经下载并设置了Python环境,介绍了几个有用的库和数据结构,并开始了使用Pandas的探索性分析。如果还没有阅读之前的文章,请先阅读,然后再继续。
在数据探索过程中,发现了一些需要解决的问题,这些问题在数据准备好进行模型构建之前需要被解决。这个过程通常被称为“数据清洗”。以下是已经知道的问题:
在年龄字段中,大约31%(891中的277)的值缺失。预计年龄将扮演重要角色,因此希望能够以某种方式估计这个值。
在查看分布时,发现票价似乎包含了极端值——一些票可能是免费提供的,或者包含了数据输入错误。另一方面,512美元听起来像是一个非常高的票价。
除了这些数值字段的问题,还应该查看非数值字段,即姓名、票号和舱位,看看它们是否包含任何有用信息。
让从舱位开始。第一眼看这个变量,印象是数据集中有太多的NaN值。因此,让检查数据集中的空值/NaN值的数量。
sum(df['Cabin'].isnull())
这个Pandas命令应该告诉缺失值的数量,因为isnull()如果值为null则返回1。输出是687——这是一个很多的缺失值。因此,需要删除这个变量。
接下来,让看看票号变量。票号看起来混合了数字和文本,似乎不包含任何信息,所以也将删除票号。
df = df.drop(['Ticket','Cabin'], axis=1)
填充年龄的缺失值有多种方法——最简单的是用平均值替换,可以通过以下代码完成:
meanAge = np.mean(df.Age)
df.Age = df.Age.fillna(meanAge)
另一个极端是构建一个监督学习模型,根据其他变量预测年龄,然后使用年龄和其他变量预测生存。
由于本教程的目的是展示数据清洗的步骤,将采取一个介于这两个极端之间的方法。关键假设是姓名、性别和舱位等级中的称呼可以提供所需的信息,以在很大程度上填补缺失值。
让定义一个函数,该函数从以这种格式书写的姓名中提取称呼:Family_Name, Salutation. First Name。
def name_extract(word):
return word.split(',')[1].split('.')[0].strip()
接下来,使用apply()函数将这个函数应用到整个列,并把结果转换为一个新的Pandas DataFrame df2:
df2 = pd.DataFrame({'Salutation':df['Name'].apply(name_extract)})
一旦有了称呼,让看看它们的分布。在合并DataFrame df2和DataFrame df后使用groupby:
df = pd.merge(df, df2, left_index = True, right_index = True) # merges on index
temp1 = df.groupby('Salutation').PassengerId.count()
print temp1
以下是输出结果:
称呼
Capt 1
Col 2
Don 1
Dr 7
Jonkheer 1
Lady 1
Major 2
Master 40
Miss 182
Mlle 2
Mme 1
Mr 517
Mrs 125
Ms 1
Rev 6
Sir 1
the Countess 1
dtype: int64
如所见,有4个主要的称呼——Mr, Mrs, Miss和Master——其他的数量较少。因此,将把所有剩余的称呼合并为一个称呼——Others。为了做到这一点,采取与提取称呼相同的方法——定义一个函数,将其应用到一个新列,将结果存储在一个新的Pandas DataFrame中,然后将其与旧的DataFrame合并:
def group_salutation(old_salutation):
if old_salutation == 'Mr':
return('Mr')
else:
if old_salutation == 'Mrs':
return('Mrs')
else:
if old_salutation == 'Master':
return('Master')
else:
if old_salutation == 'Miss':
return('Miss')
else:
return('Others')
df3 = pd.DataFrame({'New_Salutation':df['Salutation'].apply(group_salutation)})
df = pd.merge(df, df3, left_index = True, right_index = True)
temp1 = df3.groupby('New_Salutation').count()
temp1
df.boxplot(column='Age', by = 'New_Salutation')
以下是新称呼的分布和年龄变化的结果:
同样地,通过性别和舱位等级绘制年龄分布图显示了一个斜率:
因此,创建一个透视表,它提供了上述所有单元格的中位数值。接下来,定义一个函数,该函数返回这些单元格的值,并将其应用于填补年龄的缺失值:
table = df.pivot_table(values='Age', index=['New_Salutation'], columns=['Pclass', 'Sex'], aggfunc=np.median)
# 定义函数返回此透视表的值
def fage(x):
return table[x['Pclass']][x['Sex']][
x['New_Salutation']]
# 替换缺失值
df['Age'].fillna(df[df['Age'].
isnull()].apply(fage, axis=1), inplace=True)
这应该为提供了一个填补年龄缺失值的好方法。
接下来,让看看按舱位等级划分的票价分布:
正如预期的那样,票价的均值整齐地按照舱位等级排列。然而,有一些极端值。一个特别引人注目的数据点,一级舱位的票价512,这看起来像是一个可能的错误。同样,有多种方法可以填补这个数据——用一级舱位的均值/中位数替换,或者也可以用第二高的值替换,这个值更接近其他数据点。