用到的数据集:
train 链接: https://pan.baidu.com/s/1hCQKvLYxTb5MkltJDa1QlQ 提取码: jsh8
test 链接: https://pan.baidu.com/s/16SkJ7fo1yEutv4CwnWPEnA 提取码: yry1
由于元组是不可变的并且不能更改,因此与列表相比,它们的处理速度更快。因此,如果您的列表不太可能更改,则应使用元组而不是列表。
import pandas as pd
import numpy as np
import matplotlib as plt
#读入贷款预测数据集
df=pd.read_csv(r'C:\Users\lele\Desktop\train-贷款预测.csv',engine='python')
快速数据探索
读取数据集后,您可以使用head()函数查看顶部几行。
接下来,您可以使用describe()函数查看数字字段的摘要:
describe()函数将在其输出中提供计数,均值,标准差(std),最小值,四分位数和最大值.
这里有一些推断,您可以通过查看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分布似乎符合预期。与申请人相同
请注意,通过将平均值与中位数(即50%的数字)进行比较,我们可以了解数据中可能存在的偏斜。
对于非数字值(例如Property_Area,Credit_History等),我们可以查看频率分布以了解它们是否有意义。可以通过以下命令打印频率表:
df['Property_Area'].value_counts()
Similarly, we can look at unique values of port of credit history. Note that dfname[‘column_name’] is a basic indexing technique to access a particular column of the dataframe. It can be a list of columns as well.
#---分布分析
既然我们已经熟悉了基本数据特征,那么让我们研究各种变量的分布。
让我们从数字变量开始-即ApplicantIncome和LoanAmount
首先使用以下命令绘制ApplicantIncome的直方图:
df['ApplicantIncome'].hist(bins=50)
#Here we observe that there are few extreme values.
#This is also the reason why 50 bins are required to depict the distribution clearly.
'''
Next, we look at box plots to understand the distributions. Box plot for fare can be plotted by:
'''
df.boxplot(column='ApplicantIncome')
'''
这确认了许多异常值/极端值的存在。这可以归因于社会上的收入差距。
部分原因可能是由于我们正在寻找具有不同教育水平的人。让我们按教育来区分它们:
'''
df.boxplot(column ='ApplicantIncome',by='Education')
'''
我们可以看到,毕业生和非毕业生的平均收入之间没有实质性差异。
但是,收入较高的毕业生人数较多,这似乎与众不同。
现在,让我们使用以下命令查看LoanAmount的直方图和箱线图:
'''
df['LoanAmount'].hist(bins=50)
df.boxplot(column='LoanAmount')
'''
同样,还有一些极限值。显然,ApplicantIncome和LoanAmount都需要一定数量的数据处理。
LoanAmount具有缺失值和极值,而ApplicantIncome具有一些极值,这需要更深入的了解。
我们将在接下来的部分中进行介绍。
'''
'''
分类变量分析:
现在,我们了解了ApplicantIncome和LoanIncome的分布,让我们更详细地了解分类变量。
我们将使用Excel样式数据透视表和交叉表。例如,让我们根据信用历史记录来查看获得贷款的机会。
'''
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:\n',temp1)
print ('\nProbility of getting loan for each Credit History class:\n',temp2)
'''
可以使用“ matplotlib”库通过以下代码将其绘制为条形图:
'''
import matplotlib.pyplot as plt
plt.figure(figsize=(8,6),dpi=100)
plt.subplot(121)
plt.bar(range(len(temp1.index)),temp1.values,color='r')
plt.xticks(ticks=range(len(temp1.index)),labels=temp1.index)
plt.xlabel('Credit_History')
plt.title('Applicants by Credit_History')
plt.subplot(122)
plt.bar(range(len(temp2.index)),temp2['Loan_Status'],color='b')
plt.xticks(ticks=range(len(temp2.index)),labels=temp2.index)
plt.xlabel('Credit_History')
plt.title('Probability of getting loan by credit history')
plt.show()
'''
这表明,如果申请人具有有效的信用记录,则获得贷款的机会是八倍。
您可以按已婚,自雇,Property_Area等绘制类似的图。
或者,也可以通过将它们组合成堆叠图表来可视化这两个图:
'''
temp3 = pd.crosstab(df['Credit_History'], df['Loan_Status'])
temp3.plot(kind='bar', stacked=True, color=['red','blue'], grid=False)
您还可以将性别添加到混合中(类似于Excel中的数据透视表):
temp4 = pd.crosstab([loan_df['Credit_History'],loan_df['Gender']], loan_df['Loan_Status'])
temp4.plot(kind='bar',stacked=True,color=['red','blue'])
If you have not realized already, we have just created two basic classification algorithms here,
one based on credit history, while other on 2 categorical variables (including gender).
You can quickly code this to create your first submission on AV Datahacks.
We just saw how we can do exploratory analysis in Python using Pandas.
I hope your love for pandas (the animal) would have increased by now – given the amount of help,
the library can provide you in analyzing datasets.
Next let’s explore ApplicantIncome and LoanStatus variables further,
perform data munging and create a dataset for applying various modeling techniques.
I would strongly urge that you take another dataset and problem and go through an independent example before reading further.
4.用Python处理数据:使用Pandas
对于那些一直在追随的人,这是您必须穿上鞋子才能开始跑步的地方。
数据处理-需求概述:
在探索数据的过程中,我们发现了数据集中的一些问题,需要先解决这些问题,然后才能为好的模型准备好数据。
此练习通常称为“数据整理”。这是我们已经意识到的问题:
一些变量中缺少值。我们应该根据缺失值的数量和变量的预期重要性来明智地估计这些值。
在查看分布时,我们看到ApplicantIncome和LoanAmount似乎在任一端都包含极值。
尽管它们可能具有直觉上的意义,但应适当对待。
除了数字字段的这些问题外,我们还应该查看非数字字段,例如性别,财产领域,已婚,教育和受抚养人,
以查看它们是否包含有用的信息。
检查数据集中的缺失值:
让我们看一看所有变量中的缺失值,因为大多数模型都无法处理缺失数据,即使它们确实存在,
对它们进行估算也往往会有所帮助。因此,让我们检查数据集中的空值/ NaN个数。
df.apply(lambda x: sum(x.isnull()),axis=0)
该命令应该告诉我们每列中缺少值的数量,因为isull()返回1(如果该值为null)。
尽管缺失值的数量不是很高,但是有很多变量,因此应该对每个变量进行估计并将其添加到数据中。
注意:请记住,缺失值不一定总是NaN。例如,如果Loan_Amount_Term为0,这有意义吗?还是您会认为缺失?
我想您的答案不见了,您说得对。因此,我们应该检查不可行的值。
如何填写LoanAmount中的缺失值?
有很多方法可以填补贷款金额的缺失值-最简单的方法是用均值替换,可以通过以下代码完成:
df['LoanAmount'].fillna(df['LoanAmount'].mean(), inplace=True)
另一个极端可能是建立一个监督学习模型,以基于其他变量来预测贷款额,然后将年龄和其他变量一起用于预测生存期。
因为,现在的目的是找出数据处理的步骤,所以我宁愿采用一种方法,该方法介于这两个极端之间。一个关键的假设是,一个人是受过教育还是自谋职业,可以结合起来对贷款金额进行很好的估计。
首先,让我们看一下箱线图,看是否存在趋势:
loan_df.boxplot(column=['LoanAmount'],by=['Education','Self_Employed'],figsize=(10,8))
因此,我们看到每个组的贷款金额中位数都有一些变化,可以用来估算这些值。但是首先,我们必须确保“个体经营”和“教育”变量中的每个值都不应缺少。
正如我们之前所说,Self_Employed具有一些缺失的值。让我们看一下频率表:
由于〜86%的值为“否”,因此将丢失的值归为“否”是安全的,因为成功的可能性很高。可以使用以下代码完成此操作:
df['Self_Employed'].fillna('No',inplace=True)
现在,我们将创建数据透视表,该表为我们提供了自雇和教育功能的所有唯一值组的中值。
接下来,我们定义一个函数,该函数返回这些单元格的值并将其应用于填充贷款金额的缺失值:
table = df.pivot_table(values='LoanAmount', index='Self_Employed' ,columns='Education', aggfunc=np.median)
# Define function to return value of this pivot_table
def fage(x):
return table.loc[x['Self_Employed'],x['Education']]
# Replace missing values
df['LoanAmount'].fillna(df[df['LoanAmount'].isnull()].apply(fage, axis=1), inplace=True)
这应该为您提供一种估算贷款金额缺失值的好方法。
注意:仅当您没有使用以前的方法(即使用均值)填充Loan_Amount变量中的缺失值时,此方法才有效。
如何处理LoanAmount和ApplicantIncome分配中的极值?
让我们首先分析LoanAmount。由于极高的价值实际上是可能的,即有些人可能会因特殊需要而申请高价值贷款。
因此,让我们尝试对数转换以消除其影响,而不是将它们视为离群值:
df['LoanAmount_log'] = np.log(df['LoanAmount'])
df['LoanAmount_log'].hist(bins=20)
再次查看直方图:
现在,分布看起来更接近于正态分布,极值的影响已大大减弱。
即将来临的申请人收入。一种直觉可能是某些申请人的收入较低,但支持共同申请人。
因此,将两个收入合并为总收入并对其进行对数转换可能是一个好主意。
df['TotalIncome'] = df['ApplicantIncome'] + df['CoapplicantIncome']
df['TotalIncome_log'] = np.log(df['TotalIncome'])
df['LoanAmount_log'].hist(bins=20)
现在我们看到分布比以前好得多。我将由您自己来填写性别,已婚,受抚养人,贷款额度,信贷历史记录的缺失值。
另外,我建议您考虑可以从数据中得出的其他信息。例如,为LoanAmount / TotalIncome创建一个列可能很有意义,因为它可以使申请人了解贷款的还款能力。
接下来,我们将研究制作预测模型。
5.用Python构建预测模型
之后,我们使数据对建模有用,现在让我们看一下在我们的数据集上创建预测模型的python代码。
Skicit-Learn(sklearn)是为此目的在Python中最常用的库,我们将继续学习。
由于sklearn要求所有输入均为数字,因此我们应通过编码类别将所有分类变量转换为数字。
在此之前,我们将填充数据集中的所有缺失值。
可以使用以下代码完成此操作:
df['Gender'].fillna(df['Gender'].mode()[0], inplace=True)
df['Married'].fillna(df['Married'].mode()[0], inplace=True)
df['Dependents'].fillna(df['Dependents'].mode()[0], inplace=True)
df['Loan_Amount_Term'].fillna(df['Loan_Amount_Term'].mode()[0], inplace=True)
df['Credit_History'].fillna(df['Credit_History'].mode()[0], inplace=True)
from sklearn.preprocessing import LabelEncoder
var_mod = ['Gender','Married','Dependents','Education','Self_Employed','Property_Area','Loan_Status']
le = LabelEncoder()
for i in var_mod:
df[i] = le.fit_transform(df[i])
接下来,我们将导入所需的模块。然后,我们将定义一个通用分类函数,该函数将模型作为输入并确定准确性和交叉验证分数。
由于这是一篇介绍性文章,因此我不会详细介绍编码。
#Import models from scikit learn module:
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import KFold #For K-fold cross validation
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn import metrics
#Generic function for making a classification model and accessing performance:
def classification_model(model, data, predictors, outcome):
#Fit the model:
model.fit(data[predictors],data[outcome])
#Make predictions on training set:
predictions = model.predict(data[predictors])
#Print accuracy
accuracy = metrics.accuracy_score(predictions,data[outcome])
print ("Accuracy : %s" % "{0:.3%}".format(accuracy))
#Perform k-fold cross-validation with 5 folds
kf = KFold(data.shape[0], n_folds=5)
error = []
for train, test in kf:
# Filter training data
train_predictors = (data[predictors].iloc[train,:])
# The target we're using to train the algorithm.
train_target = data[outcome].iloc[train]
# Training the algorithm using the predictors and target.
model.fit(train_predictors, train_target)
#Record error from each cross-validation run
error.append(model.score(data[predictors].iloc[test,:], data[outcome].iloc[test]))
print ("Cross-Validation Score : %s" % "{0:.3%}".format(np.mean(error)))
#Fit the model again so that it can be refered outside the function:
model.fit(data[predictors],data[outcome])
逻辑回归:
让我们建立第一个Logistic回归模型。一种方法是将所有变量都放入模型中,
但这可能会导致过拟合(如果您还不知道此术语,请不要担心)。
简而言之,采用所有变量可能会使模型理解特定于数据的复杂关系,并且不能很好地概括。
我们可以很容易地做出一些直观的假设来使球滚动。在以下情况下获得贷款的机会会更高:
拥有信用记录的申请人(还记得我们在探索中观察到的吗?)
申请人和共同申请人收入较高的申请人
受过高等教育的申请者
具有高增长前景的市区物业
因此,让我们使用“ Credit_History”创建第一个模型。
outcome_var = 'Loan_Status'
model = LogisticRegression()
predictor_var = ['Credit_History']
classification_model(model, df,predictor_var,outcome_var)
准确性:80.945%,交叉验证得分:80.946%
#我们可以尝试不同的变量组合:
predictor_var = ['Credit_History','Education','Married','Self_Employed','Property_Area']
classification_model(model, df,predictor_var,outcome_var)
准确性:80.945%,交叉验证得分:80.946%
通常,我们希望添加变量会提高准确性。但这是一个更具挑战性的案例。不那么重要的变量不会影响准确性和交叉验证分数。Credit_History主导了该模式。现在我们有两个选择:
功能工程:获取新信息并尝试进行预测。我将把这个留给您的创造力。
更好的建模技术。接下来让我们探讨一下。
决策树:
决策树是用于建立预测模型的另一种方法。已知提供比逻辑回归模型更高的准确性。
model = DecisionTreeClassifier()
predictor_var = ['Credit_History','Gender','Married','Education']
classification_model(model, df,predictor_var,outcome_var)
准确性:81.930%交叉验证得分:76.656%
在这里,基于分类变量的模型无法产生影响,因为信用历史记录控制着它们。让我们尝试一些数字变量:
#我们可以尝试不同的变量组合:
predictor_var = ['Credit_History','Loan_Amount_Term','LoanAmount_log']
classification_model(model, df,predictor_var,outcome_var)
准确性:92.345%,交叉验证得分:71.009%
在这里,我们观察到尽管添加变量的准确性有所提高,但交叉验证误差却有所降低。
这是模型过度拟合数据的结果。
让我们尝试一个更复杂的算法,看看是否有帮助:
随机森林:
随机森林是解决分类问题的另一种算法。
随机森林的一个优点是我们可以使它与所有要素一起使用,并且它返回一个要素重要性矩阵,可用于选择要素。
model = RandomForestClassifier(n_estimators=100)
predictor_var = ['Gender', 'Married', 'Dependents', 'Education',
'Self_Employed', 'Loan_Amount_Term', 'Credit_History', 'Property_Area',
'LoanAmount_log','TotalIncome_log']
classification_model(model, df,predictor_var,outcome_var)
准确性:100.000%交叉验证得分:78.179%
在这里,我们看到训练集的准确性是100%。这是过度拟合的最终案例,可以通过两种方式解决:
1.减少预测变量的数量
2.调整模型参数
让我们尝试这两个。
首先,我们看到特征重要性矩阵,从中可以提取最重要的特征。
#Create a series with feature importances:
featimp = pd.Series(model.feature_importances_, index=predictor_var).sort_values(ascending=False)
print (featimp)
让我们使用前5个变量创建模型。另外,我们将稍微修改随机森林模型的参数:
model = RandomForestClassifier(n_estimators=25, min_samples_split=25, max_depth=7, max_features=1)
predictor_var = ['TotalIncome_log','LoanAmount_log','Credit_History','Dependents','Property_Area']
classification_model(model, df,predictor_var,outcome_var)
准确性:82.899%交叉验证得分:81.461%
请注意,尽管准确性降低了,但是交叉验证得分却有所提高,表明该模型具有很好的泛化能力。请记住,随机森林模型不是完全可重复的。由于随机化,不同的运行会导致轻微的变化。但是输出应该留在球场上。
您可能已经注意到,即使在随机森林上进行了一些基本参数调整之后,我们所达到的交叉验证准确性也仅比原始逻辑回归模型略高。该练习为我们提供了一些非常有趣且独特的学习方法:
使用更复杂的模型不能保证获得更好的结果。
避免在不了解基本概念的情况下将复杂的建模技术用作黑匣子。这样做会增加过度拟合的趋势,从而使您的模型难以解释
功能工程是成功的关键。每个人都可以使用Xgboost模型,但真正的艺术和创造力在于增强您的功能以使其更适合该模型。