2.3 MiB
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Первый датафрейм о бриллиантах
df = pd.read_csv(".//static//csv//diamonds_prices2022.csv")
print(df.columns)
print()
df.info()
Описание набора: В этом наборе данных представлен датасет о ценах на бриллианты. Рассматривается набор данных, содержащий цены и атрибуты примерно для 54 000 бриллиантов круглой огранки. В наборе данных 53 940 бриллиантов с 10 характеристиками (карат, огранка, цвет, прозрачность, глубина, таблица, цена, x, y и z). Большинство переменных являются числовыми по своей природе, но переменные cut, color и clearity являются упорядоченными факторными переменными со следующими уровнями. О валюте для столбца price: это цена ($). Что касается столбцов x, y и z, то они представляют собой размеры алмаза в виде (( x: длина в мм, y: ширина в мм, z: глубина в мм))
# Для наглядности
df.head()
# Описание данных (основные статистические показатели)
df.describe()
# Процент пропущенных значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f'{i} Процент пустых значений: %{null_rate:.2f}')
# Проверка на пропущенные данные
df.isnull().sum()
df.isnull().any()
Пропущенных данных в колонках нет :)
Анализ сведений о наборе данных¶
Набор данных: Набор данных содержит 53 940 наблюдений, каждое из которых представляет собой бриллиант с характеристиками, такими как вес (карат), огранка, цвет, прозрачность, глубина, размеры (x, y, z), а также цена.
Проблемная область: Проблемной областью может быть задача оценки стоимости бриллианта на основе его характеристик, что важно для торговли бриллиантами, определения их рыночной стоимости и других бизнес-задач.
Проанализируем содержимое...
Объекты наблюдения: Каждый бриллиант будет объектом наблюдения.
Атрибуты объектов: Основные атрибуты представляют собой числовые характеристики такие, как carat (вес), depth (глубина в бриллианте - расстояние от площадки до каллеты. Калетта - нижняя часть бриллианта), table (площадка - большая грань бриллианта), x,y,z - размеры. Категориальные характеристики такие, как cut (огранка), color (цвет) и clarity (прозрачность).
Связи между объектами: Вес бриллианта влияет на цену (carat -> price), также существует связь между качеством огранки и ценой (cut -> price)
Бизнес-цель¶
- Автоматизация процесса оценки стоимости бриллианта
Построить модель для оценки цены бриллианты на основе его характеристик. Эффект для бизнеса от анализа данных заключается в улучшении бизнес-процессов (повышение эффективности операционных процессов), повышении доходов, сокращении затрат и улучшению клиентских отношений. - Оптимизация ассортимента и продаж
Построить модель для анализа данных, какие характеристики бриллиантов наиболее востребованы и наилучшим образом влияют на рост продаж. Эффект для бизнеса в том, что компании могут оптимизировать ассортимент на более востребованные, что приведёт к увеличению продаж.
Техническая цель¶
- Разработка модели для оценки стоимости бриллиантов
Создать модель машинного обучения, которая на вход получает характеристики бриллианта (вес, огранка, цвет и т.д.) и предсказывает его цену. На вход поступают характеристики, а целевой признак - цена бриллианта. - Оптимизация ассортимента и прогнозирование спроса
Создать модель для предсказания спроса (популярности) определённых категорий бриллиаантов в зависимости от их характеристик. НА вход поступают характеристики бриллианта, а целевой признак - показатели продаж или востребованность товара.
# Построим графики boxplot для обнаружения выбросов
plt.figure(figsize=(20, 15))
# Создание boxplot
for i, column in enumerate(['carat', 'depth', 'table', 'price'], 1):
plt.subplot(4, 2, i)
sns.boxplot(x=df[column])
plt.title(f"Boxplot для {column}")
plt.tight_layout()
plt.show()
Проблемы наборов¶
Зашумленность данных: Может быть обнаружена через большое количество выбросов (аномальных значений). Выбросы могут выходить за нормальные границы. Они наблюдаются во всех графиках, которые мы построили. Если у определённого параметра много выбросов, то данные могут быть зашумлены или содержат необычные значения, которые стоит анализировать и, возможно, удалить или скорректировать. Графики boxplot помогают визуализировать распределение данных и выявить выбросы, которые находятся за пределами "усов" боксплота.
Попробуем решить устранить проблему выбросов для table и depth. Используется метод усреднения данных для устранения выбросов. Метод стандартных отклонений.
# Вычисление среднего и стандартного отклонения для столбцов
means = df[['carat', 'depth', 'table']].mean()
std_devs = df[['carat', 'depth', 'table']].std()
# Определение порога для выбросов (например, 3 стандартных отклонения)
threshold = 3
# Функция для замены выбросов на среднее значение
def replace_outliers_with_mean(column):
mean_value = column.mean()
upper_limit = mean_value + threshold * column.std()
lower_limit = mean_value - threshold * column.std()
return column.where((column >= lower_limit) & (column <= upper_limit), mean_value)
# Применение функции к каждому столбцу
for column in ['depth', 'table', 'carat']:
df[column] = replace_outliers_with_mean(df[column])
# Графическое отображение после замены выбросов
plt.figure(figsize=(20, 15))
for i, column in enumerate(['carat', 'depth', 'table'], 1):
plt.subplot(4, 2, i)
sns.boxplot(x=df[column])
plt.title(f"Boxplot для {column} после замены выбросов на среднее значение")
plt.tight_layout()
plt.show()
Этот подход позволяет вам обрабатывать выбросы, не прибегая к квантилям и он наверяка избавит от выбросов. Однако стоит отметить, что использование стандартных отклонений может не всегда быть оптимальным для всех распределений данных, потому что данные могут быть плохо распределены. А использование медианы с квантилями вместо среднего значения помогает лучше справиться с выбросами, особенно если распределение данных имеет сильные отклонения.
# Вычисление квантилей для каждого столбца
Q1 = df[['carat', 'depth', 'table']].quantile(0.01)
Q3 = df[['carat', 'depth', 'table']].quantile(0.99)
IQR = Q3 - Q1
# Определение границ для выбросов
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Функция для замены выбросов на медианное значение
def replace_outliers_with_median(column):
median_value = column.median()
return column.where((column >= lower_bound[column.name]) & (column <= upper_bound[column.name]), median_value)
# Применение функции к каждому столбцу
for column in ['depth', 'table', 'carat']:
df[column] = replace_outliers_with_median(df[column])
# Графическое отображение после замены выбросов
plt.figure(figsize=(20, 15))
for i, column in enumerate(['carat', 'depth', 'table'], 1):
plt.subplot(4, 2, i)
sns.boxplot(x=df[column])
plt.title(f"Boxplot для {column} после замены выбросов на медиану")
plt.tight_layout()
plt.show()
Актуальность данных — это проблема, которая возникает, когда данные устарели или больше не отражают текущую ситуацию. Это часто встречается в данных о ценах.
Просачивание данных происходит, когда в обучающей выборке присутствует информация, которая не должна быть известна модели на этапе обучения. В данном случае это может происходить, если некоторые переменные, такие как цена, сильно коррелируют с целевым признаком и тем самым искажают результат. Проверка на наличие утечек данных.
Смещение в данных может возникать, если датасет не полностью репрезентативен для реальной популяции бриллиантов. Например, если в датасете больше дешёвых или дорогих бриллиантов, это создаёт смещение в оценке моделей
Код ниже проверяет данные на распредение признаков и просачивание данных.
# Проверка распределения признаков
plt.figure(figsize=(15, 10))
for i, column in enumerate(['price', 'cut'], 1):
plt.subplot(3, 1, i)
sns.histplot(df[column], bins=20, kde=True)
plt.title(f"Распределение {column}")
plt.tight_layout()
plt.show()
# Средняя цена по типу огранки (cut)
cut_price_mean = df.groupby('cut')['price'].mean().sort_values()
plt.figure(figsize=(10, 6))
sns.barplot(x=cut_price_mean.index, y=cut_price_mean.values)
plt.title("Средняя цена по типу огранки (cut)")
plt.xlabel("Огранка")
plt.ylabel("Средняя цена")
plt.show()
Для решения проблем с просачиваниям, проведём корелляционый анализ между признаками и целевым признаком.
from sklearn.model_selection import train_test_split
# Преобразуем все категориальные данные в числовые
# Проверим, какие столбцы являются категориальными
categorical_columns = df.select_dtypes(include=['object']).columns
# Применяем one-hot encoding к категориальным столбцам
df_encoded = pd.get_dummies(df, columns=categorical_columns, drop_first=True)
# Вычисляем корреляцию для преобразованных данных
correlations = df_encoded.corr()['price'].sort_values(ascending=False)
print("Корреляция признаков с ценой (price):")
print(correlations)
# Визуализация распределения цены (price)
plt.figure(figsize=(10, 6))
sns.histplot(df['price'], bins=30, kde=True)
plt.title('Распределение цены (price)')
plt.xlabel('Цена')
plt.ylabel('Количество')
plt.show()
# Разделение данных на обучающую и тестовую выборки
X = df_encoded.drop('price', axis=1)
y = df_encoded['price']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=df['cut'])
# Проверка на наличие дубликатов
duplicates = df.duplicated().sum()
print(f"Количество дубликатов: {duplicates}")
# Проверим, какие столбцы являются категориальными
categorical_columns = X.select_dtypes(include=['object']).columns
# Применяем one-hot encoding к категориальным столбцам
X_encoded = pd.get_dummies(X, columns=categorical_columns, drop_first=True)
# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=42, stratify=df['cut'])
# Визуализация распределений признаков
def visualize_distribution(X_train, X_test, feature):
plt.figure(figsize=(12, 6))
sns.histplot(X_train[feature], bins=30, color='blue', label='Train', kde=True)
sns.histplot(X_test[feature], bins=30, color='red', label='Test', kde=True)
plt.title(f'Распределение {feature} в обучающей и тестовой выборках')
plt.xlabel(feature)
plt.ylabel('Количество')
plt.legend()
plt.show()
# Распределение для каждого из признаков
for feature in X_encoded.columns:
visualize_distribution(X_train, X_test, feature)
# Проверка корреляции
correlations = X_train.corr()
print("Корреляция признаков в обучающей выборке:")
print(correlations)
# Преобразование категориальных данных в числовые
df_encoded = pd.get_dummies(df, columns=['cut'], drop_first=True)
# Разделение данных на обучающую и тестовую выборки
X = df_encoded.drop('price', axis=1)
y = df_encoded['price']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Оценка выборок и Аугментация данных¶
# Проверка сбалансированности целевой переменной в обучающей выборке
cut_counts_train = y_train.value_counts()
cut_counts_test = y_test.value_counts()
print("Сбалансированность в обучающей выборке:")
print(cut_counts_train)
print("\nСбалансированность в тестовой выборке:")
print(cut_counts_test)
После того как мы оценили сбалансированность, можем решить, нужно ли использовать методы аугментации данных. Например, если одна из категорий в 'cut' значительно меньше других, это может потребовать применения oversampling или undersampling.
# Проверка на наличие дубликатов
duplicates = df.duplicated().sum()
print(f"Количество дубликатов: {duplicates}")
# Преобразуем все категориальные данные в числовые
categorical_columns = df.select_dtypes(include=['object']).columns
df_encoded = pd.get_dummies(df, columns=categorical_columns, drop_first=True)
# Разделение данных на обучающую и тестовую выборки
X = df_encoded.drop('price', axis=1)
y = df_encoded['price']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=df['cut'])
# Проверка сбалансированности целевой переменной
class_counts = y_train.value_counts()
print("Распределение классов в обучающей выборке:")
print(class_counts)
# Фильтрация классов с недостаточным количеством образцов
# Установим минимальное количество образцов, чтобы сохранить класс
min_samples = 2
classes_to_keep = class_counts[class_counts >= min_samples].index
X_train_filtered = X_train[y_train.isin(classes_to_keep)]
y_train_filtered = y_train[y_train.isin(classes_to_keep)]
# Применение SMOTE или RandomOverSampler
from imblearn.over_sampling import SMOTE, RandomOverSampler
# Используем SMOTE, если классов достаточно
if y_train_filtered.value_counts().min() > 1:
smote = SMOTE(random_state=42, k_neighbors=1)
X_resampled, y_resampled = smote.fit_resample(X_train_filtered, y_train_filtered)
else:
# Или RandomOverSampler
ros = RandomOverSampler(random_state=42)
X_resampled, y_resampled = ros.fit_resample(X_train_filtered, y_train_filtered)
# Проверка сбалансированности после oversampling
resampled_counts = y_resampled.value_counts()
print("\nСбалансированность после oversampling:")
print(resampled_counts)
Итог произвели балансировку данных. Использовались методы oversampling (увеличение данных недопредставленных категорий) и методы SMOTE. Произвелась аугментация данных (создавались дополительные данные из имеющихся). Использование методов, таких как SMOTE или RandomOverSampler, помогло увеличить количество экземпляров редких классов в обучающей выборке, что повысило шансы модели правильно классифицировать их.
2 Датасет: Цены на ноутбуки¶
Выгрузили второй датасет! (цены ноутбуки)
df = pd.read_csv(".//static//csv//laptop_prices.csv")
print(df.columns)
print()
df.info()
Датасет: Цена ноутбука. Прайс-лист компании-производителя ноутбуков для регрессии
Kaggle предоставляет следующие данные о датасете: Компания — производитель ноутбуков, Продукт — бренд и модель, Название типа — тип (ноутбук,ультрабук, игровой и т. д.), Дюймы — размер экрана, Разрешение экрана — разрешение экрана, Процессор — центральный процессор (ЦП), Оперативная память — оперативная память ноутбука, Память — жёсткий диск / SSD-накопитель, GPU — графические процессоры (GPU), OpSys — операционная система, Вес — вес ноутбука, Цена_в_евро — цена (в евро)
Объекты наблюдения: Каждый объект наблюдения в наборе данных — это конкретная модель ноутбука, представленная в прайс-листе производителя. Атрибуты объектов: компания, продукт, тип, диагональ экрана ОЗУ (оперативная память), Операционная система, вес, цена, разрешение экрана, IPS-панель, модель GPU, модель процессора (CPU_model), частота процессора, производитель CPU.
Связи между объектами: Взаимосвязь между характеристиками ноутбуков и их ценой. Например, цена может зависеть от типа процессора, объема памяти, разрешения экрана, а также от производителя.
# Для наглядности
df.head()
# Описание данных (основные статистические показатели)
df.describe()
# Процент пропущенных значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f'{i} Процент пустых значений: %{null_rate:.2f}')
# Проверка на пропущенные данные
df.isnull().sum()
df.isnull().any()
Пропущенных данных в колонках нет :)
Бизнес-цель¶
- Оптимизация ценообразования
Использование данных для построения модели прогнозирования цены ноутбуков на основе характеристик. Эффект: Повышение продаж за счет правильного позиционирования товаров в разных ценовых сегментах. - Анализ рынка и планирование производства Определение наиболее популярных и прибыльных конфигураций ноутбуков на основе данных о характеристиках и продажах. Эффект: Снижение издержек на производство непопулярных моделей и повышение прибыльности.
Техническая цель¶
- Прогнозирование цены ноутбуков
Создать модель машинного обучения, которая на вход получает характеристики ноутбука (ОЗУ, CPU, объём памяти, экран и т.д.) и предсказывает его цену. На вход поступают характеристики, а целевой признак - цена ноутбука. - Классификация сегмента ноутбука
Создать модель для предсказания ценового сегмента в зависимости от их характеристик. На вход поступают характеристики ноутбука, а целевой признак - определение ценового сегмента (бюджетный, средний, премиум).
# Визуализация выбросов для столбца Price_euros
plt.figure(figsize=(10, 6))
sns.boxplot(x=df['Price_euros'])
plt.title('Boxplot для цены ноутбуков (Price_euros)')
plt.show()
# Визуализация распределения моделей процессоров
plt.figure(figsize=(10, 6))
df['CPU_model'].value_counts().plot(kind='bar')
plt.title('Распределение процессоров ноутбуков')
plt.xlabel('Модель процессора')
plt.ylabel('Количество')
plt.xticks(rotation=90)
plt.show()
Проблема наборов¶
Зашумленность данных — это наличие ненужной информации, ошибок или неверных значений, которые могут исказить анализ. Например, в поле OS могут быть пробелы или некорректные названия операционных систем (например, "No OS", "Windows", "Windows 10").
Смещение данных может возникнуть, если данные отражают предпочтения определённого производителя или сегмента. Если в данных преобладает один бренд (например, Apple), это может сместить модель в сторону этого производителя.
Актуальность данных - неактуальные данные могут влиять на точность прогнозирования. Ноутбуки устаревают быстро, поэтому информация о старых моделях может быть неактуальной для анализа современных трендов.
Выбросы — это значения, которые значительно отличаются от большинства данных. Поле Price_euros может содержать аномально высокие или низкие цены, которые не соответствуют реальности.
Просачивание данных - это когда информация из тестовой выборки "просачивается" в обучение, что даёт модели несправедливое преимущество.
Решение: Очистить данные, убрать пробелы, проверить на корректность. Чётко разделить данные для обучения и тестирования, исключить целевые признаки из обучения. Уравнять количество данных для разных производителей или использовать методы балансировки.
Для устранения смещения применим рэсемплинг данных, либо же балансировку.
# Балансировка данных. Визуализация до ресэмплинга
plt.figure(figsize=(10, 6))
df['Company'].value_counts().plot(kind='bar', color='blue')
plt.title('Распределение компаний до ресэмплинга')
plt.xlabel('Компания')
plt.ylabel('Количество')
plt.xticks(rotation=45)
plt.show()
# Пример ресэмплинга
brand_counts = df['Company'].value_counts()
min_count = brand_counts.min()
balanced_data = pd.concat([df[df['Company'] == brand].sample(min_count) for brand in brand_counts.index])
# Визуализация после ресэмплинга
plt.figure(figsize=(10, 6))
balanced_data['Company'].value_counts().plot(kind='bar', color='green')
plt.title('Распределение компаний после ресэмплинга')
plt.xlabel('Компания')
plt.ylabel('Количество')
plt.xticks(rotation=45)
plt.show()
Рэсемплинг данных позволил нам изменить размер выборки, чтобы достичь более сбалансированного распределения классов, чтобы повысить общую эффективность анализа данных. Устанили перекос (дисбаланс) данных и добились более равномерное распределение компаний (брендов) ноутбуков.
import numpy as np
# Вычисление медианы для 'Price_euros'
median_price = df['Price_euros'].median()
# Вычисление абсолютных отклонений от медианы
df['absolute_deviation'] = np.abs(df['Price_euros'] - median_price)
# Вычисление медианного абсолютного отклонения (MAD)
mad = df['absolute_deviation'].median()
# Определение порога для выбросов. Вы можете настроить множитель в зависимости от ваших предпочтений
threshold = 3 * mad
# Выявление выбросов
outliers = df[df['absolute_deviation'] > threshold]
# Удаление выбросов из набора данных
datalaptop_cleaned = df[df['absolute_deviation'] <= threshold].drop(columns=['absolute_deviation'])
# Вывод количества найденных выбросов и оставшихся записей
print(f"Количество выявленных выбросов: {len(outliers)}")
print(f"Количество записей после удаления выбросов: {len(datalaptop_cleaned)}")
# Визуализация результатов
plt.figure(figsize=(12, 6))
sns.boxplot(x=df['Price_euros'])
plt.title('Распределение Price_euros с выбросами')
plt.show()
plt.figure(figsize=(12, 6))
sns.boxplot(x=datalaptop_cleaned['Price_euros'])
plt.title('Распределение Price_euros после удаления выбросов')
plt.show()
Медиальный способ борьбы с выбросами позволяет сохранить структуру даныых, создать устойчивость к этим выбросать, чтобы избежать смещения данных, если использовали бы среднее. Если имеются товары с высоко аномальной ценой, то замена на медиану позволит сократить влияние на данные. Удаление выбросов вдобавок и решает проблему зашумлённости данных. Выбросы - это одна из форм шума и удаление их позволяеи сделать данные чище и менее зашумлённые.
from imblearn.over_sampling import RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler
# Разделение признаков и целевой переменной
X = df.drop(columns=['Price_euros']) # Признаки
y = df['Price_euros'] # Целевая переменная (для регрессии)
# Разбиение данных на обучающую, контрольную и тестовую выборки
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
print(f"Размер обучающей выборки: {len(X_train)}")
print(f"Размер валидационной выборки: {len(X_val)}")
print(f"Размер тестовой выборки: {len(X_test)}")
# Все типы к числовым приводим
X_train = X_train.apply(pd.to_numeric, errors='coerce')
print(X_train.dtypes)
# Квантилизация целевой переменной для создания категорий
y_train_cat = pd.qcut(y_train, q=4, labels=False)
# Объединяем исходные данные и "шумные" данные для увеличения обучающей выборки
X_train_combined = np.vstack([X_train, X_train])
y_train_combined = np.hstack([y_train, y_train]) # Убедитесь, что y_train повторяется для новых данных
# Применение oversampling и undersampling
ros = RandomOverSampler(random_state=42)
X_train_ros, y_train_ros = ros.fit_resample(X_train, y_train_cat)
# Проверка распределения после oversampling
plt.figure(figsize=(10, 6))
sns.histplot(y_train_ros, bins=30, kde=True, color='green')
plt.title('Распределение целевого признака после oversampling')
plt.xlabel('Price_euros')
plt.ylabel('Частота')
plt.show()
# Применение RandomUnderSampler
rus = RandomUnderSampler(random_state=42)
X_train_rus, y_train_rus = rus.fit_resample(X_train, y_train_cat)
# Проверка распределения после undersampling
plt.figure(figsize=(10, 6))
sns.histplot(y_train_rus, bins=30, kde=True, color='red')
plt.title('Распределение целевого признака после undersampling')
plt.xlabel('Price_euros')
plt.ylabel('Частота')
plt.show()
# Вывод количества данных до и после аугментации
print(f"Количество записей в обучающей выборке до аугментации: {len(y_train)}")
print(f"Количество записей в обучающей выборке после oversampling: {len(y_train_ros)}")
print(f"Количество записей в обучающей выборке после undersampling: {len(y_train_rus)}")
Набор данных, судя по числам, был относительно сбалансирован, и применение oversampling/undersampling не сильно изменил размер выборок. Использование RandomOverSampler и RandomUnderSampler для регрессионных задач не является оптимальным решением, поскольку эти методы предназначены для классификации.
Третий датафрейм: Зарплата сотрудников по обработке данных (DataScience)¶
Выгрузили третий датасет!!! :)
# Выгружаем третий датафрейм
df = pd.read_csv(".\\static\\csv\\ds_salaries.csv")
print(df.columns)
print()
df.info()
Описание набора¶
Kaggle даёт следующие пояснения о датасете:
Целью данного исследования является изучение факторов, влияющих на заработную плату специалистов по обработке данных. Для этого был использован набор данных, содержащий различные релевантные переменные. В этом отчёте описывается исследовательский анализ, проведённый для понимания взаимосвязи между этими факторами и заработной платой специалистов по обработке данных. Наука о данных — быстро развивающаяся область, и специалисты по обработке данных играют важнейшую роль в анализе и интерпретации больших объёмов данных. Поскольку эта профессия становится всё более востребованной, важно понимать факторы, которые могут влиять на зарплату специалистов по обработке данных. Этот анализ посвящён изучению этих факторов и их влиянию на зарплату.
# Для наглядности
df.head()
# Описание представленного датафрейма
df.describe()
# Процент пропущенных значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f'{i} Процент пустых значений: %{null_rate:.2f}')
# Проверка на пропущенные данные
df.isnull().sum()
df.isnull().any()
Хе-хе, какие весёлые датасеты :) Ни где данных пропущенных не нашлось, хе-хе))
Анализ сведений о наборе данных¶
Набор данных: Набор данных представляет собой информацию о сотрудниках DataScientist. Их зарплатах, занятости, стаже и по этим данным будет проводиться анализ.
Проблемная область: Проблемной областью может являться анализ и управление заработной платой сотрудников с учётом различных факторов, которые позволяют компаниям улучшать свои кадровые стратегии и конкурировать на рынке труда.
Проанализируем содержимое...
Объекты наблюдения: Каждый сотрдник в области оьработки данных является объектом наблюдения.
Атрибуты объектов: Основные атрибуты представляют собой зарплату работников, тип занятости, уровень опыта разработчика, год получения опыта работника, валюта (выплачиваемой зарплаты), местоположение сотрудника, мостоположение компании, размер компании, доля удалённой работы.
Связи между объектами: Стаж сотрудника может быть использован в зарплатах и трудоустройстве по годам. Более высокий опыт и определённые должности коррелируют с большими зарплатами. Регионы и страы могут показать разницу в зарплатах.
Бизнес-цель¶
- Определение конкурентоспособности зарплат
Цель: Сравнить зарплаты сотрудников по странам и должностям.
Эффект же будет заключаться в том, что компании могут использовать эту информацию для привлечения и удержания талантов, предлагая конкрурентные зарплаты. - Оценка зависимости между опытом и зарплатой
Цель: Определить, как профессиональный опыт влияет на зарплаты в различных секторах.
Эффект заключается в том, что компании могут лучше планировать бюджеты на повышение зарплат в зависимости от опыта сотрудников.
Техническая цель¶
- Конкурентоспособность зарплат
Построить модель, которая будет предсказывать зарплаты сотрудников на основе атрибутов. На вход должны следовать такие признаки, как должность, опыт, страна компании. Целевой признак: зарплата. - Оценка зависимости между опытом и зарплатой Создать модель и визуализировать влияние опыта на зарплату. На вход должны идти уровень опыта, должность, местоположение компании. Целевой признак: Зарплата
# Визуализация данных - ящик с усами. Выборка относительно сбалансирована, есть среднее смещение в среднюю сторону, медиана уравновешена
plt.figure(figsize=(10, 6))
sns.boxplot(x=df["salary_in_usd"])
plt.title("Box Plot для salary_in_usd")
plt.xlabel("salary_in_usd")
plt.show()
# Визуализируем отношение размера компании и зарплаты
plt.figure(figsize=(10, 6))
plt.scatter(df["salary_in_usd"], df["experience_level"])
plt.xlabel("salary_in_usd")
plt.ylabel("experience_level")
plt.title("salary in usd vs experience_level")
plt.show()
Проблемы выбранный наборов данных¶
Зашумленность:
Возможное присутствие некорректных или неполных данных, например, ошибки в заполнении зарплат или местоположений.
Необходима очистка данных от выбросов и ошибок.
Смещение:
Могут быть смещения в данных по странам или компаниям, например, если большая часть выборки состоит из сотрудников одной страны или отрасли.
Актуальность:
Если данные собраны за несколько лет, некоторые зарплаты могут быть неактуальны для текущего рынка, что требует дополнительной актуализации.
Выбросы:
Возможны экстремальные значения в зарплатах, которые необходимо либо исключить, либо обработать, чтобы не искажать модели.
Просачивание данных:
Если в данных есть признаки, которые могут напрямую предсказывать зарплату (например, если salary_currency или company_size напрямую коррелируют с зарплатой), это может привести к ошибкам в моделях.
Борьба с выбросами¶
# Статистический анализ для определения выбросов
Q1 = df["salary_in_usd"].quantile(0.25)
Q3 = df["salary_in_usd"].quantile(0.75)
IQR = Q3 - Q1
# Определение порога для выбросов
threshold = 1.5 * IQR
outliers = (df["salary_in_usd"] < (Q1 - threshold)) | (
df["salary_in_usd"] > (Q3 + threshold)
)
# Обработка выбросов
# В данном случае мы уберем выбросы
median_salary = df["salary_in_usd"].median()
df.loc[outliers, "salary_in_usd"] = 0
df1 = df[df.salary_in_usd != 0]
# Визуализация данных после обработки
plt.figure(figsize=(10, 6))
plt.scatter(df1["salary_in_usd"], df1["experience_level"])
plt.xlabel("salary_in_usd")
plt.ylabel("experience_level")
plt.title("salary in usd vs experience_level")
plt.show()
# Визуализация данных после обработки
plt.figure(figsize=(12, 6))
plt.boxplot(df1["salary_in_usd"])
plt.xlabel("salary_in_usd")
plt.ylabel("experience_level")
plt.title("salary in usd vs experience_level")
plt.show()
from sklearn.model_selection import train_test_split
# Пример датасета с данными (X — признаки, y — целевой признак)
X = df.drop(columns=["salary_in_usd"]) # Признаки (все столбцы, кроме целевого признака 'salary')
y = df["salary_in_usd"] # Целевая переменная
# Разделяем данные на обучающую (60%), временную (40%) выборки
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
# Временную выборку делим пополам на контрольную (20%) и тестовую (20%) выборки
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
# Проверяем размер выборок
print(f"Размер обучающей выборки: {len(X_train)}")
print(f"Размер контрольной выборки: {len(X_val)}")
print(f"Размер тестовой выборки: {len(X_test)}")
Теперь оценим сбалансированность, если нужно использовать методы аугментации данных, то применим. Анаализ проведём в категории 'salary_in_usd', в которой может потребоваться применение oversampling или undersampling.
from imblearn.over_sampling import RandomOverSampler
# Визуализация распределения зарплат в обучающей выборке
plt.figure(figsize=(10, 6))
sns.histplot(y_train, bins=30, kde=True, color='blue')
plt.title('Распределение зарплат в обучающей выборке')
plt.xlabel('Зарплата в USD')
plt.ylabel('Частота')
plt.show()
ros = RandomOverSampler(random_state=42)
X_train_ros, y_train_ros = ros.fit_resample(X_train, y_train)
# Визуализация распределения после oversampling
plt.figure(figsize=(10, 6))
sns.histplot(y_train_ros, bins=30, kde=True, color='green')
plt.title('Распределение зарплат после oversampling')
plt.xlabel('Зарплата в USD')
plt.ylabel('Частота')
plt.show()
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=42)
X_train_rus, y_train_rus = rus.fit_resample(X_train, y_train)
# Визуализация распределения после oversampling
plt.figure(figsize=(10, 6))
sns.histplot(y_train_ros, bins=30, kde=True, color='green')
plt.title('Распределение зарплат после oversampling')
plt.xlabel('Зарплата в USD')
plt.ylabel('Частота')
plt.show()
print(f"Количество записей в обучающей выборке до аугментации: {len(y_train)}")
print(f"Количество записей в обучающей выборке после oversampling: {len(y_train_ros)}")
print(f"Количество записей в обучающей выборке после undersampling: {len(y_train_rus)}")
print()
train_df, val_df = train_test_split(df, test_size=0.4, random_state=42)
val_df, test_df = train_test_split(val_df, test_size=0.5, random_state=42)
# Функция для проверки распределения
def check_balance(df, name):
counts = df['salary_in_usd'].value_counts() # Обращение к столбцу 'salary_in_usd'
print(f"Распределение salary_in_usd в {name}:")
print(counts)
print()
check_balance(train_df, "обучающей выборке")
check_balance(val_df, "контрольной выборке")
check_balance(test_df, "тестовой выборке")
print()
# Корреляция
# Сначала отбираем только числовые столбцы
numeric_df = df.select_dtypes(include='number')
correlation_matrix = numeric_df.corr()
# Визуализация корреляционной матрицы
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, fmt=".2f", cmap='coolwarm', square=True)
plt.title("Корреляция между переменными")
plt.show()
Таким образом, мы проанализировали 3 датасета. Посмотрели какие проблемы с ними могут быть связаны, возможные пути их решения. Разбили выборки, далее их сбалансировали, с помощью методов OverSampling и UnderSampling. Методы oversampling и undersampling лучше использовать для задач классификации, где целевая переменная — дискретные классы. Для регрессионных задач эти методы напрямую не применимы. Методы аугментации данных для регрессии, такие как SMOTE для регрессии, могут также помочь в увеличении количества обучающих данных и улучшении качества модели.
Вроде бы всё... Вроде бы получилось :)