117 KiB
Лабораторная работа 2
- Цены на телефоны https://www.kaggle.com/datasets/mayankanand2701/starbucks-stock-price-dataset
- Цены на машины https://www.kaggle.com/datasets/nancyalaswad90/yamana-gold-inc-stock-price
- Цены на дома в Бостоне https://www.kaggle.com/datasets/arunjangir245/boston-housing-dataset
Датасет 1. Цены мобильных телефонов
- Name: Название модели мобильного телефона.
- Rating: Рейтинг мобильного телефона (по отзывам пользователей).
- Spec_score: Оценка спецификаций телефона (возможно, по различным характеристикам).
- No_of_sim: Количество SIM-карт, поддерживаемых телефоном.
- Ram: Объем оперативной памяти (RAM) в гигабайтах.
- Battery: Емкость батареи в мАч.
- Display: Размер дисплея в дюймах.
- Camera: Разрешение камеры (в мегапикселях).
- External_Memory: Поддержка внешней памяти (да/нет).
- Android_version: Версия операционной системы Android.
- Price: Цена мобильного телефона в долларах США.
- Company: Производитель телефона.
- Inbuilt_memory: Объем встроенной памяти (в гигабайтах).
- Fast_charging: Наличие быстрой зарядки (да/нет).
- Screen_resolution: Разрешение экрана (в пикселях).
- Processor: Тип процессора.
- Processor_name: Наименование процессора.
Объект наблюдения: Каждый объект представляет собой отдельный мобильный телефон.
Связи между объектами: Внутри одного объекта есть взаимосвязь между характеристиками и его ценой. Например, объем оперативной памяти, емкость батареи, качество камеры и поддержка быстрой зарядки могут влиять на цену.
Бизнес-цель: Оптимизация продаж мобильных телефонов, оценка цен в зависимости от характеристик.
Эффект для бизнеса: Более точная оценка стоимости мобильных телефонов может помочь производителям и ритейлерам предлагать конкурентоспособные цены и максимизировать прибыль.
Техническая цель: Построение модели машинного обучения для прогнозирования цены мобильного телефона на основе его характеристик.
- Вход: Характеристики мобильного телефона (объем RAM, емкость батареи, качество камеры и т.д.).
- Целевой признак: Цена мобильного телефона.
Информативность: Высокая. Набор данных содержит важные характеристики мобильных телефонов, которые влияют на их цену.
Степень покрытия: Высокая. Датасет включает разнообразные модели телефонов, что позволяет провести полноценный анализ.
Соответствие реальным данным: Высокая. Характеристики мобильных телефонов в наборе данных соответствуют реальным характеристикам, определяемым производителями.
Согласованность меток: Высокая. Датасет не содержит проблем с несогласованностью меток, так как все данные соответствуют описанию в заголовках столбцов.
Датасет 2. Прогнозирование цен на автомобили
- make: Производитель автомобиля.
- model: Модель автомобиля.
- year: Год выпуска автомобиля.
- mileage: Пробег автомобиля в километрах.
- engine_size: Объем двигателя в литрах.
- horsepower: Мощность двигателя в лошадиных силах.
- fuel_type: Тип топлива (бензин, дизель и др.).
- transmission: Тип трансмиссии (механическая или автоматическая).
- color: Цвет автомобиля.
- body_type: Тип кузова (седан, хэтчбек, внедорожник и др.).
- price: Цена автомобиля в долларах США.
Объект наблюдения: Каждый объект представляет собой отдельный автомобиль.
Связи между объектами: Внутри одного объекта есть взаимосвязь между характеристиками и его ценой. Например, год выпуска, пробег и мощность двигателя могут влиять на цену автомобиля.
Бизнес-цель: Оптимизация продаж автомобилей, оценка цен в зависимости от характеристик.
Эффект для бизнеса: Более точная оценка стоимости автомобилей может помочь дилерам и производителям предлагать конкурентоспособные цены и максимизировать прибыль.
Техническая цель: Построение модели машинного обучения для прогнозирования цены автомобиля на основе его характеристик.
- Вход: Характеристики автомобиля (год выпуска, пробег, объем двигателя и др.).
- Целевой признак: Цена автомобиля.
Датасет 3. Прогнозирование цен на жилье в Бостоне
- crim: Уровень преступности на душу населения по городам.
- zn: Доля крупных жилых участков (более 25,000 кв. футов).
- indus: Доля не розничных бизнес-акров на город.
- Chas: Двоичный признак, указывающий, находится ли объект рядом с рекой Чарльз (1 — да, 0 — нет).
- nox: Концентрация оксидов азота в воздухе.
- rm: Среднее количество комнат в одном жилом доме.
- age: Доля старых жилых единиц, построенных до 1940 года.
- dis: Взвешенные расстояния до рабочих центров Бостона.
- rad: Индекс доступности радиальных шоссе.
- tax: Налог на недвижимость на сумму $10,000.
Объект наблюдения: Каждый объект представляет собой отдельный дом или квартиру.
Связи между объектами: Внутри одного объекта есть взаимосвязь между характеристиками, такими как уровень преступности, количество комнат и налоги, которые могут влиять на цену жилья.
Бизнес-цель: Оценка стоимости недвижимости для покупателей и продавцов, а также для инвесторов в недвижимость.
Эффект для бизнеса: Более точная оценка цен на жилье может помочь улучшить принятие решений при покупке и продаже недвижимости.
Техническая цель: Построение модели машинного обучения для прогнозирования цен на жилье в Бостоне на основе его характеристик.
- Вход: Характеристики жилья (уровень преступности, количество комнат, налоги и др.).
- Целевой признак: Цена жилья.
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from imblearn.under_sampling import RandomUnderSampler
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv(
"data/boston_housing.csv"
)
# Проверка на пропуски и "зашумленные" столбцы (если процент пустых значений больше 10%)
noisy_features = [] # Список для хранения столбцов с большим количеством пропусков
for col in df.columns: # Проходим по каждому столбцу
if (
df[col].isnull().sum() / len(df) > 0.1
): # Проверяем, если доля пропусков больше 10%
noisy_features.append(col) # Добавляем столбец в список
# Проверка на смещение (относительно нормального распределения)
skewness = df.select_dtypes(
include=[np.number]
).skew() # Вычисляем коэффициент смещения для числовых столбцов
skewed_features = skewness[
abs(skewness) > 1
].index.tolist() # Находим сильно смещенные столбцы
# Поиск выбросов (сильно отличающиеся значения)
for col in df.select_dtypes(
include=["number"]
).columns: # Проходим по числовым столбцам
Q1 = df[col].quantile(0.25) # Находим первый квартиль (значение, ниже которого 25% данных)
Q3 = df[col].quantile(
0.75
) # Находим третий квартиль (значение, ниже которого 75% данных)
IQR = Q3 - Q1 # Вычисляем интерквартильный размах
lower_bound = Q1 - 1.5 * IQR # Вычисляем нижнюю границу
upper_bound = Q3 + 1.5 * IQR # Вычисляем верхнюю границу
outliers = df[col][
(df[col] < lower_bound) | (df[col] > upper_bound)
] # Находим выбросы
print(f"Выбросы в столбце '{col}':\n{outliers}\n") # Выводим выбросы
# Визуализация выбросов
numeric_cols = df.select_dtypes(
include=["number"]
).columns # Получаем список числовых столбцов
plt.figure(figsize=(12, 8)) # Устанавливаем размер графика
for i, col in enumerate(
numeric_cols, 1
): # Проходим по числовым столбцам для построения графиков
plt.subplot(
len(numeric_cols) // 3 + 1, 3, i
) # Создаем подграфик для каждого столбца
sns.boxplot(data=df, x=col) # Строим боксплот для столбца
plt.title(f"Boxplot for {col}") # Устанавливаем заголовок для подграфик
plt.tight_layout() # Упорядочиваем графики
plt.show() # Отображаем графики
# Проверка на корреляцию (насколько одна переменная изменится (и зависит) от изменения другой) между признаками
if len(df.columns) >= 2: # Проверяем, что в датасете более одного столбца
for col1 in df.columns: # Проходим по всем столбцам
for col2 in df.columns: # Сравниваем с каждым другим столбцом
if col1 != col2: # Проверяем, что это разные столбцы
correlation = df[col1].corr(df[col2]) # Вычисляем корреляцию
if abs(correlation) > 0.9: # Проверяем, превышает ли корреляция 0.9
print(
f"Просачивание данных: Высокая корреляция ({correlation:.2f}) между столбцами '{col1}' и '{col2}'"
) # Выводим информацию о высокой корреляции
# Функция для разбиения на train/val/test
def split_stratified_into_train_val_test(
df_input,
stratify_colname="y",
frac_train=0.6,
frac_val=0.15,
frac_test=0.25,
random_state=None,
):
if frac_train + frac_val + frac_test != 1.0: # Проверяем, что доли составляют 1
raise ValueError(
"fractions %f, %f, %f do not add up to 1.0"
% (frac_train, frac_val, frac_test)
) # Генерируем ошибку, если это не так
if (
stratify_colname not in df_input.columns
): # Проверяем, есть ли колонка для стратификации
raise ValueError(
"%s is not a column in the dataframe" % (stratify_colname)
) # Генерируем ошибку, если колонки нет
X = df_input # Храним все данные
y = df_input[[stratify_colname]] # Храним целевую переменную
df_train, df_temp, y_train, y_temp = (
train_test_split( # Разбиваем данные на обучающие и временные
X, y, stratify=y, test_size=(1.0 - frac_train), random_state=random_state
)
)
relative_frac_test = frac_test / (
frac_val + frac_test
) # Вычисляем относительную долю тестового набора
df_val, df_test, y_val, y_test = (
train_test_split( # Разбиваем временные данные на валидационные и тестовые
df_temp,
y_temp,
stratify=y_temp,
test_size=relative_frac_test,
random_state=random_state,
)
)
assert len(df_input) == len(df_train) + len(df_val) + len(
df_test
) # Проверяем, что все данные были распределены
return df_train, df_val, df_test # Возвращаем разбитые данные
# целевой признак 'tax'
df["tax_binned"] = pd.cut( # Разбиваем значения 'tax' на категории
df["tax"],
bins=[0, 200, 400, 600, 800, 1000],
labels=["Very Low", "Low", "Medium", "High", "Very High"],
)
df = df.dropna() # Удаляем строки с пропусками
# Разделение данных
df_train, df_val, df_test = (
split_stratified_into_train_val_test( # Разбиваем данные на обучающие, валидационные и тестовые
df,
stratify_colname="tax_binned",
frac_train=0.60,
frac_val=0.20,
frac_test=0.20,
)
)
# Выводим размеры разбитых выборок
print("Обучающая выборка: ", df_train.shape)
print("Контрольная выборка: ", df_val.shape)
print("Тестовая выборка: ", df_test.shape)
# Уравнивание данных для обучения модели
# Подход с Random Under Sampler
rus = RandomUnderSampler(
random_state=42
) # Инициализируем метод уменьшения дисбаланса классов
X_resampled, y_resampled = rus.fit_resample(
df_train, df_train["tax_binned"]
) # Применяем undersampling
print(df_train.tax_binned.value_counts())
df_train_rus = pd.DataFrame(X_resampled) # Сохраняем результат в новый DataFrame
print(
"Обучающая выборка после undersampling: ", df_train_rus.shape
) # Выводим размеры новой обучающей выборки
print(
df_train_rus.tax_binned.value_counts()
) # Выводим количество классов в новой обучающей выборке