Раздел
Программирование
Просмотров
11
Покупок
0
Антиплагиат
Не указан
Размещена
10 Авг в 16:00
ВУЗ
Не указан
Курс
Не указан
Стоимость
1 450 ₽
Демо-файлы   
3
zip
pim
95.2 Кбайт
pdf
lab_1_weather_prediction_pt
218.7 Кбайт
pdf
lab_2_titanic_pt
390.5 Кбайт
Файлы работы   
1
Каждая работа проверяется на плагиат, на момент публикации уникальность составляет не менее 40% по системе проверки eTXT.
rar
РЕШЕНИЕ и 2 ОТЧЕТА
645.4 Кбайт
Описание

Выполнены 2 лабораторные работы + сделан отчет

ПОЛНОЕ ЗАДАНИЕ В ДЕМО ФАЙЛЕ

+ ДЛЯ ПОИСКА ДУБЛИРУЮ НИЖЕ

Оглавление

Лабораторная №1: Классификация погоды

В этом ноутбуке мы:

Получим набор данных по погоде с открытого API

Рассмотрим и проанализируем его

Обучим пару моделей для классификации погоды

Классифицируем погоду на сегоднешний день с помощью обученных моделей

Ноутбук основан на Kaggle: Weather prediction-Ensemble Methods

Установка и импорт бибилиотек

# Установка библиотек для получения данных!pip install openmeteo-requests!pip install requests-cache retry-requests

# Импорт библиотек / функций для дальнейшей работыimport jsonimport requestsimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy import statsfrom scipy.stats import ttest_indfrom scipy.stats import pearsonrfrom sklearn.preprocessing import StandardScaler, LabelEncoderfrom sklearn.model_selection import train_test_splitfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.svm import SVCfrom sklearn.ensemble import GradientBoostingClassifierfrom xgboost import XGBClassifierfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_report

Получение данных

Получим данные о значениях погоды, сумме осадков, максимальной/минимальной температуры и максимальной скорости ветра с открытого API

Для простоты предлагается загрузить предоставленные данные ( open-meteo-67.59N33.44E174m.csv ) в локальное хранилище и использовать их для обучения. В данном случае это данные для города Апатиты с 2010-01-01 по 2024-08-10. Альтернативно можно загрузить данные на свой гугл диск и взять от туда

Если работа ведется не через Гугл коллаб, в конце ноутбука есть код для получения данных напрямую с API, им так же можно воспользоваться для получения данных для другого города или времени.

Для загрузки в локальное хранилище выберите слева пункт Файлы и затем Загрузить в сессионное хранилище

# Импорт данных через сессионное хранилищеdaily_dataframe=pd.read_csv("/content/open-meteo-67.59N33.44E174m.csv", skiprows=3)daily_dataframe.head()

# Импорт данных через гугл диск# from google.colab import drive# drive.mount('/content/drive')# daily_dataframe=pd.read_csv("/content/drive/MyDrive/open-meteo-67.59N33.44E174m.csv", skiprows=3)# daily_dataframe.head()

Анализ набора данных

daily_dataframe.info()

Мы уже знаем какими признаками для анализа располагаем, а именно -

date - Дата

weather_code - Наиболее суровые погодные условия в определенный день в формате WMO

temperature_2m_max - Максимальная температура воздуха на высоте 2 метров над землей за день

temperature_2m_min - Минимальная температура воздуха на высоте 2 метров над землей за день

precipitation_sum - Сумма суточных осадков (включая дождь, ливни и снег)

wind_speed_10m_max - Максимальная скорость ветра за день

Из них:

4 неприрывных числовых признака (precipitation_sum, temperature_2m_max, temperature_2m_min, wind_speed_10m_max)

1 признак является датой (date)

1 признак сообщает нам о типе погоды (weather_code)

Что бы преобразовать WMO коды в осознанные погодные значения, воспользуемся интернетом и найдем описание кодов

url = "https://gist.githubusercontent.com/stellasphere/9490c195ed2b53c707087c8c2db4ec0c/raw/76b0cb0ef0bfd8a2ec988aa54e30ecd1b483495d/descriptions.json"resp = requests.get(url)wmo_codes = {int(key): value['day']['description'] for key, value in json.loads(resp.text).items()}wmo_codes

Упростим задачу нашей модели и избавимся от разнообразия погоды в целевых значениях

