Машинное обучение: титанический случай для начала работы с деревьями решений

машинное обучение

В этой статье записано вводное упражнение по машинному обучению, а именно: простая бинарная классификация с деревьями решений. В то же время в сочетании с классическим случаем Titanic на Kaggle, чтобы проверить реальный эффект.

1. Набор данных

использоватьKaggleНабор данных Титаник в формате . Данные включают:

  • тренировочный набор: тренировочный набор (train.csv)
  • Набор тестов: набор тестов (test.csv)
  • Критерии подачи: поле_submission.csv

Поскольку Kaggle предполагает работу с научным доступом в Интернет, поэтомуисходный набор данныхОн был скачан и выложен на Gighub.

2. Обработка данных

Сначала импортируйте тренировочный набор и проверьте данные:

from sklearn.tree import DecisionTreeClassifier # 导入模型决策树分类器
from sklearn.model_selection import cross_val_score,train_test_split,GridSearchCV # 导入的模型作用分别为交叉验证、训练集与数据集的划分,网格搜索
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

data = pd.read_csv('/Users/liz/code/jupyter-notebook/sklearn/1- DecisionTree/Titanic_train.csv') # 导入数据集
data.head() # 显示数据集的前五行
[out]:

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

С приведенными выше данными, показывающими ситуацию, все, что нам нужно сделать, это использовать Survived в качестве метки, а остальные столбцы в качестве функций. Цель: Предсказать метки с известными функциями. Фактический смысл этого набора данных состоит в том, чтобы сделать прогноз выживания пассажиров на основе известных данных.

data.info() # 查看整个训练集的情况
out:
 <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 891 entries, 0 to 890
    Data columns (total 12 columns):
    PassengerId    891 non-null int64
    Survived       891 non-null int64
    Pclass         891 non-null int64
    Name           891 non-null object
    Sex            891 non-null object
    Age            714 non-null float64
    SibSp          891 non-null int64
    Parch          891 non-null int64
    Ticket         891 non-null object
    Fare           891 non-null float64
    Cabin          204 non-null object
    Embarked       889 non-null object
    dtypes: float64(2), int64(5), object(5)
    memory usage: 83.7+ KB
анализ данных
  1. В приведенном выше отображении данных имеется в общей сложности 891 данные, среди которых функции с отсутствующими значениями: Возраст, Каюта, Посадка; нечисловые функции: Имя, Пол, Билет, Каюта, Посадка.
  2. Когда мы используем существующие функции для прогнозирования ситуации выживания пассажиров, некоторые пары функций, которые являются более хлопотными и менее важными, могут не использоваться. Например, Имя и Билет здесь можно не использовать, потому что в действительности имя пассажира и купленный билет мало влияют на выживаемость пассажира. Другая причина заключается в том, что и те, и другие являются нечисловыми данными, и их сложнее преобразовать в числовую форму (данные, полученные в компьютере, в конечном итоге должны быть представлены в виде чисел).
  3. Поскольку в Cabin много пропущенных значений, здесь принят метод удаления по тем же причинам, что и выше.
  4. Хотя пол также является данными характера, на практике пол оказывает определенное влияние на возможность побега, поэтому он резервируется.
  5. Вменить пропущенные значения; преобразовать нечисловые данные в числовые данные.
# 删除Name、Ticket、Cabin特征列
data.drop(['Name','Cabin','Ticket'],inplace=True,axis=1)


# 缺失值的填补
# 对于Age的缺失值填补的一种策略为:以年龄的平均值作为填补
data.loc[:,'Age'] = data['Age'].fillna(int(data['Age'].mean()))
# Embarked由于只有两条数据具有缺失值,这里采用的方式是删除这两条缺失的数据(缺失两条数据对模型的训练好坏影响不大)
data = data.dropna()
data = data.reset_index(drop = True) # 删除过后,用于重置索引

# 将非数值型数据转化为数值型数据
# 性别只有两类,故可用0\1来表示男女
data['Sex'] = (data['Sex'] == 'male').astype(int) # 0表示女,1表示男
tags = data['Embarked'].unique().tolist() # tags: ['S', 'C', 'Q']
# Embarked只有三类分别以S,C,Q的索引代表他们,0~9均可采用此种方法
data.iloc[:,data.columns == 'Embarked'] = data['Embarked'].apply(lambda x : tags.index(x))

# 查看数据
data.info() # 查看数据信息
out:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 889 entries, 0 to 888
Data columns (total 9 columns):
PassengerId    889 non-null int64
Survived       889 non-null int64
Pclass         889 non-null int64
Sex            889 non-null int64
Age            889 non-null float64
SibSp          889 non-null int64
Parch          889 non-null int64
Fare           889 non-null float64
Embarked       889 non-null int64
dtypes: float64(2), int64(7)
memory usage: 62.6 KB


# 将特征与标签进行分离
x = data.iloc[:,data.columns != 'Survived'] # 取出Survived以为的列作为特征x
y = data.iloc[:,data.columns == 'Survived'] # 取出Survived列作为特征y
обучение модели

