Kaggle|入门:泰坦尼克号生存预测(线性回归)

前段时间学习了吴恩达的机器学习课程,然后蠢蠢欲动想要有所体验机器学习,于是上kaggle来体验了一下入门比赛-泰坦尼克号生存预测。

在kaggle上下载了项目训练集,就可以开始动手啦

本文仅仅是新手入门,hhh

1.数据初探

import numpy as np
import pandas as pd 
import seaborn as sns

import matplotlib.pyplot as plt

data_train=pd.read_csv('train.csv')
data_train.head()

使用head快速返回前5条消息。可以发现结果如下:

在kaggle页面上,我们找到了每一列的说明:

VariableDefinitionKey
survivalSurvival0 = No, 1 = Yes
pclassTicket class1 = 1st, 2 = 2nd, 3 = 3rd
sexSex 
AgeAge in years 
sibsp# of siblings / spouses aboard the Titanic 
parch# of parents / children aboard the Titanic 
ticketTicket number 
farePassenger fare 
cabinCabin number 
embarkedPort of EmbarkationC = Cherbourg, Q = Queenstown, S = Southampton

大致就是:

  1. # passengerId 乘客编号
  2. # survived 是否存活 1是 0否
  3. # pclass 船舱等级  1=lst 2=2nd 3=3rd
  4. # name 姓名
  5. # sex 性别
  6. # age 年纪
  7. # sibsp ?上的兄弟姐妹/配偶个数
  8. # parch ?上的父母,孩子
  9. # ticket 船票号码
  10. # fare 船票价格
  11. # cabin 船仓号
  12. # embarked 登船港口  C = Cherbourg, Q = Queenstown, S = Southampto

对于样本,我们进行整体把握,查看一下总体的信息:

data_train.info()

# 可以发现age,和cabin有大量缺失
# embarked只有两条缺失

2.数据处理与特征选择

Cabin船舱号有大量空值,对于空值填充可能有较大误差,所以我们先不考虑cabin作为特征

passengerId是一个连续的序列,与结果无关,我们不选择这个作为特征

ticket是船票序列,我们不分析

age,由于age缺失很少,我们使用年龄的平均值进行填充

embarked中有两条缺失的,我们使用其中出现最多的来填充

我们发现embarked和sex这两个特征是字符串,进行处理。我们将sex中male=1,famle=0。将embarked中 c=1,q=2,s=3

2.1数据填充

填充age

data_train['Age']=data_train['Age'].fillna(data_train['Age'].median())
data_train.describe()

# 可以发现AGE现在全部被填充了

填充embarked

## 统计出Embarked列各个元素出现次数
ans=data_train['Embarked'].value_counts()

# 返回最大值索引
fillstr=ans.idxmax()

data_train['Embarked']=data_train['Embarked'].fillna(fillstr)
data_train.info()
#可以发现embarked无缺失了

修改embarked与sex

# data_train['Sex'][data_train['Sex']=='male']=1
# data_train['Sex'][data_train['Sex']=='female']=0

# 使用loc定位行列
# data_train["Sex"] == "male"定位行 sex是列
data_train.loc[data_train["Sex"] == "male","Sex"] = 0
data_train.loc[data_train["Sex"] == "female","Sex"] = 1


data_train.loc[data_train['Embarked']=='C','Embarked']=0
data_train.loc[data_train['Embarked']=='Q','Embarked']=1
data_train.loc[data_train['Embarked']=='S','Embarked']=2

2.2特征选择

由于还处于入门级别,我只是想先体验一下做项目的感觉,我们就不进行一些详细的分析,使用特征工程创造更多的特征等等了。

我们进行最简单的相关性系数分析,只需要观察每个特征与分类结果Survived的相关性系数即可

相关性系数是我们研究变量的线性相关程度的量,我们最常使用的就是皮尔逊相关系数:

r(X, Y)=\frac{\operatorname{Cov}(X, Y)}{\sqrt{\operatorname{Var}[X] \operatorname{Var}[Y]}}

其中,Cov(X,Y)为X与Y的协方差,Var[X]为X的方差,Var[Y]为Y的方差

使用python实现如下:

# 下面计算相关性系数

import math