simple_wmo_codes = {0: 'Sunny', 1: 'Sunny', 2: 'Cloudy', 3: 'Cloudy', 45: 'Fog', 48: 'Fog', 51: 'Drizzle', 53: 'Drizzle', 55: 'Drizzle', 56: 'Drizzle', 57: 'Drizzle', 61: 'Rain', 63: 'Rain', 65: 'Rain', 66: 'Rain', 67: 'Rain', 71: 'Snow', 73: 'Snow', 75: 'Snow', 77: 'Snow', 80: 'Show', 81: 'Showers', 82: 'Showers', 85: 'Showers', 86: 'Showers', 95: 'Thunderstorm', 96: 'Thunderstorm', 99: 'Thunderstorm'}

# Добавим новый признак погоды на основе ее кодаdaily_dataframe["weather"] = daily_dataframe["weather_code"].map(wmo_codes)daily_dataframe["simple_weather"] =

daily_dataframe["weather_code"].map(simple_wmo_codes)daily_dataframe.head()

Исследование данных

Начнем с исследования нашего "сырого" набора данных. А именно сначала посмотрим на категориальный признак weather

sns.countplot(x="weather", data=daily_dataframe, stat="percent").tick_params(axis='x', rotation=90)

Из приведенного выше графика видно, что приемущественно погода облачная, снежная или моросил дождь

Посмотрим так же на упрощенный признак погоды simple_weather

sns.countplot(x="simple_weather", data=daily_dataframe, stat="percent").tick_params(axis='x', rotation=90)

Можно заметить что данные не сбалансированны, но в рамках этой работы мы оставим все как есть

Далее рассмотрим Непрерывные признаки

daily_dataframe[["precipitation_sum","temperature_2m_max","temperature_2m_min","wind_speed_10m_max"]].describe()

Можно сделать несколько наблюдений:

Среднее значение температуры по датасету находится в районе нуля

Максимальная минимальная температура за сутки порядка 20 градусов, значит когда то летом была очень теплая ночь

Минимальная максимальная температура -28, а значит когда то днем было очень холодно

Не то что бы это было полезно в данном случае, но часто с помощью метода датафрейма .describe() можно получить полезную информацию от которой можно отталкиваться в контексте анлиза имеющихся данных

Посмотрим на распределение числовых признаков с помощью Гистограмм и скрипичного графика

sns.set(style="darkgrid")fig,axs=plt.subplots(2, 2, figsize=(10,8))sns.histplot(data=daily_dataframe, x="precipitation_sum", kde=True, ax=axs[0,0], color='green')sns.histplot(data=daily_dataframe, x="temperature_2m_max", kde=True, ax=axs[0,1], color='red')

sns.histplot(data=daily_dataframe, x="temperature_2m_min", kde=True, ax=axs[1,0], color='skyblue')sns.histplot(data=daily_dataframe, x="wind_speed_10m_max", kde=True, ax=axs[1,1], color='orange')

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

Максимальная температура кажется имеет легкую положительную ассиметрию, а Минимальная термератруа легкую отрицательную ассиметрию

Выбросов в данных не наблюдается

Посмотрим на корреляции также с помощью Тепловой карты

plt.figure(figsize=(12,7))sns.heatmap(daily_dataframe.drop(columns=['date', 'weather', 'weather_code', 'simple_weather']).corr(), annot=True, cmap='coolwarm')

Можно наблюдать положительную корреляцию между максимальной и минимальной температурами, что достаточно очевидно

Посмотрим на некоторые корреляции более детально при помощи коэффициента корреляции Пирсона и/или t-теста

daily_dataframe.plot("precipitation_sum", "temperature_2m_min", style='o')print("Pearson correlation:", daily_dataframe["precipitation_sum"].corr(daily_dataframe["temperature_2m_min"]))print("T Test and P value:", stats.ttest_ind(daily_dataframe["precipitation_sum"], daily_dataframe["temperature_2m_min"]))

Значение корреляции Пирсона в 0.2 указывает на слабую положительную корреляцию

daily_dataframe.plot("wind_speed_10m_max", "temperature_2m_max", style='o')print("Pearson correlation:", daily_dataframe["wind_speed_10m_max"].corr(daily_dataframe["temperature_2m_max"]))print("T Test and P value:", stats.ttest_ind(daily_dataframe["wind_speed_10m_max"], daily_dataframe["temperature_2m_max"]))

Корреляция Пирсона равна 0.06, что указывает на практически незначительную положительную корреляцию

Подготовка данных для машинного обучения

Для начала проверим наш датасет на нулевые значения

daily_dataframe.isna().sum()

Таковых нет и можно двигаться дальше

Если бы таковые были, то мы могли бы восполнить их каким либо способом, или удалить, например при помощи метода датафрейма .dropna()

Удалим ненужные признаки

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

df = daily_dataframe.drop(['date', 'weather', 'weather_code'], axis=1)df.head()

Преобразуем значения нашего упрощенного признака погоды simple_weather при помощи LabelEncoder в числовые

