美文网首页
泰坦尼克号获救预测

泰坦尼克号获救预测

作者: Radiance_sty | 来源:发表于2019-05-15 13:59 被阅读0次

    练习:泰坦尼克号获救数据预测,预测人员获救与哪些因素有关。


    1. 读取数据

    import pandas as pd
    
    df = pd.read_csv('titanic_train.csv')
    print(df.head())
    print(df.columns)
    print(df.isnull().sum())
    print(df.describe())
    

    运行结果如图1所示:

    图1

    从图中可以看出数据大小为891 * 12,列名有['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket','Fare', 'Cabin', 'Embarked'],有些列的数据存在着缺失,我们先看看每一列代表什么意思。

    'PassengerId':乘客的ID
    'Survived':乘客是否获救,0表示未获救,1表示获救
    'Pclass':乘客舱位等级
    'Name':乘客名字
    'Sex':乘客性别
    'Age':乘客年龄
    'SibSp':乘客兄弟姐妹数
    'Parch':乘客携带的老人以及小孩数量
    'Ticket':乘客船票编号
    'Fare':乘客当前船票价格
    'Cabin':缺失值太多,忽略
    'Embarked':乘客上船地点,分别有C、S、Q


    2.数据预处理

    • 从图1看出数据中'Age'列和'Carbin'列存在缺失值,所以我们先要对'Age'列进行填充,这里使用均值填充,而'Carbin'列在分析的时候可以忽视它。
    df['Age'] = df['Age'].fillna(df['Age'].median())
    print(df.describe())
    

    运行结果如图2所示:

    图2

    从图2可以看出,'Age'列缺失的数据已经被填充好了。

    • 观察'Sex'这一列,发现里面的数据是male和female,分别代表男性和女性,在机器学习上无法识别str,我们需要将str转换为0,1,即male用0表示,female用1表示。
    print(df['Sex'].unique())
    df.loc[df['Sex'] == 'male','Sex'] = 0
    df.loc[df['Sex'] == 'female','Sex'] = 1
    print(df['Sex'].unique())
    

    运行结果如图3所示:

    图3

    从图3可以看出,已经将male和female转换为0和1.


    • 观察Embarked这一列,发现里面的数据是C、Q、S,所以也要和上面的一样,进行数据类型转换。这里将S用0表示,C用1表示,Q用2表示。同时发现Embarked列也存在着缺失值,所以需要对缺失值进行填充,先统计C、Q、S中出现频率最高的,然后将出现频率最高的填入缺失值。
    print(df['Embarked'].unique())
    print(dict(df['Embarked'].value_counts()))
    
    df['Embarked'] = df['Embarked'].fillna('S')
    df.loc[df['Embarked'] == 'S','Embarked'] = 0
    df.loc[df['Embarked'] == 'C','Embarked'] = 1
    df.loc[df['Embarked'] == 'Q','Embarked'] = 2
    
    print(df['Embarked'].unique())
    

    运行结果如图4所示:

    图4

    从图4中可以看出S的频率最高,所以这里讲S填入缺失值,经过处理后的数据变为0、1、2。


    3.模型建立

    • 用线性回归预测
    # 利用线性回归预测
    from sklearn.linear_model import LinearRegression
    from sklearn.model_selection import KFold
    
    # 设置标签
    predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
    alg = LinearRegression()
    
    kf = KFold(n_splits=3, random_state=1)
    predictions = []
    for train, test in kf.split(df[predictors]):
        train_predictors = df[predictors].iloc[train, :]
        train_target = df['Survived'].iloc[train]
        alg.fit(train_predictors, train_target)
    
        # 对测试集进行预测
        test_predictions = alg.predict(df[predictors].iloc[test, :])
        predictions.append(test_predictions)
    
    predictions = np.concatenate(predictions, axis=0)
    predictions[predictions > 0.5] = 1  # 大于0.5表示获救
    predictions[predictions <= 0.5] = 0 # 小于0.5表示未获救
    accuracy = len(predictions[predictions == df['Survived']]) / len(predictions)
    print(accuracy)
    

    运行结果为:0.7833894500561167
    可见预测的准确率并不是很高。同时还要注意,由于版本的变换,KFold模块现在改为从model_selection中导入。还有,KFold的使用方法也改了,下面是之前版本的使用方式。

    kf = KFold(df.shape[0], n_folds=3,  random_state=1)
    predictions = []
    for train, test in kf:
        train_predictors = (df[predictors].iloc[train, :]
    

    • 用逻辑回归预测
    from sklearn import model_selection
    from sklearn.linear_model import LogisticRegression
    
    predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
    alg_1 = LogisticRegression(random_state=1)
    scores = model_selection.cross_val_score(alg_1, df[predictors], df['Survived'], cv=3)
    
    print(scores.mean())
    

    运行结果为:0.7878787878787877
    可见预测的准确率之比线性回归高了那么一点点,但还是不高。在运行程序时发现了警告,警告内容如图5所示:

    图5

    虽然警告信息并不影响代码运行,但输出窗口异常明显的几行红字提醒,总觉得不爽。
    FutureWarning是语言或者库中将来可能改变的有关警告。
    根据报警信息和参考相关文档,“Default will change from 'liblinear' to 'lbfgs' in 0.22.”,默认的solver参数在0.22版本中,将会由“liblinear”变为“lbfgs”,且指定solver参数可以消除该warning。
    这是代码在发出警告,将来代码运行时如果没有及时关注到版本的问题,可能solver的参数会发生改变。所以,最安全的方法并不是通过ignore消除警告,而是指定一个solver参数。
    解决办法:

    # 版本问题,需要在后面添加 solver='liblinear',否则会有警告,虽然不影响运行
    alg_1 = LogisticRegression(random_state=1, solver='liblinear')
    

    另一种思路是:

    # 这种方法可以消除任何警告信息
    import warnings
    warnings.filterwarnings("ignore")
    

    • 随机森林模型进行预测
      同时我们要考虑上述标签中,到底是哪个标签的权重对获救的概率影响高一点,哪个权重会使得获救的概率降低,这一点需要考虑。这里引进随机森林模型,能够综合的利用标签,降低过拟合的风险,提高预测的准确性。
    # 使用随机森林模型
    from sklearn import model_selection
    from sklearn.ensemble import RandomForestClassifier
    
    # 设置标签
    predictors = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
    
    # 通过随机森林进行预测,这里随机森林的参数只是随便设定的,具体参数需要建立一个随机森林模型    
    # n_estimators指树的个数,min_samples_split指内部节点再划分所需最小样本数,min_samples_leaf叶子节点最少样本数
    alg_2 = RandomForestClassifier(random_state=1, n_estimators=50,   min_samples_split=4, min_samples_leaf=2)
    kf = model_selection.KFold(n_splits=3, random_state=1, shuffle=True)
    scores_1 = model_selection.cross_val_score(alg_2, df[predictors], df['Survived'], cv=kf)
    print(scores_1.mean())
    

    运行结果为:0.8260381593714926
    从图中的结果可以看出预测的准确率又比前面的高了一些,但还是不够。由于这里的随机森林模型是随便设定的,没有设定好参数,所以需要对模型进行优化,建立合适的树模型,优化数的个数和深度。
    RandomForestClassifier用法参考:https://www.cnblogs.com/pinard/p/6160412.html


    • 自己构造特征

    前面我们还有一些标签没有使用上,在这里我们将剩下的一些标签给用上,将标签进行数字化处理。其中,构建一个FamilySize标签,它是由SibSp标签和Parch标签相加得到;构建一个NameLength标签,它是乘客的名字长度;再构建Title标签,它是每个乘客的称号,如Mr、Mrs、Miss、Dr...。然后将标签的数据转换为数字进行处理。

    # 自己构建特征
    df['FamilySize'] = df['SibSp'] + df['Parch']  # 兄弟姐妹和老人小孩
    df['NameLength'] = df['Name'].apply(lambda x: len(x))  # 名字的长度
    
    import re
    
    
    # 每个人都有自己的身份的词,如Miss, Mr...
    def get_title(name):
        title_search = re.search(' ([A-Za-z]+)\.', name)
        if title_search:
            return title_search.group(1)
        return ''
    
    
    titles = df['Name'].apply(get_title)
    print(pd.value_counts(titles))
    
    # 将称号用数字表示
    title_mapping = {'Mr': 1, 'Miss': 2, 'Mrs': 3, 'Master': 4, 'Dr': 5, 'Rev': 6, 'Col': 7, 'Major': 8, 'Mlle': 9,
                 'Countess': 10, 'Ms': 11, 'Lady': 12, 'Jonkheer': 13, 'Don': 14, 'Mme': 15, 'Capt': 16, 'Sir': 17}
    for k, v in title_mapping.items():
        titles[titles == k] = v
    print(pd.value_counts(titles))
    
    df['Title'] = titles
    

    运行结果如图6、7所示:

    图6-各个称号的个数
    图7-各个称号数字化处理后的结果

    至此,3个新的标签就已经构建好了,我们先将数据可视化,观察哪个标签所占的权重较高,然后使用随机森林模型进行预测。

    from sklearn.feature_selection import SelectKBest, f_classif
    
    predictors_new = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked', 'FamilySize', 'NameLength', 'Title']
    
    selector = SelectKBest(f_classif, k=5)
    selector.fit(df[predictors_new], df['Survived'])
    scores_2 = -np.log10(selector.pvalues_)
    
    plt.bar(range(len(predictors_new)), scores_2)
    plt.xticks(range(len(predictors_new)), predictors_new, rotation='vertical')
    plt.show()
    

    SelectKBest用法参考:https://www.jianshu.com/p/586ba8c96a3d
    运行结果如图8所示:

    图8-各个标签所占权重

    通过上述图8我们选择5个最重要的标签,接下来用随机森林模型进行预测。

    predictors_1 = ['Pclass', 'Sex', 'Fare', 'Title', 'NameLength']
    alg_3 = RandomForestClassifier(random_state=1, n_estimators=50, min_samples_split=8, min_samples_leaf=4)
    kf = model_selection.KFold(n_splits=3, random_state=1, shuffle=True)
    scores_1 = model_selection.cross_val_score(alg_3, df[predictors_1], df['Survived'], cv=kf)
    
    print(scores_1.mean())
    

    运行结果为:0.8215488215488215
    可见,预测的结果并没有多大的改变,可见随机森林的预测效果还不够好,看能否优化一下树结构。

    相关文章

      网友评论

          本文标题:泰坦尼克号获救预测

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