# 函数:计算相关系数
def calc_corr(a, b):
    a_avg = sum(a) / len(a)
    b_avg = sum(b) / len(b)

    # 计算分子,协方差————按照协方差公式,本来要除以n的,由于在相关系数中上下同时约去了n,于是可以不除以n
    cov_ab = sum([(x - a_avg) * (y - b_avg) for x, y in zip(a, b)])

    # 计算分母,方差乘积————方差本来也要除以n,在相关系数中上下同时约去了n,于是可以不除以n
    sq = math.sqrt(sum([(x - a_avg) ** 2 for x in a]) * sum([(x - b_avg) ** 2 for x in b]))

    corr_factor = cov_ab / sq

    return corr_factor

当然,pandas中已经为我们封装的很好了,我们可以直接使用。

#相关性协方差表,corr()函数,返回结果接近0说明无相关性,大于0说明是正相关,小于0是负相关.
#去掉passengerId,这一项是连续的序列,对结果无影响
train_corr = data_train.drop('PassengerId',axis=1).corr()
train_corr

当然,我们可以画出更为清晰的热力图

#画出相关性热力图
a = plt.subplots(figsize=(15,9))#调整画布大小
a = sns.heatmap(train_corr, vmin=-1, vmax=1 , annot=True , square=True)#画热力图

虽然我们可以发现 Sibsp,age,Parch的相关性系数都很小,但是由于是入门,我们就还是将他们都考虑进去,作为特征吧。

3.使用线性回归

首先来介绍一下线性回归。

假设你有了喜欢的?,那么在追她之前,你需要对自己进行评估。那么你会对自己身上的一系列特征评估,来认识自己。比如身高x1,x2,帅气程度x3,有钱程度x4等等。那么我们预测自己的得分h(x):

h_{\theta}(x)=\theta^{T} X=\theta_{0}+\theta_{1} x_{1}+\theta_{2} x_{2}+\ldots+\theta_{n} x_{n}

那么上式中的Ɵ(theta)参数就是对于我们每一个特征的权重,我们系要做的就是找到一组合适的theta,使得我们的预测更加准确,这样我们才能正确的评估自己,避免盲目出击。比如我们认为有钱程度x4的权重theta4为100,身高x1的权重为20也许是比较合理的。如果我们认为有钱程度x4的权重theta4为-2,身高x1的权重为3,那么根据实际经验,这显然是错误的。

3.1代价函数

那么我们怎么知道我们的theta参数最好呢,我们此时需要定义一个代价函数,反应我们预测值与实际值的差距。最简单的就是误差平方和啦。我们现在给出cost function J(theta)的定义:J\left(\theta\right)=\frac{1}{2 m} \sum_{i=1}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right)^{2}

所以我们现在的目标是找到使得我们的代价函数最小theta。

3.2梯度下降

首先,梯度的本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)【from 百科】。直观的理解就是,比如我们面前一座山,我们沿着山坡最陡峭的下坡(梯度)往下跑,我们下来的最快。那么对于代价函数J(theta),我们沿着其梯度,我们会一直下降到函数的某一个极值点(局部最优解),或者是最小值点(全局最优解)。

如下图黑色的线,我们就是我们使用梯度下降就可以从起点不断向着最优解收敛。

我们对J求theta的偏导,就可以得到theta的偏导数{\frac{1}{m} \sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right) x_{j}^{(i)}}。然后迭代的将theta沿着梯度下降的方向更新。这样我们就可以不断向着最优解逼近

上面就是线性回归的基本知识,下面我们就用线性回归来进行预测吧。

首先我们先自己实现一下线性回归,然后进行预测。

代码如下:

# 实现多元线性回归

# 获取样本

x_data=data_train[["Pclass","Age","Parch","Fare","Sex","Embarked"]]
y_data=data_train['Survived']

x=x_data.values #将dataframe转为矩阵 

y=y_data.values.reshape(-1,1) #  列向量 891X1


# 标准化数据
def norm(x_data):
    mu = np.zeros(x_data.shape[1])
    sigma = np.zeros(x_data.shape[1])


    mu=np.mean(x_data)
    sigma=np.std(x_data)

    x_norm=(x_data-mu)/sigma

    return x_norm
   

# 添加常数项x0 为1
x_norm=np.insert(x_norm,0,np.ones(x_norm.shape[0]),axis=1)
x_norm # 891X 7