le = LabelEncoder()df["simple_weather"] = le.fit_transform(df["simple_weather"])df.simple_weather.unique()

Для того что бы преобразовать полученные числовые признаки обратно, можно воспользоваться методом энкодера .inverse_transform

Отделим целевые значения от наших данных и разделим датасет на обучающий и проверочный

x = ((df.loc[:,df.columns!="simple_weather"])).values[:,0:]y = df["simple_weather"].valuesx_train,x_test,y_train,y_test = train_test_split(x, y, test_size=0.1, random_state=2)

Обучение моделей и проверка их точности

В рамках этой работы мы будем использовать следующие модели:

K-Nearest Neighbour(KNN)

Support Vector Machine(SVM)

Gradient Boost

Extreme Gradient Boosting(XGBC)

K-NEAREST NEIGHBOR CLASSIFIER:

knn = KNeighborsClassifier()knn.fit(x_train, y_train)print(f"KNN Accuracy: {round(knn.score(x_test, y_test)*100, 2)}%")

SUPPORT VECTOR MACHINE - CLASSIFIER:

svm = SVC()svm.fit(x_train, y_train)print(f"SVM Accuracy: {round(svm.score(x_test, y_test)*100, 2)}%")

GRADIENT BOOSTING CLASSIFIER:

gbc = GradientBoostingClassifier(subsample=0.5, n_estimators=450, max_depth=5, max_leaf_nodes=25)gbc.fit(x_train, y_train)print(f"Gradient Boosting Accuracy: {round(gbc.score(x_test,y_test)*100, 2)}%")

EXTREME GRADIENT BOOSTING OR XGBCLASSIFIER:

import warningswarnings.filterwarnings('ignore')xgb = XGBClassifier()xgb.fit(x_train, y_train)print(f"XGB Accuracy: {round(xgb.score(x_test, y_test)*100, 2)}%")

Лабораторная работа

В рамках лабораторной работы вам будет необходимо:

Запросить значения по сумме осадков (Precipitation Sum), максимальной, минимальной температур (Maximum Temperature, Minimum Temperature) и скорости ветра (Maximum Wind Speed (10 m)) на текущий день (Forecast days: 1) для Апатит с откыртого API при помощи бибилиотеки requests (requests.get) или другим способом. При этом нас интересуют значения переменных по дням (Daily Weather Variables). Обращаю внимание что по ссылке к API, в разделе "API Response" можно выбрать язык Python и подсмотреть как должен выглядеть запрос для тех параметров что вы выставите там же выше.

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

