Pandas简介
Pandas是Python中最有用的数据分析库之一,它提供了大量使我们能够快速便捷地处理结构化数据的数据结构和函数。Pandas兼具NumPy高性能的数据计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因素之一。
在本篇中,我们将使用Pandas读取来自Analytics Vidhya竞赛的数据集,并对它进行探索分析,包括建立基本的分类算法和进行数据清洗。
在读入数据之前,让我们先来了解一下Pandas中的2个关键数据结构——Series和DataFrames
Series和DataFrames简介
Seriess是一个一维数组对象,与Numpy中的一维array类似。二者与Python的基本数据结构List也很相近。Series除了包含一组数据外,还包含一组索引,因此我们可以把它理解为是一个带索引的数组。Series如今能保存不同种数据类型,如字符串、boolean值、数字等。
DataFrame是一个二维的表格型数据结构,提供有序的列和不同类型的列值,具有指向行和列的行名称和列名称,可以使用行或列索引对它进行访问。我们可以将DataFrame理解为Series的容器。
Series和DataFrames构成了Python中Pandas的核心数据模型。我们需要先将数据集读入DataFrames,然后就可以非常轻松地将各种操作(例如分组,聚合等)应用于其列了。
数据集介绍
本次我们使用的是Analytics Vidhya竞赛贷款预测问题中的数据集,其变量描述如下:
下面让我们开始对该数据集进行探索分析吧~
导入库和数据集
在进行我们的分析前,需要先导入用到的库并读取数据集,以下是我们在本次分析中将使用的库:
numpy
matplotlib
pandas
导入库之后,使用read_csv()函数读取数据集:
import pandas as pd
import numpy as np
import matplotlib as plt
%matplotlib inline
#Reading the dataset in a dataframe using Pandas
df = pd.read_csv("train.csv")
快速数据探索
读取数据集后,我们可以使用head(n)函数查看数据集的前n行:
df.head(10)
我们还可以使用describe()函数查看数据集的基本情况:
df.describe()
describe()函数在输出中提供了如下统计值变量:
count:统计该列有效值个数
unipue:统计不同值个数
std:标准差
min:最小值
25%:四分之一分位数
50%:二分之一分位数
75%:四分之三分位数
max:最大值
mean:均值
通过查看本数据集describe()函数的输出可以得出如下结论:
LoanAmount列有(614–592=)22个缺失值
Loan_Amount_Term列有(614–600=)14个缺失值
Credit_History列有(614–564=)50个缺失值
大约84%的申请人有credit_history。本结论可由Credit_History字段的平均值为0.84得出(对于拥有信用记录的用户,规定Credit_History的值为1,否则为0)
ApplicantIncome和CoapplicantIncome的分布似乎都符合预期
(需要注意的是,我们可以通过比较平均值与中位数来了解数据中可能存在的偏斜)
对于非数字值(例如Property_Area,Credit_History字段),我们可以查看频率分布来判断它们是否有意义。可以使用以下命令打印频率表:
df['Property_Area'].value_counts()
其中,dfname['column_name']是访问dataframe中特定列的基本索引方法
数值变量分布分析
现在我们已经熟悉了本数据集的基本数据特征,接下来让我们从数值型变量开始,进行变量的分布分析研究吧~
(在此我们使用ApplicantIncome和LoanAmount两个变量)
首先,我们可以使用如下代码绘制基于ApplicantIncome变量的直方图:
df['ApplicantIncome'].hist(bins=50)
我们可以观察到上图中的极值很少。这也是为什么在代码中bins要设置为50才能清楚地描述该数据分布的原因。
接下来,我们可以使用如下命令绘制箱线图,从而了解申请人收入数据的分布情况:
df.boxplot(column='ApplicantIncome')
上图表明ApplicantIncome字段中存在许多异常值或极值。这可以归因于社会上存在的收入差距,部分原因可能是我们的数据样本有不同学历背景。下面让我们对学历进行划分:
df.boxplot(column='ApplicantIncome', by = 'Education', figsize=(8, 6))
从上图中我们可以看出,研究生和本科生的平均收入没有实质性差异。但是,观察两列数据中的极值点可以发现,与本科生相比,有更多的研究生有非常高的收入。
同样的,让我们来看看LoanAmount字段的直方图和箱线图:
df['LoanAmount'].hist(bins=50)
df.boxplot(column='LoanAmount')
可以看到该字段中也有一些极值。显然,ApplicantIncome和LoanAmount字段都需要进行一定的数据整理。LoanAmount字段有缺失值和极值,而ApplicantIncome字段则有几个极值,这需要进行更深入的分析处理,我们将在后面的内容中讨论这个问题。
分类变量分析
到这里,我们已经了解了ApplicantIncome和LoanIncome这两个变量的数据分布情况,接下来让我们对分类变量进行研究分析。
我们先使用Excel中的数据透视表和交叉表。例如,要根据申请者的信用历史记录查看他能获得贷款的概率,我们可以在Excel中使用数据透视表如下实现:
(注意:此处的贷款状态已规定为1(是)和0(否),因此平均值表示获得贷款的概率)
下面,我们来看看如何使用Python来实现类似效果(向左滑动查看全部代码):
temp1 = df['Credit_History'].value_counts(ascending=True)
temp2 = df.pivot_table(values='Loan_Status',index=['Credit_History'],aggfunc=lambda x: x.map({'Y':1,'N':0}).mean())
print ('Frequency Table for Credit History:')
print (temp1)
print ('\nProbility of getting loan for each Credit History class:')
print (temp2)
可以看到,通过上述代码我们得到了与Excel类似的枢轴表。接下来我们使用matplotlib库通过以下代码将其绘制为条形图:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,4))
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)
temp1.plot(ax = ax1,kind='bar')
temp2.plot(ax = ax2,kind='bar',legend='')
ax1.set_xlabel('Credit_History')
ax1.set_ylabel('Count of Applicants')
ax1.set_title("Applicants by Credit_History")
ax2.set_xlabel('Credit_History')
ax2.set_ylabel('Probability of getting loan')
ax2.set_title("Probability of getting loan by credit history")
从上图中我们可以看出,如果贷款申请人具有良好的信用记录,其获得贷款的机会会提升8倍。同样,我们还可以根据申请人是否已婚、是否自雇人士、所在地区等来绘制类似的图。此外,我们也可以把这两个图组合成一个堆叠图来展现相同的数据效果:
temp3 = pd.crosstab(df['Credit_History'], df['Loan_Status'])
temp3.plot(kind='bar', stacked=True, color=['red','blue'], grid=False)
我们还可以将性别属性添加到图中(与Excel中的数据透视表类似):
在上面,我们使用了两种基本分类算法,一种是使用1个变量(信用记录)进行分类,另一种是使用2个变量(信用记录和性别)。在这里我们仅提供了一个参考,你也可以用这两种方法对已有的数据进行不同维度的探索分析。
数据清洗初步探索
在进行数据分析处理前,有一个必不可少的环节——数据清洗,其结果质量直接关系到我们的模型效果和最终结论。在实际操作中,数据清洗通常会占据分析过程的50%—80%的时间。我们接下来就对这个问题进行讨论
我们在上面的数据探索过程中提到,本数据集中的LoanAmount和ApplicantIncome字段存在一些问题:
一些变量中存在缺失值。我们应该根据缺失值的数量和变量的预期重要性来合理地对这些缺失值进行估计
在查看分布时,我们看到ApplicantIncome和LoanAmount似乎在两端都包含极值。尽管我们第一直觉并未察觉到异常,但还是应该进行合理的处理
除了数值字段的这些问题外,我们还应该关注非数值字段,例如性别、财产所在区域、是否已婚,学历和家属数量等,查看它们是否包含一些有用的信息。
检查数据集中的缺失值
大多数模型都无法对缺失值进行处理,即使有时候缺失值确实有其存在的意义。因此,让我们先来看看本数据集中的各变量是否存在缺失值。此外,填补这些数据对我们要进行的分析处理也会很有意义。
我们可以使用以下代码查看本数据集中的空值和NaN值(注意,缺失值不一定总是NaN):
df.apply(lambda x: sum(x.isnull()),axis = 0)
如果值为null,则isnull()返回1。运行该行代码,我们可以得到每个字段中缺失值的个数。
从结果中我们可以看到,尽管缺失值的数量不是很多,但是变量的数目却很多,因此对每个变量的缺失值进行估计和填补很重要。
如何填补缺失值?
在此,我们以LoanAmount字段为例。有很多方法可以填补缺失值,其中最简单的方法是计算出该字段的均值后进行替换,我们可以通过以下代码完成:
df['LoanAmount'].fillna(df['LoanAmount'].mean(),inplace =True)
最复杂的方法是建立一个监督学习模型,基于其他变量来预测该字段的缺失值。
由于我们现在的目的是完成数据整理的步骤,所以我们在此采用介于这两种方法中的第三种方法。我们有一个关键是假设是,可以根据一个人是否受过教育和是否是自雇职业,来对他的贷款金额进行较为准确的估计。
首先,我们来看一下箱线图中是否存在趋势:
我们可以看到每组贷款金额的中位数有些变化,这可以用来估算该值。但首先,我们必须确保Self_Employed和Education这两个变量都不应该有缺失值。
按照之前提到的方法,我们可以通过以下代码打印出频率表来查看Self_Employed含有的缺失值:
df['Self_Employed'].value_counts()
由于有大约86%的值为“No”,因此根据它来估算缺失值是可行的。可以使用以下代码完成此操作:
df['Self_Employed'].fillna('No',inplace=True)
现在,我们来创建一个数据透视表,该表为我们提供Self_Employed和Education的所有唯一值组的中值。然后我们定义一个函数,返回单元格值并用其填补贷款金额的缺失值:
这是一个估算缺失值的好方法,但需注意的是,只有在没有使用均值填充缺失值时,此方法才有效
如何处理极值?
我们来分析一下LoanAmount字段。极值是很可能出现的,比如有些人会由于特殊需要而申请高额贷款。因此,与其将它们视为异常值,不如尝试通过对数转换来消除其影响:
df['LoanAmount_log'] = np.log(df['LoanAmount'])
df['LoanAmount_log'].hist(bins=20)
我们再来看一下直方图:
现在该变量的分布看起来更接近正态分布,极值的影响已经显著减弱。
再来看ApplicantIncome字段。我们知道,尽管有些申请人收入较低,但他会有共同申请人的支持。因此,我们可以将这两类收入合并为总收入,并对其进行对数变换。
df['TotalIncome'] = df['ApplicantIncome'] + df['CoapplicantIncome']
df['TotalIncome_log'] = np.log(df['TotalIncome'])
df['LoanAmount_log'].hist(bins=20)
现在我们可以看到直方图的分布比以前好多了。我们还可以用同样的方法对Gender/Married/Dependents/ Credit_History等字段进行缺失值处理。除此之外,我们还可以通过组合各个变量得到更多需要的信息,比如,我们可以通过LoanAmount /TotalIncome创建一个字段,用于估算申请人的还款能力。
在本文中,我们使用Pandas建立了基本的分类算法,并进行了初步清洗。Pandas是一个功能强大的开源Python库,主要用于数据分析处理和可视化。自2014年以来,它已经越来越受欢迎,并成为Python数据科学工具包中“必须使用”的工具。相信随着更深入的使用,你会发现Pandas在数据分析处理领域的强大之处。

