[Обмен опытом конкурса начального уровня Kaggle top5%] - Моделирование

искусственный интеллект Python анализ данных Kaggle

Добавить Автора

Публичный аккаунт WeChat:PythonНаука о данных

Знаю почти:аналитик данных Python


Обзор прошлой ситуации

Предыдущая статья — прелюдия к интеллектуальному анализу данных, основная цель —Распознавайте функции данных, оценивайте важность функций, наблюдайте за аномалиями в данных и определяйте взаимосвязь между данными.. В этой статье будет продолжен предыдущий анализ части моделирования интеллектуального анализа данных.

Ссылки на предыдущий анализ данных:[Обмен опытом конкурса начального уровня Kaggle top5%] — Анализ

предварительная обработка данных

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

  • Очистка данных: пропущенные значения, выбросы, согласованность;
  • Кодирование функций:one-hotиlabel coding;
  • Биннинг функций: равная частота, равное расстояние, кластеризация и т.д.;
  • производная переменная: Сильная интерпретируемость, подходящая для ввода модели;
  • Выбор функции: выбор дисперсии, выбор хи-квадрат, регуляризация и т.д.;

1. Очистка данных

В части анализа мы видим, что есть 4 функции с пропущенными значениями:Возраст, Кабина, Посадили, Плата за проезд. Некоторые блоггеры уже представили некоторые методы обработки пропущенных значений:[Основа анализа данных Python]: обработка пропущенных значений данных

Начнем разбираться с пропущенными значениями отдельно.

Обработка пропущенного значения тарифа

Сначала взгляните на отсутствующую функцию Fare:

df[df['Fare'].isnull()]

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

Продолжайте наблюдать, каковы характеристики этого бесценного пассажира? Как использовать наш предыдущий анализ, чтобы справиться с этим?

  • Особенность 1: Pclass равен 3, в аналитической части мы знаем, что плата за проезд и социальный класс Pclass имеют тесную связь, плата за проезд Pclass1 относительно высока, а самая низкая плата за проезд — Pclass3;
  • Особенность 2: возраст пассажира больше 60 лет, он мужчина;

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

df.loc[(df['Pclass']==3)&(df['Age']>60)&(df['Sex']=='male')]

Мы нашли еще нескольких пассажиров, которые совпадали с ним, и использовали данные пассажира.Средний тарифзаполнять.

# 提取出Name中的Surname信息
df['surname'] = df["Name"].apply(lambda x: x.split(',')[0].lower())
fare_mean_estimated = df.loc[(df['Pclass']==3)&(df['Age']>60)&(df['Sex']=='male')].Fare.mean()
df.loc[df['surname']=='storey','Fare'] = fare_mean_estimated

Отсутствующие значения встроенной функции

Так же наблюдайтеEmbarkedдля отсутствующих значений:

# Embarked缺失值处理
df[df['Embarked'].isnull()]

обнаружил, что оба女性. В предыдущем визуальном анализеpclass1а в случае с женщинамиQ港口почти 0 иC港口самый, следующийS港口, на следующем рисунке показаны результаты визуализации анализа.

Здесь используются самые распространенные порты, т.е.Порт режима Cзаполнять.

df['Embarked'] = df['Embarked'].fillna('C')

Отсутствующие значения характеристик кабины

Особенности Каина70%Отсутствующее значение , является более серьезным, и при большом объеме заполнения будет внесено больше шума. Поскольку отсутствующее значение также является значением, здесь отсутствующее значение Cabin рассматривается как специальное значение, и новая функция выводится на основе первого символа Cabin.CabinCat.

df['CabinCat'] = pd.Categorical.from_array(df.Cabin.fillna('0').apply(lambda x: x[0])).codes

пандыCategorical.from_array()использование. Смысл кода в том, чтобы использовать“0”заменятьCabin缺失值, и извлеките первое значение неотсутствующего значения характеристики кабины для классификации, например, A114 — это A, C345 — это C, следующим образом:

[0, C, 0, C, 0, ..., 0, C, 0, 0, 0]
Length: 1309
Categories (9, object): [0, A, B, C, ..., E, F, G, T]

использоватьCategorical.from_array()Разделите Cabin на 9 групп и, наконец, определите их количество с помощью кодов и наблюдайте за результатами групповой дискретизации с помощью визуализации:

fig, ax = plt.subplots(figsize=(10,5))
sns.countplot(x='CabinCat', hue='Survived',data=df)
plt.show()

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

Отсутствующие значения признака возраста

Возраст имеет 20% пропущенных значений, а пропущенных значений много. Большое количество удалений сократит информацию о выборке. Поскольку она отличается от Cabin, для прогнозирования и заполнения возраста будут использоваться другие функции, то есть подгонка неизвестных собственных значений возраста. , который будет обработан позже.

Анализ согласованности данных

Когда мы получаем данные, мы должны помнить об одном:Не доверяйте полностью данным. Даже если это не выброс, это может быть дезинформация, которая нужна для проверки непротиворечивости данных.

В этом примере мы понимаем это через два исправления.

ошибка 1: Несоответствие между функциями SibSp и Parch.

df.loc[df['surname']=='abbott',['Name','Sex','Age','SibSp','Parch']]

Для простоты чтения ниже вместо имен используются серийные номера.

Сначала найдите название лодкиabbottхозяин, семья. Открытие: 392 пассажирам было всего 13 лет, и у них было двое детейParch=2(Теоретически маловероятно), в то время как 279 пассажиров были в возрасте 35 лет, имели одного ребенка и одного брата или сестру, а 746 пассажиров имели одного родителя и одного родного брата. Очевидно, что информация неверна, и информация о пассажирах 279 и 392 перепутана.Правильный посыл - мама с двумя детьми, поэтому измените на: 279 пассажировSibSp=0,Parh=2, 392-летний пассажир:SibSp=1, Parh=1. Вот измененный код:

df.loc[(df['surname']=='abbott')&(df['Age']==35),'SibSp'] = 0
df.loc[(df['surname']=='abbott')&(df['Age']==35),'Parch'] = 2
df.loc[(df['surname']=='abbott')&(df['Age']==13),'SibSp'] = 1
df.loc[(df['surname']=='abbott')&(df['Age']==13),'Parch'] = 1

Ошибка 2: Несоответствие между функциями SibSp и Parch.

df.loc[df['surname']=='ford',['Name','Sex','Age','SibSp','Parch']]

Так же,fordТакже существует проблема непротиворечивости ошибок в семье, и каждый может проанализировать ее самостоятельно.Правильно: Мать с тремя детьми., а последний пассажир является образцом в тестовом наборе, предполагается, что это, вероятно, отец. Вот измененный код:

df.loc[(df['surname']=='ford')&(df['Age']==16),'SibSp'] = 3
df.loc[(df['surname']=='ford')&(df['Age']==16),'Parch'] = 1
df.loc[(df['surname']=='ford')&(df['Age']==9),'SibSp'] = 3
df.loc[(df['surname']=='ford')&(df['Age']==9),'Parch'] = 1
df.loc[(df['surname']=='ford')&(df['Age']==21),'SibSp'] = 3
df.loc[(df['surname']=='ford')&(df['Age']==21),'Parch'] = 1
df.loc[(df['surname']=='ford')&(df['Age']==48),'SibSp'] = 0
df.loc[(df['surname']=='ford')&(df['Age']==48),'Parch'] = 4
df.loc[(df['surname']=='ford')&(df['Age']==18),'SibSp'] = 3
df.loc[(df['surname']=='ford')&(df['Age']==18),'Parch'] = 1

2. Преобразование данных

производная переменная