url = "https://api.open-meteo.com/v1/forecast"params = { # Впишите сюда необходимые параметры запроса }my_data = requests.get(url, params)my_data.json()

# Если все хорошо, код ниже должен получить необходимые данные и вывести ихprecipitation = my_data.json()['daily']['precipitation_sum'][0]temp_max = my_data.json()['daily']['temperature_2m_max'][0]temp_min = my_data.json()['daily']['temperature_2m_min'][0]wind = my_data.json()['daily']['wind_speed_10m_max'][0]print(f"Сумма осадков за сутки: {precipitation}\nТемпература от {temp_min} до {temp_max}\nСкорость ветра до: {wind}")

input = [[temp_max, temp_min, precipitation, wind]]print(f"Погода по API: {wmo_codes[my_data.json()['daily']['weather_code'][0]]}\n")print("Прогнозы наших моделей: ")knn_prediction = knn.predict(input)print(f"KNN: {le.inverse_transform([knn_prediction])[0]}")svm_prediction = svm.predict(input)print(f"SVM: {le.inverse_transform([svm_prediction])[0]}")gbc_prediction = gbc.predict(input)print(f"GBC: {le.inverse_transform([gbc_prediction])[0]}")xgb_prediction = xgb.predict(input)print(f"XGB: {le.inverse_transform([xgb_prediction])[0]}")

_

Лабораторная №2: Анализ данных Титаника

В рамках этого ноутбука мы пройчем через:

1.

Постановку задачи;

2.

Получение данных для обучения и тестирования;

3.

"Выпас данных" (под этим термином обычно понимаюттакие этапы как: очистка данных, приведение данных к одному формату(например, перевод в одинаковые единицы измерения), агрегация данных, нормализация данных, парсинг сложных структур данных (например, DOM-дерева сайтов), соединение разных групп данных по ключу, работа с пропущенными данными, дополнение данных из открытых источников (например, погодных данных));

4.

Анализ, выявление закономерностей и изучение данных;

5.

Моделирование, прогноз и решение проблемы;

(опционально) можно будет посмотреть был ли какой то эффект от всей этой предобработки даннных

Ноутбук основан на Kaggle: Titanic Data Science Solutions

Постановка задачи

Поставим вопрос следующим образом:

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

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

15 апреля 1912 года во время своего первого плавания «Титаник» затонул после столкновения с айсбергом, в результате чего погибли 1502 из 2224 пассажиров и экипажа. Что можно интерпретировать как 32% выживаемость.

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

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

# Импортируем библиотеки# анализ и обработка данныхimport pandas as pdimport numpy as npimport random as rnd# визуализацияimport seaborn as sns

import matplotlib.pyplot as plt%matplotlib inline

Получение данных

Начнем с получения наборов данных для обучения и тестирования в Pandas DataFrames. Мы также объединим эти наборы для совместного выполнения определенных операций с ними.

Данные можно импортировать через сессионное хранилище или Гугл диск

# Замените путь к файлу если он лежит не в корне гугл диска, или в локальном хранилище# Путь к файлу можно копирвоать нажав правой кнопкой по файлу в меню Файлов слеваtest_df = pd.read_csv("/content/titanic_test.csv")train_df = pd.read_csv("/content/titanic_train.csv")combine = [train_df, test_df]

Анализ данных

Pandas также помогает оценить данные, отвечая на следующие вопросы в начале нашего проекта.

Какие признаки присутсвуют в наборе данных?

# Посмотрим на данныеtrain_df.head()

train_df.tail()

print(train_df.columns.values)

'PassengerId' - Айди пасажира,

'Survived' - Выжил ли пассажир,

'Pclass' - Класс пасажира,

'Name' - Имя пасажира,

'Sex' - Пол пасажира,

'Age' - Возраст пасажира,

'SibSp' - Количество братьев и сестер/супругов на борту,

'Parch' - Количество родителей/детей на борту,

'Ticket' - Номер билета,

'Fare' - Стоимость проезда / Тариф,

'Cabin' - Номер каюты,

'Embarked' - Посадка (Порт посадки (C = Cherbourg; Q = Queenstown; S = Southampton))

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

Категориальные: Survived, Sex, and Embarked

Порядковый: Pclass

Какие признаки являются числовыми? Такие значения меняются от образца к образцу. Являются ли значения внутри числовых признаков дискретными, непрерывными или основанными на временных рядах?

Непрерывные: Age, Fare

Дискретные: SibSp, Parch

Какие признаки относятся к смешанным типам данных? Числовые, буквенно-цифровые данные в пределах одного признака.

Ticket представляет собой сочетание числовых и буквенно-цифровых типов данных.

Cabin буквенно-цифровая.

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

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

Какие признаки содержат нулевые или пустые значения? Потребует исправления.

Признаки Cabin, Age, Embarked содержат нулевые значения (для обучающего набора данных)

Признаки Cabin, Age неполные (в случае тестового набора данных)

Каковы типы данных различных признаков? Семь признаков являются целыми числами (int64) или числами с плавающей запятой(float64). Шесть в случае тестового набора данных. Пять признаков — строки(object).

# info() выводит информацию о датафрейме включая типы данных, ненулевые значения и использование им памятиtrain_df.info()print('_'*40)test_df.info()

Каково распределение значений числовых признаков по выборкам? Это поможет нам определить насколько репрезентативным является набор обучающих данных.

Всего выборка содержит 891 человек или 40% от фактического количества пассажиров на борту «Титаника» (2224 человека).

Survived — это категориальный признак со значениями 0 или 1.

Около 38% людей выжили, что соответствует фактической выживаемости в 32%.

Большинство пассажиров (>75%) путешествовали без родителей или детей.

Почти у 30% пассажиров на борту находились братья, сестры и/или супруги.

Стоимость проезда значительно различалась: лишь немногие пассажиры (<1%) платили до 512 долларов.

Мало пожилых пассажиров (<1%) в возрасте 65–80 лет.

# describe дает описательную статистику датафреймаtrain_df.describe(percentiles=[.61, .62])

Каково распределение категориальных признаков?

Имена уникальны во всем наборе данных (count=unique=891).

Переменная пола в виде двух возможных значений с 65% мужчин (top=male, freq=577/count=891).

Значения Cabin имеют несколько дубликатов в выборках. Иначе говоря, несколько пассажиров делили каюту.

Embarked принимает три возможных значения. S для большиснва пассажиров.

Признак Ticket имеет высокий процент (22%) повторяющихся значений (уникальных = 681).

train_df.describe(include=['O'])

Предположения, основанные на оценке данных

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

Корреляция

Мы хотим знать, насколько хорошо каждая функция коррелирует с признаком Survival(выживанием). Мы хотим сделать это на ранних этапах нашего проекта и сопоставить эти "быстрые" корреляции с смоделированными, позже в проекте.

Дополнение

1.

Возможно, мы захотим дополнить значения признака Age, поскольку он определенно связан с выживанием.

2.

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

Исправление

1.

Признак Ticket может быть исключен из нашего анализа, поскольку он содержит высокий процент дубликатов (22%), и корреляция между номером билета и выживанием может отсутствовать.

2.

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

3.

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

4.

Признак Name не может напрямую способствовать выживанию, поэтому его можно исключить.

Создание

1.

Возможно, мы захотим создать новый признак под названием Family на основе Parch и SibSp, чтобы получить общее количество членов семьи на борту.

2.

Возможно, мы захотим обработать признак Name, чтобы извлекать титул как новый признак.

3.

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

4.

Мы также можем захотеть создать признак диапазона Fare(Стоимости проезда), если это поможет нашему анализу.

Классификация Мы также можем добавить к нашим предположениям:

Женщины (Sex=female) имели больше шансов выжить.

Дети (Age<?) имели больше шансов выжить.

Пассажиры высшего класса (Pclass=1) имели больше шансов выжить.

Анализ при помощи изменения точки зрения

Чтобы подтвердить некоторые из наших наблюдений и предположений, мы можем быстро проанализировать корреляции наших признаков, сравнивая их друг с другом. На данном этапе мы можем сделать это только для признаков, которые не имеют нулевых значений. Также имеет смысл делать это только для объектов категориального (Sex), порядкового (Pclass) или дискретного (SibSp, Parch) типа.

train_df[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)

Pclass Мы наблюдаем значительную корреляцию (>0,5) между Pclass=1 и Survived (классификация №3). Мы включим этот признак в нашу модель.

train_df[['Sex', 'Survived']].groupby(['Sex'], as_index=False).mean().sort_values(by='Survived', ascending=False)

Sex Мы подтверждаем наблюдение, сделанное ранее, что женщины имели очень высокую выживаемость - 74%.

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)

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