Идея: использовать перекрестную проверку для оценки нашей модели, а также использовать поиск по сетке, чтобы найти лучшие параметры, обычно встречающиеся в деревьях решений.

# 网格搜索:能够帮助我们同时调整多个参数的技术,本质是枚举技术。
# paramerters:用于确定的参数。
parameters = {'splitter':('best','random')
             ,'criterion':('gini','entropy')
             ,'max_depth':[*range(1,10)]
             ,'min_samples_leaf':[*range(1,50,5)]
             ,'min_impurity_decrease':[*np.linspace(0,0.5,20)]
             }

# 网格搜索实例代码,所需要确定的参数越多,耗时越长
clf = DecisionTreeClassifier(random_state=30)
GS = GridSearchCV(clf,parameters,cv=10) # cv=10,做10次交叉验证
GS = GS.fit(x_train,y_train)

# 最佳参数
GS.best_params_
out:
    {'criterion': 'gini',
 'max_depth': 3,
 'min_impurity_decrease': 0.0,
 'min_samples_leaf': 1,
 'splitter': 'best'}
    
# 最佳得分
GS.best_score_

Определив оптимальные значения для заданных параметров, приступаем к обучению модели:

# 训练模型,将以上设置参数的最佳值填入模型的实例化中
clf_model = DecisionTreeClassifier(criterion='gini'
                                  ,max_depth=3
                                  ,min_samples_leaf=1
                                  ,min_impurity_decrease=0
                                  ,splitter='best'
                                  )
clf_model = clf_model.fit(x,y)

Экспортируйте модель:

# 导出模型
from sklearn.externals import joblib
joblib.dump(clf_model,'/Users/liz/Code/jupyter-notebook/sklearn/1- DecisionTree/clf_model.m')

Обработка тестового набора:

# 导入测试集
data_test = pd.read_csv('/Users/liz/code/jupyter-notebook/sklearn/1- DecisionTree/Titanic_test.csv')
data_test.info()
out:
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 418 entries, 0 to 417
    Data columns (total 11 columns):
    PassengerId    418 non-null int64
    Pclass         418 non-null int64
    Name           418 non-null object
    Sex            418 non-null object
    Age            332 non-null float64
    SibSp          418 non-null int64
    Parch          418 non-null int64
    Ticket         418 non-null object
    Fare           417 non-null float64
    Cabin          91 non-null object
    Embarked       418 non-null object
    dtypes: float64(2), int64(4), object(5)
    memory usage: 36.0+ KB

# 测试集处理的方法同训练集,同时测试集要与训练集保持同样的特征
# 由于最后,我们需要将处理结果上传到Kaggle上,所以不能够将数据条目减少,即:需要上传418条测试数据;故这里Fare缺失的一条数目同样采用平均值来填补
data_test.drop(['Name','Ticket','Cabin'],inplace=True,axis=1)
data_test['Age'] = data_test['Age'].fillna(int(data_test['Age'].mean()))
data_test['Fare'] = data_test['Fare'].fillna(int(data_test['Fare'].mean()))
data_test.loc[:,'Sex'] = (data_test['Sex'] == 'male').astype(int)
tags = data_test['Embarked'].unique().tolist()
data_test['Embarked'] = data_test['Embarked'].apply(lambda x : tags.index(x))

На этом этапе данные тестового набора предварительно обрабатываются, экспортируйте модель и тестируйте данные:

# 导出模型且测试数据集
model = joblib.load('/Users/liz/Code/jupyter-notebook/sklearn/1- DecisionTree/clf_model.m')
Survived = model.predict(data_test) # 测试结果
# 生成数据
Survived = pd.DataFrame({'Survived':Survived}) # 将结果转换为字典形式并后续作为csv形式导出
PassengerId = data_test.iloc[:,data_test.columns == 'PassengerId'] # 切片,分割出PassengerId
gender_submission = pd.concat([PassengerId,Survived],axis=1)# 将Survived与PassengerId拼接,一一对应

#导出数据
#导出数据
gender_submission.index = np.arange(1, len(gender_submission)+1) # 索引从1开始
gender_submission.to_csv('/Users/liz/Code/jupyter-notebook/sklearn/1- DecisionTree/gender_submission.csv',index=False) # index=False,导出时不显示索引

Экспорт файла:

PassengerId Survived
0 892 0
1 893 1
2 894 0
3 895 0
4 896 1
... ... ...
413 1305 0
414 1306 1
415 1307 0
416 1308 0
417 1309 0

418 строк × 2 столбца

представить результатыKaggle, окончательный балл:

得分

Окончательная оценка 0,77990, оценка невысокая, а самая высокая оценка заполнена.Эта статья — просто введение в машинное обучение и Kaggle.

Окончательный исходный код и набор данных Kaggle будут загружены в мой репозиторий Github, в том числе некоторые связанные заметки, размещенные в Интернете, также будут загружены в Github, этот репозиторий будет постоянно обновляться...

прикрепил

URL-адрес на гитхабе:GitHub.com/Chem LE at/ml-…