В разделе анализа не упоминаетсяNameОсобенности, ведь имя у всех разное. Но некоторые люди могут действовать группами, например, всей семьей, иsurnameто же самое, поэтому в это время семейную группу можно найти по фамилии. Для чего нужны семейные группы? Мы упомянем об этом позже. На самом деле, функция Name очень важна, если копнуть глубже.Только представьте, могут ли пассажиры сесть на корабль вместе с другими людьми? Это семья? пара? все еще один? Вероятность выживания этой группы людей должна иметь общие черты, например, есть семья из 5 человек, а погибло 4 человека, можно предположить, что пятый человек, скорее всего, погибнет. Ниже приведены новые переменные функций, полученные из всех функций.

# 从Name中提取Title信息,因为同为男性,Mr.和 Master.的生还率是不一样的
df["Title"] = df["Name"].apply(lambda x: re.search(' ([A-Za-z]+)\.',x).group(1))
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 7, "Mlle": 2, "Mme": 3,"Don": 9,"Dona": 9, "Lady": 10, "Countess": 10, "Jonkheer": 10, "Sir": 9, "Capt": 7, "Ms": 2}

# 量化Title信息
df["TitleCat"] = df.loc[:,'Title'].map(title_mapping)

# SibSp和Parch特征进行组合
df["FamilySize"] = df["SibSp"] + df["Parch"] + 1
# 根据FamilySize分布进行分箱
df["FamilySize"] = pd.cut(df["FamilySize"], bins=[0,1,4,20], labels=[0,1,2])

# 从Name特征衍生出Name的长度
df["NameLength"] = df["Name"].apply(lambda x: len(x))

# 量化Embarked特征
df["Embarked"] = pd.Categorical.from_array(df.Embarked).codes

# 对Sex特征进行独热编码分组
df = pd.concat([df,pd.get_dummies(df['Sex'])],axis=1)

Следующее описание производных характеристических переменных:

  • Title: Извлечение информации о Титуле из Имени, так как оба мужчины, коэффициенты выживаемости Мистера и Мастера разные;
  • TitleCat: Отображение и количественная оценка информации о заголовке.Хотя эта функция может иметь коллинеарность с полем, мы сначала получаем ее, а затем фильтруем;
  • FamilySize: В части визуального анализа видно, что распределения SibSp и Parch похожи, а признаки SibSp и Parch объединены;
  • NameLength: Длина Имени происходит от признака Имени, потому что чем короче название некоторых стран, тем они благороднее;
  • CabinCat: Группировка информации о салоне; Расширенные производные переменные

[1] Характеристики, производные от персонажей

Из-за высокой выживаемости детей все дети-пассажиры извлекаются отдельно (здесь установлено 18 лет). Для взрослых женщин вероятность выживания относительно высока, поэтому она не для взрослых женщин и взрослых мужчин. код показывает, как показано ниже:

# 妇女/儿童 男士标签
child_age = 18
def get_person(passenger):
    age, sex = passenger
    if (age < child_age):
        return 'child'
    elif (sex == 'female'):
        return 'female_adult'
    else:
        return 'male_adult'

df = pd.concat([df, pd.DataFrame(df[['Age', 'Sex']].apply(get_person, axis=1), columns=['person'])],axis=1)
df = pd.concat([df,pd.get_dummies(df['person'])],axis=1)

[2] Функции, производные от билетов

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

table_ticket = pd.DataFrame(df["Ticket"].value_counts())
table_ticket.rename(columns={'Ticket':'Ticket_Numbers'}, inplace=True)
table_ticket['Ticket_dead_women'] = df.Ticket[(df.female_adult == 1.0) 
                                    & (df.Survived == 0.0) 
                                    & ((df.Parch > 0) | (df.SibSp > 0))].value_counts()

table_ticket['Ticket_dead_women'] = table_ticket['Ticket_dead_women'].fillna(0)
table_ticket['Ticket_dead_women'][table_ticket['Ticket_dead_women'] > 0] = 1.0