Анализ посредством визуализации данных

Теперь мы можем продолжить подтверждение некоторых наших предположений, используя визуализации для анализа данных.

Сопоставление числовых характеристик

Давайте начнем с понимания корреляции между числовыми признаками и целью нашей разработки(Survived).

Гистограммы полезны для анализа непрерывных числовых переменных, таких как возраст, где можно визуально выявить полезные закономерности. Гистограмма может отображать распределение выборок с использованием автоматически определяемых интервалов или полос с одинаковым диапазоном. Это поможет нам ответить на вопросы, касающиеся конкретных групп (была ли у младенцев более высокая выживаемость?)

Обратите внимание, что ось X в визуализациях гистограммы представляет количество образцов или пассажиров.

Наблюдения

Младенцы (возраст <= 4) имели высокую выживаемость.

Выжили самые старые пассажиры (возраст = 80).

Большое количество молодых людей в возрасте 15-25 лет не выжило.

Большинство пассажиров находятся в возрасте от 15 до 35 лет.

Решения Этот простой анализ подтверждает наши предположения и решения для дальнейшей работы

Мы должны учитывать возраст при обучении нашей модели.

Дополнить признак Age для нулевых значений.

Нам следует объединить возрастные группы.

g = sns.FacetGrid(train_df, col='Survived')g.map(plt.hist, 'Age', bins=20)

Корреляция числовых и порядковых признаков

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

Наблюдения

Pclass=3 имеет большинство пассажиров, однако большинство из них не выжило. Подтверждает наше классификационное предположение №2.

Младенци из классов Pclass=2 и Pclass=3 в основном выжили. Еще одно пордтверждение нашего классификационного предположения №2.

Большинство пассажиров Pclass=1 выжили. Подтверждает наше классификационное предположение №3.

Pclass варьируется в зависимости от возрастного состава пассажиров.

Решения

Принять во внимание Pclass для обучения моделей.

grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', height=2.2, aspect=1.6)grid.map(plt.hist, 'Age', alpha=.5, bins=20)grid.add_legend();

Корреляция категориальных признаков

Теперь мы можем соотнести категориальные признаки с выживаемостью.

Наблюдения

Пассажиры-женщины имели гораздо большую выживаемость, чем мужчины. Подтверждает выдвинутую ранее гипотезу.

Исключение в Embarked=C, где мужчины имели более высокую выживаемость. Это может быть корреляция между Pclass и Embarked и, в свою очередь, Pclass и Survived, но не обязательно прямая корреляция между Embarked и Survived.

Мужчины имели лучшую выживаемость в Pclass=3 по сравнению с Pclass=2 для портов C и Q.