# 使用梯度下降

# 定义学习率
alpha=0.1
# 定义迭代次数
iters=700

#初始化theta   7X1 
theta=np.zeros(x_norm.shape[1]).reshape(-1,1)


# 样本数m

# (n,)是一个数组,既不是行向量也不是列向量

# 定义代价函数
def mutilCost(X,y,theta):
    m=X.shape[0]
    bais=np.dot(theta.T,x_norm.T)-y.T
    cost=1/2/m*np.dot(bais,bais.T)
    return cost


# 定义梯度下降函数
def gradientDescentMulti(X, y, theta, alpha, num_iters):
    m=X.shape[0]
    cost_history =np.zeros(num_iters)
    for i in range(1,num_iters):
        theta=theta-aplha/m*X.T@(X@theta-y)
        cost_history[i] = mutilCost(X, y, theta)
    return theta,cost_history

训练theta
[theta, cost_history] = gradientDescentMulti(x_norm, y, theta, alpha, iters)

获取结果
ans=x_norm@theta

# 这是一个2分类问题,结果为0,1.那么对于预测生存几率大于0.5的,我们认为其能存活,置为1,小于0.5的为0

ans[ans>=0.5]=1
ans[ans<0.5]=0
ans.shape
data_train["Survived"].shape


# 查看准确率
accuracy = sum(ans == data_train["Survived"].values.reshape(-1,1)) / len(predictions)
print("准确率为: ", accuracy)

最后我们发现准确率为0.67。不是很理想hhh,不过毕竟是自己简单实现的。

当然,我们可以直接使用sklearn中的linea regression来进行预测

from sklearn.linear_model import LinearRegression #导入线性回归

# 训练集进行交叉验证,得到均值

from sklearn.model_selection import KFold

# 选取简单的可用数字特征
predictors=["Pclass","Age","Parch","Fare","Sex","Embarked",'SibSp']     


#初始化现行回归算法
alg = LinearRegression()
#样本平均分成3份,3折交叉验证
kf = KFold(n_splits=3,shuffle=False,random_state=1) 
predictions = []
for train,test in kf.split(data_train):
    train_predictors = (data_train[predictors].iloc[train,:])
    train_target = data_train["Survived"].iloc[train]
    alg.fit(train_predictors,train_target)
    test_predictions = alg.predict(data_train[predictors].iloc[test,:])
    predictions.append(test_predictions)


#测试准确率
import numpy as np
 
predictions = np.concatenate(predictions,axis=0)
 
predictions[predictions>.5] = 1
predictions[predictions<=.5] = 0

accuracy = sum(predictions == data_train["Survived"]) / len(predictions)
print ("准确率为: ", accuracy)

这下我们的准确率来到了0.79,这就非常不错了。完成了我们的算法,进行了训练,得到的预测结果也还可以,然后我们就可以提交了?

too young,我们还需要对测试集中的数据进行处理(类似我们对训练集数据的处理),然后生成符合kaggle提交要求的文件。代码如下:

#对data——test进行一样的预处理

data_test=pd.read_csv('test.csv')

ans=data_test['Embarked'].value_counts()

# 返回最大值索引
fillstr=ans.idxmax()

data_test['Embarked']=data_test['Embarked'].fillna(fillstr)
data_test.info()
data_test.loc[data_test["Sex"] == "male","Sex"] = 0
data_test.loc[data_test["Sex"] == "female","Sex"] = 1

data_test.loc[data_test['Embarked']=='C','Embarked']=0
data_test.loc[data_test['Embarked']=='Q','Embarked']=1
data_test.loc[data_test['Embarked']=='S','Embarked']=2

data_test['Age']=data_test['Age'].fillna(data_test['Age'].median())

mid=data_test['Fare'].median()
data_test['Fare']=data_test['Fare'].fillna(value=mid)


test_predictions = alg.predict(data_test[predictors])
test_predictions[test_predictions>=0.5]=1
test_predictions[test_predictions<0.5]=0

# 导出结果
result=pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(),'Survived':test_predictions.astype(np.int32)})

这下算是大功告成了,我们接下来可以愉快的提交了。

 

好了,至此我们就完成了首次的kaggle体验了。也希望自己在以后的学习中有更多的收获吧。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值