table_ticket['Ticket_surviving_men'] = df.Ticket[(df.male_adult == 1.0) 
                                    & (df.Survived == 1.0) 
                                    & ((df.Parch > 0) | (df.SibSp > 0))].value_counts()

table_ticket['Ticket_surviving_men'] = table_ticket['Ticket_surviving_men'].fillna(0)
table_ticket['Ticket_surviving_men'][table_ticket['Ticket_surviving_men'] > 0] = 1.0 

# Ticket特征量化
table_ticket["Ticket_Id"] = pd.Categorical.from_array(table_ticket.index).codes

table_ticket["Ticket_Id"][table_ticket["Ticket_Numbers"] < 3 ] = -1
# Ticket数量分箱
table_ticket["Ticket_Numbers"] = pd.cut(table_ticket["Ticket_Numbers"], bins=[0,1,4,20], labels=[0,1,2])

df = pd.merge(df, table_ticket, left_on="Ticket",right_index=True, how='left', sort=False)

Аналогично, на основе производных переменныхSurnameПеременные расширенных функций также могут быть получены, иCabin的奇偶性衍生特征.

Обработка отсутствующего значения возраста

Как упоминалось ранее, метод подгонки будет использоваться для заполненияAgeПропущенные значения, так почему же это должно быть рассмотрено позже? Причины следующие:

  • Также отсутствуют значения в других функциях, которые вводятся в подобранную модель, чтобы повлиять на эффект прогнозирования;
  • Функции остаются исходными символами, не оцениваются количественно и не могут быть введены в модель;

Поскольку поднятые вопросы были решены выше, мы можем начать拟合Age缺失值. В этой части используется случайный лесExtraTreesRegressorМодель установлена, и код выглядит следующим образом:

from sklearn.ensemble import RandomForestClassifier, ExtraTreesRegressor

classers = ['Fare','Parch','Pclass','SibSp','TitleCat', 
            'CabinCat','female','male', 'Embarked', 'FamilySize', 'NameLength','Ticket_Numbers','Ticket_Id']
etr = ExtraTreesRegressor(n_estimators=200,random_state=0)
X_train = df[classers][df['Age'].notnull()]
Y_train = df['Age'][df['Age'].notnull()]
X_test = df[classers][df['Age'].isnull()]

etr.fit(X_train.as_matrix(),np.ravel(Y_train))
age_preds = etr.predict(X_test.as_matrix())
df['Age'][df['Age'].isnull()] = age_preds

Если вы хотите продолжать видеть, каковы результаты подгонки, вы можете наблюдать это с помощью визуализации:

# Age缺失值填补后的情况
X_test['Age'] = pd.Series(age_preds)
f,ax=plt.subplots(figsize=(10,5))
sns.swarmplot(x='Pclass',y='Age',data=X_test)
plt.show()

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

3. Выбор функции

Фильтрация — дисперсионный анализ

Эта функция используетANOVAдисперсионный анализF值Для оценки каждой функциональной переменной значение оценки таково: вес влияния каждой функциональной переменной на целевую переменную. Код выглядит следующим образом, используя sklearnfeature_selection:

from sklearn.feature_selection import SelectKBest, f_classif,chi2

target = data_train["Survived"].values
features= ['female','male','Age','male_adult','female_adult', 'child','TitleCat',
           'Pclass','Ticket_Id','NameLength','CabinType','CabinCat', 'SibSp', 'Parch',
           'Fare','Embarked','Surname_Numbers','Ticket_Numbers','FamilySize',
           'Ticket_dead_women','Ticket_surviving_men',
           'Surname_dead_women','Surname_surviving_men']

train = df[0:891].copy()
test = df[891:].copy()

selector = SelectKBest(f_classif, k=len(features))
selector.fit(train[features], target)
scores = -np.log10(selector.pvalues_)
indices = np.argsort(scores)[::-1]
print("Features importance :")
for f in range(len(scores)):
    print("%0.2f %s" % (scores[indices[f]],features[indices[f]]))