В портах посадки наблюдаются разные показатели выживаемости пассажиров класса P=3 и пассажиров мужского пола.

Решения.

Добавьте признака пола (sex) в обучение модели.

Дополнить и добавить признак Embarked для обучения модели.

grid = sns.FacetGrid(train_df, row='Embarked', height=2.2, aspect=1.6)grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex', palette='deep', order=[1,2,3], hue_order=['female','male'])grid.add_legend()

Корреляция категориальных и числовых признаков

Мы также можем сопоставить категориальные признаки (с нечисловыми значениями) и числовые признаки. Мы можем рассмотреть возможность корреляции Embarked (категориальный нечисловой показатель), Sex (категориальный нечисловой показатель), Fare (непрерывный числовой показатель) и Survived (категориальный числовой показатель).

Наблюдения

Пассажиры с более высокой стоимостью проезда (Fare) имели лучшую выживаемость. Подтверждает наше предположение о диапазонах стоимостей проезда.

Порт посадки (Embarked) коррелирует с уровнем выживаемости. Подтверждает выдвинутые ранее гипотезы.

Решения.

Рассмотрите возможность объединения признака Fare.

grid = sns.FacetGrid(train_df, row='Embarked', col='Survived', height=2.2, aspect=1.6)grid.map(sns.barplot, 'Sex', 'Fare', alpha=.5, order=['female', 'male'])grid.add_legend()

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

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

Исправление путем удаления признаков

Это хорошая стартовая цель. Отбрасывая признаки, мы имеем дело с меньшим количеством данных. Ускоряя работу нашего блокнота и облегчая анализ.

Основываясь на наших предположениях и решениях, мы хотим отказаться от признаков Cabin и Ticket.

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

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]print("After", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)

Before (891, 12) (418, 11) (891, 12) (418, 11)After (891, 10) (418, 9) (891, 10) (418, 9)

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

Мы хотим проанализировать, можно ли разобрать признак Name для извлечения титулов и проверить корреляцию между ними и выживаемостью, прежде чем отказываться от признака Name и PassengerId.

В следующем блоке кода мы извлекаем признак Title с помощью регулярных выражений. Шаблон RegEx (\w+\.) соответствует первому слову, оканчивающемуся точкой, в признаке имени. Флаг expand=False возвращает DataFrame.

Наблюдения Когда мы строим график Титул, Возраст и Выжившие, мы можем отметить следующее.

Большинство титулов точно соответствуют возрастным группам. Например: Среднее значение титула Master составляет 5 лет.

Выживаемость среди групп титулованного возраста незначительно различается.

Некоторые титулы в основном выжили (Mme, Lady, Sir) или не выжили (Don, Rev, Jonkheer).

Решение

Мы решили сохранить новый признак Title для обучения моделей.

for dataset in combine: dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False)pd.crosstab(train_df['Title'], train_df['Sex'])

