赞
踩
数据加载与合并:
pandas
读取训练集和测试集数据,然后合并,这便于对整体数据执行一致的预处理和分析。数据探索与可视化:
pandas
进行基础数据探索(如检查缺失值、数据类型、基本统计描述)。matplotlib
和seaborn
进行数据可视化,探索不同特征与目标变量(生存率)之间的关系。特征工程:
模型构建与评估:
结果预测与提交:
- import warnings
- warnings.filterwarnings("ignore") #忽略警告信息
-
- # 数据处理清洗包
- import pandas as pd
- import numpy as np
- import random as rnd
-
- # 可视化包
- import seaborn as sns
- import matplotlib.pyplot as plt
- %matplotlib inline
-
- # 机器学习算法相关包
- from sklearn.linear_model import LogisticRegression, Perceptron, SGDClassifier
- from sklearn.svm import SVC, LinearSVC
- from sklearn.neighbors import KNeighborsClassifier
- from sklearn.naive_bayes import GaussianNB
- from sklearn.tree import DecisionTreeClassifier
- from sklearn.ensemble import RandomForestClassifier
-
- SVC()
%matplotlib inline
: 是一个魔法命令,它可以在IPython或Jupyter Notebook中内嵌绘图,并且可以省略掉plt.show()
。- Scikit-learn (
sklearn
): 是Python中使用最广泛的机器学习库之一,包含了从数据预处理到训练模型的各种工具。
LogisticRegression
、Perceptron
、SGDClassifier
: 线性模型,用于分类任务。SVC
、LinearSVC
: 支持向量机,用于分类和回归分析。KNeighborsClassifier
: 最近邻算法,用于分类和回归。GaussianNB
: 朴素贝叶斯分类器,适用于大量特征的数据。DecisionTreeClassifier
: 决策树分类器,用于分类和回归。RandomForestClassifier
: 随机森林是一个包含多个决策树的分类器,用于分类和回归,能有效处理过拟合。SVC()
是创建一个支持向量机分类器的实例,通常用于比较不同模型
- train_df = pd.read_csv('./titanic/train.csv')
- test_df = pd.read_csv('./titanic/test.csv')
- combine = [train_df, test_df] # 合并数据
合并数据便于对整体数据执行一致的预处理和分析。
- # 获取所有特征名
- print(train_df.columns.values)
-
- # 预览前五个数据
- train_df.head()
-
- # 预览后五个数据
- train_df.tail()
- print(train_df.isnull().sum()) #找出不同特征的缺失值数量
- print('_'*40) #分割线
- test_df.isnull().sum() #最后一个单元格表达式自动显示
test_df.isnull().sum() #在Jupyter Notebook中,单元格中的最后一个表达式的结果会被自动展示,这使得在一些情况下可以不必显式地使用print()函数。这种方式可以让代码看起来更简洁,尤其是在进行探索性数据分析时,可以快速查看数据而不需要过多的print()调用
- train_df.info()
- print('_'*40)
- test_df.info()
info()方法详细列出了DataFrame中的每列,包括其名称、非空值的数量以及每列的数据类型。此外,还提供了DataFrame使用的内存量。
- 在交互式环境中:如Jupyter Notebook,
info()
的输出自动显示,不需要print()
。- 在非交互式环境中(如直接在Python脚本中运行):
info()
的输出仍然会显示在控制台,因为它设计为直接输出到标凈输出流
round(train_df.describe(percentiles=[.5, .6, .7, .75, .8, .9, .99]),2)
train_df.describe()
:
describe()
是一个生成描述性统计数据的方法,常用于快速查看数据的分布情况。- 默认情况下,它提供 count(计数)、mean(均值)、std(标准差)、min(最小值)、25%(第一四分位数)、50%(中位数)、75%(第三四分位数)和 max(最大值)。
percentiles=[.5, .6, .7, .75, .8, .9, .99]
:
- 通过
percentiles
参数,可以指定需要计算的具体百分位数。- 在这个例子中,除了常规的 25%、50%、75% 外,还额外计算了 60%、70%、80%、90% 和 99% 的百分位数。
- 50%(0.5)其实就是中位数,这里显示了将其作为百分位数的一部分也是可以的。
round(..., 2)
:
round()
函数用于对describe()
方法的结果进行四舍五入。- 这里的
, 2
表示将结果四舍五入到小数点后两位。- 这通常用于改进数据的呈现,使其更易读,尤其是在处理包含很多小数的数据时。
运行结果
列的解释:
- PassengerId:乘客的ID号。
- Survived:乘客是否存活,其中1表示存活,0表示未存活。
- Pclass:乘客的舱位等级,一个分类变量,代表1等舱、2等舱和3等舱。
- Age:乘客的年龄。
- SibSp:乘客在船上的兄弟姐妹或配偶的数量。
- Parch:乘客在船上的父母或子女的数量。
- Fare:乘客为船票支付的费用。
统计量的解释:
- count:表示每个特征列的非空值数量。例如,Age列有714个非空值,说明有部分乘客的年龄数据缺失。
- mean:平均值。例如,Survived的平均值为0.38,表明大约38%的乘客存活。
- std:标准差,表示数据的离散程度。例如,Age的标准差为14.53,说明乘客年龄分布的波动较大。
- min:最小值。例如,Fare的最小值为0.00,表明有乘客没有为船票支付费用。
- 50% (中位数):数据的中间点。例如,Pclass的中位数为3,表明大多数乘客处于3等舱。
- 60%, 70%, 75%, 80%, 90%, 99%:这些都是不同的百分位数,提供了关于数据分布的更多细节。例如,99%的乘客年龄小于或等于65.87岁。
- max:最大值。例如,Age的最大值为80岁,表明船上最老的乘客是80岁。
分析例子:
Survived:
- 平均值为0.38,说明大约38%的乘客存活。
- 50% (中位数) 为0,说明超过一半的乘客未存活。
- 99%的百分位数为1,说明除了极少数之外,绝大多数乘客都未能存活。
Fare:
- 平均值为32.20,但中位数仅为14.45,表明船票费用分布极不均匀,少数高票价拉高了平均值。
- 最高票价为512.33,远高于大多数乘客的票价,表明可能有极少数的高级舱位。
describe()
是 pandas 库中的一个强大函数,用于生成关于 DataFrame 或 Series 对象中数据的描述性统计摘要。这通常包括均值、标准差、最小值、最大值以及各个百分位数。
describe()
函数可以通过几个参数来定制其行为:percentiles:一个介于0和1之间的数值列表,用于指定计算哪些百分位数。默认是
[0.25, 0.5, 0.75]
,分别对应25%,50%(中位数),75% 百分位数。
df.describe(percentiles=[0.2, 0.4, 0.6, 0.8])
include:用于指定应该包括哪些数据类型的列在输出中。默认情况下,只描述数值型列。可以设置为 'all' 包括所有列,或者一个数据类型列表。
df.describe(include='all') # 描述所有列,包括非数值型 df.describe(include=[np.number]) # 仅描述数值型列 df.describe(include=[np.object]) # 仅描述对象类型列exclude:与
include
相反,用于指定排除哪些数据类型的列。
df.describe(exclude=[np.number]) # 排除所有数值型列
train_df.describe(include=['O'])
- 使用
include=['O']
会导致describe()
方法生成那些类型为对象的列的统计摘要,这包括:
- count:非空(非 NaN)值的数量。
- unique:不重复值的数量,展示该列中有多少个唯一的值。
- top:出现频率最高的值。
- freq:出现频率最高的值的频率(即该值出现了多少次)。
对部分特征与survived的相关性进行分析,初步判断有用特征量
- # 针对Pclass和Survived进行分类汇总
- train_df[['Pclass','Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)
- # pd.DataFrame(train_df.groupby('Pclass', as_index=False)['Survived'].mean()).sort_values(by='Survived', ascending=False)
-
- train_df[['Sex','Survived']].groupby(['Sex'], as_index=False).mean().sort_values(by='Survived', ascending=False)
-
- train_df[['SibSp','Survived']].groupby(['SibSp'], as_index=False).mean().sort_values(by='Survived',ascending=False)
-
- train_df[['Parch','Survived']].groupby(['Parch'], as_index=False).mean().sort_values(by='Survived',ascending=False)
- g = sns.FacetGrid(train_df, col='Survived') #FacetGrid(data, row, col, hue, height, aspect, palette, ...)
- g.map(plt.hist, 'Age', bins=20)
sns.FacetGrid
是seaborn
库中用于创建一个网格,可以在这个网格中绘制多个图表,每个图表显示数据的一个子集。train_df
是包含数据的 DataFrame。col='Survived'
参数指定网格的列(col)基于Survived
列的不同值来分割。因为Survived
是一个二元变量(通常取值 0 或 1),所以这将生成两个面板(facet):一个为存活(Survived=1
),一个为未存活(Survived=0
)。g.map()
函数用于在每个分面上应用一个绘图函数。plt.hist
是matplotlib.pyplot
的函数,用于绘制直方图。'Age'
指定了直方图的数据列,这里是乘客的年龄。bins=20
指定将数据分成20个等宽的条形,这有助于更细致地观察年龄分布的形状。
- #grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', size=2.5, aspect=1.6)
- grid = sns.FacetGrid(train_df, col='Pclass', hue='Survived')
- #alpha是透明度
- grid.map(plt.hist, 'Age', alpha=0.5, bins=20)
- grid.add_legend();
- grid = sns.FacetGrid(train_df, col='Embarked')
-
- grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep')
-
- #add_legend():这是 seaborn FacetGrid 对象的方法,用于在图形中添加图例。图例显示的是图形中代表的#不同类别(如果 FacetGrid 在创建时使用了 hue 参数指定了颜色区分的变量)。
- #如果 FacetGrid 被定义时包含了 hue 参数(这个参数通常用于按某个变量的不同值对数据进行颜色编码),#那么 add_legend() 就会在图表中添加一个图例,标明不同颜色代表的数据类别。
-
- grid.add_legend();
- grid = sns.FacetGrid(train_df, col='Embarked', hue='Survived', palette={0: 'b', 1: 'r'})
- grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, ci=None)
- grid.add_legend()
输出
移除不需要的列
- 在代码中,使用
combine[0].shape
和combine[1].shape
来显示数据处理前后这两个 DataFrame 的形状,这有助于确认是否正确地执行了如删除列等操作。
- print("Before", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)
-
- train_df = train_df.drop(['Ticket', 'Cabin'], axis=1)
- test_df = test_df.drop(['Ticket', 'Cabin'], axis=1)
- combine = [train_df, test_df]
-
- "After", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape
提取新的特征(将乘客的称呼作为了一个新特征)
- # 使用正则表达式提取Title特征
- for dataset in combine:
- dataset['Title'] = dataset.Name.str.extract('([A-Za-z]+)\.', expand=False)
-
- pd.crosstab(train_df['Title'], train_df['Sex']).sort_values(by='female', ascending=False) # pd.crosstab列联表
循环遍历
combine
列表:combine
是一个包含两个 DataFrame (train_df
和test_df
) 的列表。这个循环确保对列表中的每个 DataFrame 执行相同的操作。使用
str.extract()
方法:这是 pandas 中的一个字符串方法,用来对字符串列应用正则表达式,并提取匹配的部分。这里的正则表达式([A-Za-z]+)\.
匹配任何连续的字母字符(至少一个),后跟一个点(.
)。这种模式匹配常见于诸如 "Mr.", "Mrs.", "Dr." 等称谓。
expand=False
:此参数设置为 False 表示返回的结果是一个 Series,而不是 DataFrame。
pd.crosstab
:这是 pandas 中的一个函数,用于计算两个(或更多)因子的简单交叉表。它非常适合于快速汇总信息,并查看两个变量之间的关系。参数:这里
train_df['Title']
作为行索引(index),train_df['Sex']
作为列索引(columns)。这将创建一个展示不同称谓和性别组合的频率分布表。
sort_values(by='female', ascending=False)
:这个方法用于对结果进行排序,基于 'female' 列的值降序排序。这样做可以快速查看哪些称谓最常与女性关联。
- grid = sns.FacetGrid(train_df, col='Title', hue='Survived', col_wrap=3, size=2.5, aspect=1.6)
- #grid = sns.FacetGrid(train_df, col='Title', hue='Survived')
- grid.map(plt.hist, 'Age', alpha=0.5, bins=20)
- grid.add_legend()
- # 可以用更常见的名称替换许多标题或将它们归类为稀有
- for dataset in combine:
- dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',
- 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
-
- dataset['Title'] = dataset['Title'].replace(['Mlle', 'Ms'], 'Miss')
- dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')
-
- train_df[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()
- # 将分类标题转换为序数
- title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
- for dataset in combine:
- dataset['Title'] = dataset['Title'].map(title_mapping) # 将序列中的每一个元素,输入函数,最后将映射后的每个值返回合并,得到一个迭代器
- dataset['Title'] = dataset['Title'].fillna(0)
-
- train_df.head()
- # 转换分类特征Sex
- for dataset in combine:
- dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int) #男性赋值为0,女性赋值为1,并转换为整型数据
-
- train_df.head()
- # 绘制Age, Pclass, Sex复合直方图
- #grid = sns.FacetGrid(train_df, row='Pclass', col='Sex', size=2.2, aspect=1.6)
- grid = sns.FacetGrid(train_df, col='Pclass', hue='Sex')
- grid.map(plt.hist, 'Age', alpha=.5, bins=20)
- grid.add_legend()
- # 创建空数组
- guess_ages = np.zeros((2,3))
- guess_ages
-
- # 遍历 Sex (0 或 1) 和 Pclass (1, 2, 3) 来计算六种组合的 Age 猜测值
- for dataset in combine:
- # 第一个for循环计算每一个分组的Age预测值
- for i in range(0, 2):
- for j in range(0, 3):
- guess_df = dataset[(dataset['Sex'] == i) & \
- (dataset['Pclass'] == j+1)]['Age'].dropna()
-
- # age_mean = guess_df.mean()
- # age_std = guess_df.std()
- # age_guess = rnd.uniform(age_mean - age_std, age_mean + age_std)
-
- age_guess = guess_df.median()
-
- # 将随机年龄浮点数转换为最接近的 0.5 年龄(四舍五入)
- guess_ages[i,j] = int( age_guess/0.5 + 0.5 ) * 0.5
-
- # 第二个for循环对空值进行赋值
- for i in range(0, 2):
- for j in range(0, 3):
- dataset.loc[ (dataset.Age.isnull()) & (dataset.Sex == i) & (dataset.Pclass == j+1),\
- 'Age'] = guess_ages[i,j]
-
- dataset['Age'] = dataset['Age'].astype(int)
- train_df.head()
- # 创建年龄段,并确定其与Survived的相关性
- # 一般在建立分类模型时,需要对连续变量离散化,特征离散化后,模型会更稳定,降低了模型过拟合的风险
- train_df['AgeBand'] = pd.cut(train_df['Age'], 5) # 将年龄分割为5段,等距分箱
- train_df[['AgeBand', 'Survived']].groupby(['AgeBand'], as_index=False).mean().sort_values(by='AgeBand', ascending=True)
-
- # 将这些年龄区间替换为序数
- for dataset in combine:
- dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0
- dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1
- dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2
- dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3
- dataset.loc[ dataset['Age'] > 64, 'Age'] = 4
- train_df.head()
-
- train_df = train_df.drop(['AgeBand'], axis=1) # 删除训练集中的AgeBand特征
- combine = [train_df, test_df]
- train_df.head()
- test_df
-
- for dataset in combine:
- dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
-
- train_df[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False)
-
- # 创建新特征IsAlone
- for dataset in combine:
- dataset['IsAlone'] = 0
- dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1
-
- train_df[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()
-
- train_df = train_df.drop(['Parch', 'SibSp', 'FamilySize'], axis=1)
- test_df = test_df.drop(['Parch', 'SibSp', 'FamilySize'], axis=1)
- combine = [train_df, test_df]
-
- train_df.head()
-
- # 创建Age*Pclass特征以此用来结合Age和Pclass变量
- for dataset in combine:
- dataset['Age*Pclass'] = dataset.Age * dataset.Pclass
-
- train_df.loc[:, ['Age*Pclass', 'Age', 'Pclass']].head(10)
- train_df[['Age*Pclass', 'Survived']].groupby(['Age*Pclass'], as_index=False).mean()
-
- freq_port = train_df.Embarked.dropna().mode()[0]
- for dataset in combine:
- dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)
-
- train_df[['Embarked', 'Survived']].groupby(['Embarked'], as_index=False).mean().sort_values(by='Survived', ascending=False)
-
- # 同样转换分类特征为序数
- for dataset in combine:
- dataset['Embarked'] = dataset['Embarked'].map( {'S': 0, 'C': 1, 'Q': 2} ).astype(int)
-
- train_df.head()
-
-
- # 测试集中Fare有一个缺失值,用中位数进行填补
- test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True)
- test_df.head()
-
- plt.hist(train_df['Fare'])
-
- train_df['FareBand'] = pd.qcut(train_df['Fare'], 4) # 根据样本分位数进行分箱,等频分箱
- train_df[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)
-
- for dataset in combine:
- dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
- dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
- dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare'] = 2
- dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
- dataset['Fare'] = dataset['Fare'].astype(int)
-
- train_df = train_df.drop(['FareBand'], axis=1)
- combine = [train_df, test_df]
-
- train_df.head(10)
- test_df.head(10)
- X_train = train_df.drop("Survived", axis=1)
- Y_train = train_df["Survived"]
- X_test = test_df.drop("PassengerId", axis=1).copy()
- X_train.shape, Y_train.shape, X_test.shape
-
- # 逻辑回归模型
- logreg = LogisticRegression()
- logreg.fit(X_train, Y_train)
- Y_pred = logreg.predict(X_test) # logreg.predict_proba(X_test)[:,1]
- acc_log = round(logreg.score(X_train, Y_train) * 100, 2)
- acc_log
-
-
- coeff_df = pd.DataFrame(train_df.columns.delete(0))
- coeff_df.columns = ['Feature']
- coeff_df["Correlation"] = pd.Series(logreg.coef_[0])
- coeff_df.sort_values(by='Correlation', ascending=False)
-
- # 支持向量机模型
- svc = SVC()
- svc.fit(X_train, Y_train)
- Y_pred = svc.predict(X_test)
- acc_svc = round(svc.score(X_train, Y_train) * 100, 2)
- acc_svc
-
- # KNN
- knn = KNeighborsClassifier(n_neighbors = 3)
- knn.fit(X_train, Y_train)
- Y_pred = knn.predict(X_test)
- acc_knn = round(knn.score(X_train, Y_train) * 100, 2)
- acc_knn
-
- # 朴素贝叶斯分类器
- gaussian = GaussianNB()
- gaussian.fit(X_train, Y_train)
- Y_pred = gaussian.predict(X_test)
- acc_gaussian = round(gaussian.score(X_train, Y_train) * 100, 2)
- acc_gaussian
-
- # 感知机
- perceptron = Perceptron()
- perceptron.fit(X_train, Y_train)
- Y_pred = perceptron.predict(X_test)
- acc_perceptron = round(perceptron.score(X_train, Y_train) * 100, 2)
- acc_perceptron
-
- # 线性SVC
- linear_svc = LinearSVC()
- linear_svc.fit(X_train, Y_train)
- Y_pred = linear_svc.predict(X_test)
- acc_linear_svc = round(linear_svc.score(X_train, Y_train) * 100, 2)
- acc_linear_svc
-
- # SDG随机梯度下降
- sgd = SGDClassifier()
- sgd.fit(X_train, Y_train)
- Y_pred = sgd.predict(X_test)
- acc_sgd = round(sgd.score(X_train, Y_train) * 100, 2)
- acc_sgd
-
- # 决策树
- decision_tree = DecisionTreeClassifier()
- decision_tree.fit(X_train, Y_train)
- Y_pred = decision_tree.predict(X_test)
- acc_decision_tree = round(decision_tree.score(X_train, Y_train) * 100, 2)
- acc_decision_tree
-
- # 决策树可视化
- from sklearn import tree
- import graphviz
- import pydotplus
- from IPython.display import Image
- dot_data = tree.export_graphviz(decision_tree, out_file=None,
- feature_names=X_train.columns,
- class_names=['0','1'],
- max_depth=3,
- filled=True, rounded=True,
- special_characters=True)
- graph = pydotplus.graph_from_dot_data(dot_data)
- Image(graph.create_png())
-
- dot_data = tree.export_graphviz(decision_tree, out_file=None,
- feature_names=X_train.columns,
- #class_names=['0','1'],
- filled=True, rounded=True,
- special_characters=True)
- graph = pydotplus.graph_from_dot_data(dot_data)
- graph.write_pdf("DTtree.pdf")
-
- train_df[(train_df['Age*Pclass']>2.5) & (train_df['Fare']<=1.5)&(train_df['Fare']>0.5)&(train_df['IsAlone']>0.5)&(train_df['Age']>0.5)& \
- (train_df['Embarked']<=1.5) &(train_df['Embarked']>0.5)&(train_df['Fare']<=2.5)&(train_df['Age']<=1.5)&(train_df['Pclass']>1.5)& \
- (train_df['Title']<=1.5)]
-
- # 随机森林
- random_forest = RandomForestClassifier(n_estimators=100)
- random_forest.fit(X_train, Y_train)
- Y_pred = random_forest.predict(X_test)
- random_forest.score(X_train, Y_train)
- acc_random_forest = round(random_forest.score(X_train, Y_train) * 100, 2)
- acc_random_forest
- models = pd.DataFrame({
- 'Model': ['Support Vector Machines', 'KNN', 'Logistic Regression',
- 'Random Forest', 'Naive Bayes', 'Perceptron',
- 'Stochastic Gradient Decent', 'Linear SVC',
- 'Decision Tree'],
- 'Score': [acc_svc, acc_knn, acc_log,
- acc_random_forest, acc_gaussian, acc_perceptron,
- acc_sgd, acc_linear_svc, acc_decision_tree]})
- models.sort_values(by='Score', ascending=False)
- submission = pd.DataFrame({
- "PassengerId": test_df["PassengerId"],
- "Survived": Y_pred
- })
- submission.to_csv('./submission.csv', index=False)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。