美文网首页数据分析类
kaggle项目之Titanic数据集

kaggle项目之Titanic数据集

作者: 汝心若知 | 来源:发表于2018-06-12 19:24 被阅读35次

    本例主要针对kaggle上的Titanic数据集进行分析预测,文章主体分为以下两个部分:

    • 机器学习流程的回顾
    • Titanic数据集的分析和处理
      image
      PS:流程回顾来源于Udacity的机器学习入门课程,Titanic数据的处理参考了kaggle上众位大佬的分享。
      ——————流程回顾——————

    在开始进行分析之前,让我们仔细回顾下一个机器学习项目的流程。

    数据集/问题——>特征处理——>算法建模——>评估

    第一步,数据集/问题

    机器学习是用来解决实际问题的,收集与实际问题有关的数据,能够有助于后续步骤的继续进行。在这个阶段需要知道

    • 数据量足够大?
    • 我提出了什么问题?
    • 要回答这个问题,有足够的正确的特征么?
    第二步,特征处理
    • 探索型分析(EDA)
      分析特征与变量的相关性(pearsonr相关系数)
      删除一些离群值
      清理特征与数据

    • 生成新的特征
      一般来说,基于对现实业务的了解,生成新的特征。

    • 特征选择

      • 单变量特征选择工具:
        SelectPercentile :最强大的 X% 特征(X 是参数)
        SelectKBest :选择 K 个最强大的特征(K 是参数)
      • 迭代特征(增/减)
      • lasso回归:
        在最小误差与特征数量之间寻找一个平衡,实际应用中,该数值越接近0,说明该特征带来的影响也就越小。
      • 删除不必要的特征
    • 特征的缩放(适用于维度变化的算法):
      减去平均值:x - mean
      minmax scaler:(x-min)/(max-min)
      standard scaler:(x-mean)/sigma

    • 转换特征:

      • PCA(主成分分析):数据中使方差最大化的方向,在对这些成分压缩或投影时,将信息丢失的可能性降至最低。
        【只对符合高斯分布的样本点有效】
        一般用于转换成新的特征,也可以用来划分等级,方差最大为第一等级,以此类推,但第一主成分绝对不会与第二主成分叠加。主成分等级的数量是有上限的,受制于输入特征的数量。

        用处:

        • 寻找隐藏特征
        • 降维:可视化高维数据,减噪
      • ICA(独立成分分析)

      • FA(因子分析)

    第三步,算法

    根据是否需要labels,分为监督学习和非监督学习

    • 监督学习:
      • 回归:线性回归、lasso回归、决策树回归、sv回归
      • 分类:决策树、朴素贝叶斯、SVM、随机森林、Adaboost、knn、LDA、logistic回归
    • 非监督学习:
      • 聚类:K均值、DBSCN、EM算法、离群值检测
    • 运行算法:调参、可视化检验、在测试集上运行、寻找最佳参数(GridsearchCV)
    第四步,评估
    • 验证:
      分隔测试集和训练集、k-flods法、可视化
    • 评估指标
      SSE/R^2、准确率、召回率、F1 分数、特征曲线

    PS:
    以上步骤的顺序不是绝对的,为了获得拥有强大泛化能力的模型,我们需要不断地重复某些步骤。

    ———————Titanic数据集的分析与预测——————

    n久之前,初生不畏牛犊的我,进入了kaggel,第一个练手的数据集——Titanic,死得剧惨。重新整理了思路了之后,预测效果也好了很多,具体思路见下文。

    主要思路

    1. 加载数据集并进行简要探索性分析
    2. 特征工程
    3. 建模与模型评估

    以前分析思路:
    加载数据集——数据清理——探索性分析——特征处理——建模评估

    1. 加载数据集&探索性分析

    (1)数据概览:

    train:


    头几行数据
    数据类型与空值状况
    数据分布的整体状况

    从简要的概览中,可以看出训练集中存在这些情况:

    • Age,Cabin,Embarked存在空值
    • Age,SibSp,Parch,Fare分布似乎呈偏右分布,具体还需要验证

    测试集的加载和训练集类似,可以自己去试下。
    这里为方便处理,合并训练集和测试集,生成新的DataFrame.

    #合并测试集和训练集
    df =  pd.concat([train, test], axis=0).reset_index()
    
    (2)从分布来看:

    a. 整体的生存状况


    image

    b. SeX


    image
    c. Pclass
    image
    image

    d. Embarked


    image
    e. Age
    image
    f. Fare
    image
    g. Parch
    image
    h. SibSp
    image

    发现:

    • 女性的存活率高于男性
    • Pclass1,2,3的生存率依次降低,这有可能与不同层的乘船人的社会地位,富裕程度有关
    • Pclass 1,2女性的生存率远大于Pclass 3的女性,Pclass 1 的男性的生存率大于Pclass 2,3层的男性
    • S口岸登船的人数最多,生存率也最低,C、Q口岸登船的人数和生存率正好相反。那个时代,远没有现在网络时代的发达,所以我们可以假定认为一个口岸登船的同一层的很容易坐在一起的,这也很可能是一个影响逃生率的因素。
    • 年龄上来说,似乎很统一,小孩先走,存活率较高
    • Fare分布差异很大,可能存在幼童免票,团体票,家庭票等情况
    • Parch 代表同船的父母或子女,SipSp代表同船的兄弟姐妹,这都是两个表现亲人的关系,后面一起会做特征处理。
    • 单人的存活几率低于有1个以上的或3个以下的亲人同船的存活几率,但过于一些过于庞大的家庭成员的生存几率。家庭成员过多也不好,过少也不好。

    2. 特征工程

    (1)Embarked
    #缺失值填充
    df['Embarked'].fillna("S",inplace=True)
    #数值化S,C,Q
    le = LabelEncoder()
    le.fit(df['Embarked'])
    df['Embarked'] = le.transform(df['Embarked'])
    
    (2)Fare
    #分配到个人票价
    df['Fare'] = df['Fare'] / df.groupby('Ticket')['Fare'].transform('count')
    df['Fare'].fillna(df['Fare'].median(),inplace=True)
    sns.distplot(df["Fare"])
    plt.title("Distribution of Fare");
    
    image
    #定义一个票价分级函数
    def fare_level(s):
        if s <= 5 :
            m = 0
        elif s>5 and s<=20:
            m = 1
        elif s>20 and s<=40:
            m = 2
        else:
            m = 3
        return m
    df['Fare_level'] = df['Fare'].apply(fare_level)
    
    (3)Parch and SibSp
    #组合Parch,SibSp
    df['Family_memebers'] = df['Parch'] + df['SibSp'] + 1
    
    (4)Sex
    #数值化性别
    le.fit(df['Sex'])
    df['Sex'] = le.transform(df['Sex'])
    
    (5)Age

    年龄拥有大量的缺失值,处理方法有很多中,这里采用建立一个回归模型预测年龄缺失值。

    #利用线性回归和随机森林回归模型预测Age的值
    age_nan = pd.DataFrame(df[['Age', 'Sex','Family_memebers', 'Fare',  'Pclass', 'Embarked']])
    age_train = age_nan[age_nan.Age.notnull()]
    age_test = age_nan[age_nan.Age.isnull()]
    #线性回归
    lr = LinearRegression()
    lr_grid_pattern = {'fit_intercept': [True], 'normalize': [True]}
    lr_grid = GridSearchCV(lr, lr_grid_pattern, cv=10, n_jobs=25, verbose=1, scoring='neg_mean_squared_error')
    lr_grid.fit(age_train.drop("Age",axis=1), age_train["Age"])
    print('Age feature Best LR Params:' + str(lr_grid.best_params_))
    print('Age feature Best LR Score:' + str(lr_grid.best_score_))
    lr = lr_grid.predict(age_test.drop("Age",axis=1))
    #随机森林回归
    rfr = RandomForestRegressor()
    rfr_grid_pattern = {'max_depth': [3], 'max_features': [3]}
    rfr_grid = GridSearchCV(rfr, rfr_grid_pattern, cv=10, n_jobs=25, verbose=1, scoring='neg_mean_squared_error')
    rfr_grid.fit(age_train.drop("Age",axis=1), age_train["Age"])
    print('Age feature Best LR Params:' + str(rfr_grid.best_params_))
    print('Age feature Best LR Score:' + str(rfr_grid.best_score_))
    rfr = rfr_grid.predict(age_test.drop("Age",axis=1))
    #取二者均值
    age_test["Age"] = (lr+rfr)/2
    #定义年龄分级的函数
    def age_level(s):
        if s <= 15 :      #儿童
            m = 0      
        elif s>15 and s<=30: #青年及少年
            m = 1
        elif s>30 and s<=60: #壮年
            m = 2
        else:               #老年
            m = 3
        return m
    df["Age_level"] = df["Age"].apply(age_level)
    

    3. 建模与模型评估

    X = df[:len(train)][['Age_level', 'Sex','Family_memebers', 'Fare_level',  'Pclass', 'Embarked']]
    y = df[:len(train)]["Survived"]
    
    (1)评估方法
    • 混淆矩阵
      有准确率、召回率、F1值等指标,本文采用准确率。
    • 交叉检验
      将数据集划分成n份,选择一份作为测试集,其余n-1份作为训练集,重复n次(每次的测试集都不同)。
    (2)建模

    利用交叉检验得到结果,cv = 10,指标为准确率,可以看到SVC具有出色的表现。


    image
    (3)模型优化

    主要利用GridSearchCV寻找最佳拟合的结果。

    SVMC = SVC(probability=True)
    svc_param_grid = {'kernel': ['rbf'], 
                      'gamma': [ 0.001, 0.01, 0.1, 1],
                      'C': [1, 10, 50, 100,200,300, 1000]}
    
    gsSVMC = GridSearchCV(SVMC,param_grid = svc_param_grid, cv=10, scoring="accuracy", n_jobs= 4, verbose = 1)
    
    gsSVMC.fit(X,y)
    SVMC_best = gsSVMC.best_estimator_
    
    (4)预测
    features = ['Age_level', 'Sex','Family_memebers', 'Fare_level',  'Pclass', 'Embarked']
    
    SVMC_best.fit(X,y)
    
    out_text = SVMC_best.predict(df[len(train):][features])
    text = pd.DataFrame(out_text.astype(int),index=df[len(train):]['PassengerId'].values).reset_index() 
    text.rename(columns={"index":"PassengerId",0:"Survived"}).to_csv('predict_02.csv',index=False)
    

    最后的结果:


    image

    笔者终于从倒数爬到了正数,不容易。
    总体上来看,

    • Titanic的特征数量比较少,很容易入手
    • 后来我又用VotingClassifier进行集成,但结果居然没有单独的SVC表现更好,这可能与其强大随机性有关,具体的原因还可以再探究一下。
    • 就特征方面来说,name和ticket可能包含了同一家人的信息,笔者没有做具体分析,这块可以再继续深入。

    原文代码:在这里

    相关文章

      网友评论

        本文标题:kaggle项目之Titanic数据集

        本文链接:https://www.haomeiwen.com/subject/xxpfeftx.html