Мы можем заменить многие титулы более распространенным именем или отнести их к редким (Rare).

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', 'Miss') dataset['Title'] = dataset['Title'].replace('Ms', 'Miss') dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')train_df[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()

Мы можем преобразовать категориальные титулы в порядковые.

# fillna(0) заполняет все пустые значения(None) нулями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()

Теперь мы можем безопасно исключить признак Name из наборов данных обучения и тестирования. Нам также более не нужен признак PassengerId в наборе обучающих данных.

train_df = train_df.drop(['Name', 'PassengerId'], axis=1)test_df = test_df.drop(['Name'], axis=1)combine = [train_df, test_df]train_df.shape, test_df.shape

Преобразование категориальных признаков

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

Давайте начнем с преобразования признака Sex в новый под названием Gender, где женщина = 1 и мужчина = 0.

for dataset in combine: dataset['Sex'] = dataset['Sex'].map( {'female': 1, 'male': 0} ).astype(int)train_df.head()

Дополнение числовых непрерывных признаков

Теперь нам следует оценить и дополнить признаки с отсутствующими или нулевыми значениями. Сначала мы сделаем это для признака Age.

Мы можем рассмотреть три метода дополнения числовых непрерывных признаков.

1.

— Простойспособсгенерироватьслучайныечисламеждусредним значениеми стандартнымотклонением.

2.

— Болееточныйспособугадатьпропущенныезначения . использоватьдругиекоррелирующиепризнакиВнашемслучаемы Age, Gender, Pclass. заметиликорреляциюмеждуиУгадатьзначения, возрастаиспользуязначениямедианы длявозрастапонаборам Pclass Gender. , комбинацийпризнакаиИтаксреднийвозрастдляPclass=1 Gender=0, Pclass=1 Gender=1 ...ииитакдалее

3.

1 2. , , ОбъединитьметодыиТакимобразомвместотогочтобы , угадыватьзначениявозрастанаосновемедианыбудем использоватьслучайныечисламеждусреднимистандартным Pclass Gender.отклонениемнаосновенаборовкомбинацийи

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

grid = sns.FacetGrid(train_df, row='Pclass', col='Sex', height=2.2, aspect=1.6)grid.map(plt.hist, 'Age', alpha=.5, bins=20)grid.add_legend()

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

guess_ages = np.zeros((2,3))guess_ages

Теперь мы перебираем Gender (0 или 1) и Pclass (1, 2, 3), чтобы вычислить предполагаемые значения возраста для шести комбинаций.

for dataset in combine: 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_guess = guess_df.median() # Convert random age float to nearest .5 age guess_ages[i,j] = int( age_guess/0.5 + 0.5 ) * 0.5 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()

Давайте создадим возрастные группы и определим корреляцию с выживанием.

train_df['AgeBand'] = pd.cut(train_df['Age'], 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']train_df.head()

Мы теперь можем удалить признак AgeBand.

train_df = train_df.drop(['AgeBand'], axis=1)combine = [train_df, test_df]train_df.head()

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

Мы можем создать новый признак для FamilySize, который сочетает в себе Parch и SibSp. Это позволит нам исключить Parch и SibSp из наших наборов данных.

for dataset in combine: dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1train_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'] = 1train_df[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()

Давайте откажемся от признаков Parch, SibSp и FamilySize в пользу IsAlone.

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()

Мы также можем создать искусственный признак, сочетающий Pclass и Age.

for dataset in combine: dataset['Age*Class'] = dataset.Age * dataset.Pclasstrain_df.loc[:, ['Age*Class', 'Age', 'Pclass']].head(10)

Дополнение категориальных признаков

Признак Embarked принимает значения S, Q, C в зависимости от порта посадки. В нашем наборе обучающих данных есть два пропущенных значения. Мы просто заполняем их наиболее распространенными значениями.

freq_port = train_df.Embarked.dropna().mode()[0]freq_port

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)

Преобразование категориальных признаков в числовые

Теперь мы можем преобразовать признак EmbarkedFill, создав новую числовой признак порта.

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()

Теперь мы моженм создать FareBand.

train_df['FareBand'] = pd.qcut(train_df['Fare'], 4)train_df[['FareBand', 'Survived']].groupby(['FareBand'],

as_index=False, observed=False).mean().sort_values(by='FareBand', ascending=True)

Преобразуем признак Fare в порядковые значения на основе FareBand.

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]print(train_df.head(10))print(test_df.head(10))

Моделируйте, прогнозируйте и решайте

Теперь мы готовы обучить модель и спрогнозировать требуемое решение. На выбор предлагается более 60 алгоритмов прогнозирования. Мы должны понимать тип проблемы и требования к решению, чтобы сузить круг до нескольких избранных моделей, которые мы можем оценить. Наша проблема — это проблема классификации и регрессии. Мы хотим определить взаимосвязь между результатами (выжили или нет) с другими переменными или признаками (пол, возраст, порт...). Мы также применяем категорию машинного обучения, которая называется обучением с учителем, поскольку мы обучаем нашу модель с заданным набором данных. Используя эти два критерия — обучение с учителем плюс классификация и регрессия — мы можем сузить выбор моделей до нескольких. К ним относятся:

Логистическая регрессия

KNN или k-ближайших соседей

Метод опорных векторов

Наивный байесовский классификатор

Персептрон

Древо решений

Метод случайного леса

Искусственная нейронная сеть

RVM или Метод релевантных векторов

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

Логистическая регрессия — это метод анализа данных, который использует математику для поиска взаимосвязей между двумя факторами данных. Затем эта взаимосвязь используется для прогнозирования значения одного из этих факторов на основе другого. Предсказание обычно имеет конечное количество результатов, например «да» или «нет».

Habr: Как легко понять логистическую регрессию

sklearn LogisticRegression

# Пример обучения модели для лаболаторной работы# Logistic Regressionfrom sklearn.linear_model import LogisticRegressionlogreg = LogisticRegression()logreg.fit(X_train, Y_train)acc_log = round(logreg.score(X_train, Y_train) * 100, 2)acc_log

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

Положительные коэффициенты увеличивают логарифмические шансы ответа (и, таким образом, увеличивают вероятность), а отрицательные коэффициенты уменьшают логарифмические шансы ответа (и, таким образом, уменьшают вероятность).

Sex является наивысшим положительным коэффициентом, что означает, что по мере увеличения значения пола (от мужчины: 0 до женщины: 1) вероятность Survived = 1 увеличивается больше всего.