В этом разделе разделены ранее объединенные наборы данных для обучения и тестирования, потому что в конце мы хотим сделать прогнозы на наборе для тестирования. Результат веса выбора признаков выглядит следующим образом (его можно отобразить визуально):

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

Корреляционный анализ признаков

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

features_selected = features
# data_corr 
df_corr = df[features_selected].copy()

colormap = plt.cm.RdBu
plt.figure(figsize=(20,20))
sns.heatmap(df_corr.corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)
plt.show()

3 Прогнозы моделирования

Создать модель

Это очевидная проблема контролируемой классификации, поэтому существует множество модельных алгоритмов на выбор или слияние моделей для повышения точности. Здесь используется случайный лес ансамблевого обучения.RandomForestМодель. код показывает, как показано ниже:

from sklearn import cross_validation

rfc = RandomForestClassifier(n_estimators=3000, min_samples_split=4, class_weight={0:0.745,1:0.255})
# rfc = AdaBoostClassifier(n_estimators=3000, learning_rate=0.1, random_state=1)

# 交叉验证,建模随机森林
kf = cross_validation.KFold(train.shape[0], n_folds=3, random_state=1)

scores = cross_validation.cross_val_score(rfc, train[features_selected], target, cv=kf)
print("Accuracy: %0.3f (+/- %0.2f) [%s]" % (scores.mean()*100, scores.std()*100, 'RFC Cross Validation'))
rfc.fit(train[features_selected], target)
score = rfc.score(train[features_selected], target)
print("Accuracy: %0.3f            [%s]" % (score*100, 'RFC full test'))
importances = rfc.feature_importances_
indices = np.argsort(importances)[::-1]
for f in range(len(features_selected)):
    print("%d. feature %d (%f) %s" % (f + 1, indices[f]+1, importances[indices[f]]*100, features_selected[indices[f]]))

Чтобы предотвратить переоснащение, используйте了K折交叉验证пробовать. Расширенные модели, такие как ансамблевое обучение, имеют свои собственные методы оценки характеристик.После обучения данных мы можем пройтиfeature_importancesПолучите оценку веса функции (когда функций слишком много, ее также можно использовать в качестве начального метода скрининга функций). Конечно, это можно показать и визуально.

Результат ввода следующий:

Предсказание модели

# 预测目标值
rfc.fit(train[features_selected], target)
predictions = rfc.predict(test[features_selected])

выходной файл

# 输出文件
PassengerId =np.array(test["PassengerId"]).astype(int)
my_prediction = pd.DataFrame(predictions, PassengerId, columns = ["Survived"])

my_prediction.to_csv("my_prediction.csv", index_label = ["PassengerId"])

Наконец, выведите результаты прогноза на лист Excel. если ты придешьKaggleОтправьте выходные данные, и результат, который вы должны получить, будет следующим:0.8188, что означает, что ваша точность равна 0,8188. Этот балл может быть достигнут500/11000классифицировать (top5%).

4 Резюме

В этой статье анализируется предварительная обработка данных и моделирование, а также завершается окончательный прогноз выживших.Есть несколько моментов, которые необходимо улучшить:

  • Найдите больше производных функций, чтобы улучшить качество ввода модели;
  • Попробуйте несколько моделей и сравните результаты прогнозирования, или вы можете использовать расширенное слияние моделей и оптимизацию вторичного слияния для повышения точности;
  • Попробуйте различные методы, чтобы отфильтровать важные функции среди множества функций;
  • Для дальнейшего обнаружения и обработки некоторых нечетких выбросов;
  • Улучшить точность заполнения пропущенных значений и уменьшить шум в данных;

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

Ссылка: https://www.kaggle.com/francksylla/titanic-machine-learning-from-disaster/

Обратите внимание на публичный аккаунт WeChat:PythonНаука о данныхчтобы открыть для себя больше отличного контента.