И наоборот, по мере увеличения Pclass вероятность Survived=1 снижается больше всего.

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

Как и Title, второй по величине положительной корреляции.

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)

Лабораторная работа

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

Модели на выбор:

Классификатор методом k-ближайших соседей

Классификатор методом опорных векторов

Наивный байесовский классификатор

Перцептрон

Дерево принятия решений

Случайные леса или леса случайных решений

Стохастический градиентный спуск

Опицонально можете поиграться с параметрами моделей для достижения лучшего результата.

Метод k-ближайших соседей (англ. k-nearest neighbors algorithm, k-NN) — метрический алгоритм для автоматической классификации объектов или регрессии. В случае использования метода для классификации объект присваивается тому классу, который является наиболее распространённым среди k соседей данного элемента, классы которых уже известны. В случае использования метода для регрессии, объекту присваивается среднее значение по k ближайшим к нему объектам, значения которых уже известны. Алгоритм может быть применим к выборкам с большим количеством атрибутов (многомерным). Для этого перед применением нужно определить функцию расстояния; классический вариант такой функции — евклидова метрика.

Habr: Классификатор kNN

sklearn KNeighborsClassifier

# k-nearest neighborsfrom sklearn.neighbors import KNeighborsClassifier

Метод опорных векторов (англ. support vector machine, SVM) — один из наиболее популярных методов обучения, который применяется для решения задач классификации и регрессии. Основная идея метода заключается в построении гиперплоскости, разделяющей объекты выборки оптимальным способом. Алгоритм работает в предположении, что чем больше расстояние (зазор) между разделяющей гиперплоскостью и объектами разделяемых классов, тем меньше будет средняя ошибка классификатора.

Habr: Классификация данных методом опорных векторов

sklearn SVC (C-Support Vector Classification)

# Support Vector Machinesfrom sklearn.svm import SVC

Наивный байесовский классификатор — простой вероятностный классификатор, основанный на применении теоремы Байеса со строгими (наивными) предположениями о независимости. Другими словами, алгоритм предполагает, что наличие какого-либо признака в классе не связано с наличием какого-либо другого признака.

Habr: Наивный Байес, или о том, как математика позволяет фильтровать спам

sklearn GaussianNB

# Gaussian Naive Bayesfrom sklearn.naive_bayes import GaussianNB

Перцептрон (англ. Perceptron) — простейший вид нейронных сетей. В основе лежит математическая модель восприятия информации мозгом, состоящая из сенсоров, ассоциативных и реагирующих элементов. Перцептрон состоит из трёх типов элементов, а именно: поступающие от датчиков сигналы передаются ассоциативным элементам, а затем — реагирующим элементам. Таким образом, перцептроны позволяют создать набор «ассоциаций» между входными стимулами и необходимой реакцией на выходе. В биологическом плане это соответствует преобразованию, например, зрительной информации в физиологический ответ от двигательных нейронов.

Habr: Машинное обучение. Нейронные сети (часть 1): Процесс обучения персептрона

sklearn Perceptron

# Perceptronfrom sklearn.linear_model import Perceptron

Дерево принятия решений (также называют деревом классификации или регрессионным деревом) — средство поддержки принятия решений, использующееся в машинном обучении, анализе данных и статистике. Структура дерева представляет собой «листья» и «ветки». На рёбрах («ветках») дерева решения записаны признаки, от которых зависит целевая функция, в «листьях» записаны значения целевой функции, а в остальных узлах — признаки, по которым различаются случаи. Чтобы классифицировать новый случай, надо спуститься по дереву до листа и выдать соответствующее значение.

Habr: Напишем и поймем Decision Tree на Python с нуля! Часть 1. Краткий обзор

sklearn DecisionTreeClassifier

# Decision Treefrom sklearn.tree import DecisionTreeClassifier

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

Habr: Random Forest: прогулки по зимнему лесу

sklearn RandomForestClassifier

# Random Forestfrom sklearn.ensemble import RandomForestClassifier

Стохастический градиентный спуск (SGD) — это простой, но очень эффективный подход к подгонке линейных классификаторов и регрессоров под выпуклые функции потерь, такие как (линейные) Метод опорных векторов и логистическая регрессия. Строго говоря, SGD — это просто метод оптимизации и не соответствует конкретному семейству моделей машинного обучения. Это всего лишь способ обучить модель.

sklearn SGDClassifier

# Stochastic Gradient Descentfrom sklearn.linear_model import SGDClassifier

Выведите результаты проверки точности моделей, выделив наилучший результат

Вам подходит эта работа?
Похожие работы
Другие работы автора
Прямой эфир