924 KiB
Определение бизнес-целей для анализа на основе набора данных Diamonds Prices2022¶
- Оптимизация ценовой стратегии: Использование данных о характеристиках бриллиантов для создания точной стратегии ценообразования и максимизации прибыли.
- Увеличение продаж: Анализ факторов, влияющих на цену и спрос на бриллианты, для предложения конкурентоспособных цен и улучшения продаж.
Подготовка данных¶
import pandas as pd
# Загружаем данные
data = pd.read_csv('data/Diamonds Prices2022.csv')
# Преобразуем столбец 'price' в числовой формат
data['price'] = pd.to_numeric(data['price'], errors='coerce')
# Преобразуем 'carat' в числовой формат
data['carat'] = pd.to_numeric(data['carat'], errors='coerce')
# Преобразуем 'depth' в числовой формат
data['depth'] = pd.to_numeric(data['depth'], errors='coerce')
# Преобразуем 'table' в числовой формат
data['table'] = pd.to_numeric(data['table'], errors='coerce')
# Преобразуем 'x', 'y', 'z' в числовой формат
data['x'] = pd.to_numeric(data['x'], errors='coerce')
data['y'] = pd.to_numeric(data['y'], errors='coerce')
data['z'] = pd.to_numeric(data['z'], errors='coerce')
# Преобразуем 'cut', 'color', 'clarity' в категориальные данные
data['cut'] = data['cut'].astype('category')
data['color'] = data['color'].astype('category')
data['clarity'] = data['clarity'].astype('category')
# Проверяем изменённые данные
print(data.head())
Выполним разбиение каждого набора данных на обучающую, контрольную и тестовую выборки для устранения проблемы просачивания данных
import pandas as pd
from sklearn.model_selection import train_test_split
# Загружаем данные
data = pd.read_csv('data/Diamonds Prices2022.csv')
# Целевая переменная для регрессии - 'price'
X_regression = data.drop(columns=['price', 'carat', 'cut', 'color', 'clarity'])
y_regression = data['price']
# Разделяем на обучающую, валидационную и тестовую выборки
X_reg_train, X_reg_temp, y_reg_train, y_reg_temp = train_test_split(
X_regression, y_regression, test_size=0.3, random_state=42
)
X_reg_val, X_reg_test, y_reg_val, y_reg_test = train_test_split(
X_reg_temp, y_reg_temp, test_size=0.5, random_state=42
)
# Проверка размеров выборок
print("Regression datasets sizes:")
print("Train:", X_reg_train.shape, "Validation:", X_reg_val.shape, "Test:", X_reg_test.shape)
Оценим
import matplotlib.pyplot as plt
# Визуализация распределения целевой переменной для регрессии
plt.figure(figsize=(12, 6))
plt.hist(y_reg_train, bins=50, alpha=0.6, label='Train', color='blue', edgecolor='black')
plt.hist(y_reg_val, bins=50, alpha=0.6, label='Validation', color='green', edgecolor='black')
plt.hist(y_reg_test, bins=50, alpha=0.6, label='Test', color='red', edgecolor='black')
plt.xlabel('Цена бриллиантов')
plt.ylabel('Количество')
plt.legend()
plt.show()
# График с нормированными частотами (барплот)
plt.figure(figsize=(12, 6))
bar_width = 0.25
# Нормированные частоты для каждой выборки
train_counts = y_reg_train.value_counts(normalize=True).sort_index()
val_counts = y_reg_val.value_counts(normalize=True).sort_index()
test_counts = y_reg_test.value_counts(normalize=True).sort_index()
# Все уникальные значения цены, чтобы синхронизировать данные
all_values = sorted(set(train_counts.index).union(val_counts.index).union(test_counts.index))
# Заполнение недостающих значений нулями
train_counts = train_counts.reindex(all_values).fillna(0)
val_counts = val_counts.reindex(all_values).fillna(0)
test_counts = test_counts.reindex(all_values).fillna(0)
# Позиции для баров
positions = range(len(all_values))
# Строим барплот
plt.bar(positions, train_counts, width=bar_width, label='Train', color='blue', edgecolor='black', align='center')
plt.bar([p + bar_width for p in positions], val_counts, width=bar_width, label='Validation', color='green', edgecolor='black', align='center')
plt.bar([p + 2 * bar_width for p in positions], test_counts, width=bar_width, label='Test', color='red', edgecolor='black', align='center')
plt.xlabel('Цена бриллиантов')
plt.ylabel('Нормированное количество')
plt.legend()
plt.show()
Создадим дополнительные признаки для решения целей
import pandas as pd
# Загрузка данных
file_path = 'data/Diamonds Prices2022.csv'
data = pd.read_csv(file_path)
# Проверим, есть ли столбец с годом продажи, и если его нет, выберем другой столбец
if 'year' in data.columns:
year_column = 'year'
else:
print("Столбец с годом продажи отсутствует в данных, возможно его нужно заменить или добавить.")
# Убедимся, что столбцы 'price' и 'carat' содержат только числовые значения
data['price'] = pd.to_numeric(data['price'], errors='coerce')
data['carat'] = pd.to_numeric(data['carat'], errors='coerce')
# 1. Конструирование признаков для цели "Оптимизация ценовой политики"
# Создаем признак "Вес бриллианта" (Carat)
data['Diamond_Weight'] = data['carat']
# Нормализуем цену бриллианта
data['Normalized_Price'] = (data['price'] - data['price'].mean()) / data['price'].std()
# 2. Конструирование признаков для цели "Увеличение конкурентоспособности"
# Генерация бинарного признака: "Дорогостоящие бриллианты" (цена > 5000)
data['Expensive_Diamond'] = (data['price'] > 5000).astype(int)
# Генерация категориального признака на основе веса
data['Carat_Category'] = pd.cut(data['carat'], bins=[0, 0.5, 1.0, 1.5, 2.0, 5.0],
labels=['<0.5', '0.5-1.0', '1.0-1.5', '1.5-2.0', '2.0+'])
# Сохраняем результат в новый файл
data.to_csv('Diamonds_Prices2022_with_features.csv', index=False)
# Выводим первые строки нового датасета для проверки
print(data.head())
Оценим качество каждого набора признаков по следующим критериям: предсказательная способность, скорость вычисления, надежность, корреляция и цельность.
Предсказательная способность признака — это его способность объяснять или предсказывать целевую переменную. В нашем случае целевой переменной является price
. Чем больше признак "связан" с целевой переменной, тем выше его предсказательная способность.
Корреляция измеряет степень линейной зависимости между двумя переменными.
Если корреляция между признаком и целевой переменной высока (близка к +1 или -1), это означает, что признак хорошо объясняет вариации price
. Например, такие признаки, как carat
или Diamond_Weight
, могут иметь сильную корреляцию с ценой, поскольку вес бриллианта напрямую влияет на его стоимость. В то время как признаки, такие как cut
или color
, могут показывать менее выраженную связь, но все равно вносят вклад в определение цены. Если корреляция близка к 0, признак почти не влияет на price
.
import seaborn as sns
import matplotlib.pyplot as plt
import time
import pandas as pd
# Загрузка данных
file_path = 'data/Diamonds Prices2022.csv'
data = pd.read_csv(file_path)
# Предсказательная способность (корреляция с целевыми переменными)
target_columns = ['price', 'carat']
feature_columns = ['carat', 'cut', 'color', 'clarity', 'depth', 'table', 'x', 'y', 'z']
# Преобразуем категориальные столбцы в числовые (one-hot encoding)
data_encoded = pd.get_dummies(data[feature_columns], drop_first=True)
# Объединяем с целевыми переменными
data_combined = pd.concat([data[target_columns], data_encoded], axis=1)
# Выбираем только числовые столбцы для вычисления корреляции
numerical_data = data_combined.select_dtypes(include=['float64', 'int64'])
# Корреляционная матрица
correlation_matrix = numerical_data.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, fmt=".2f", cmap='coolwarm')
plt.title('Корреляция признаков и целевых переменных')
plt.show()
# Скорость вычисления
calc_times = {}
# Так как столбца 'year' нет, можно исключить его из расчета или заменить на другую логику
# Пример вычислений без года:
start = time.time()
data['Price_per_Carat'] = data['price'] / data['carat']
calc_times['Price_per_Carat'] = time.time() - start
start = time.time()
data['Normalized_Price'] = (data['price'] - data['price'].mean()) / data['price'].std()
calc_times['Normalized_Price'] = time.time() - start
# График времени вычисления
plt.barh(list(calc_times.keys()), list(calc_times.values()))
plt.xlabel('Время вычисления (в секундах)')
plt.ylabel('Признаки')
plt.title('Время вычисления признаков')
plt.show()
# Надежность
missing_values = data[feature_columns].isnull().sum()
plt.barh(feature_columns, missing_values)
plt.xlabel('Количество пропусков')
plt.ylabel('Признаки')
plt.title('Пропущенные значения по признакам (надежность)')
plt.show()
Цельность признака — это его способность предоставлять полную, корректную и осмысленную информацию без пропусков или противоречий. Для вашего датасета, содержащего информацию о зарплатах и опыте сотрудников, цельный признак — это признак, который:
- Не содержит пропущенных значений (NaN или пустых значений).
- Не имеет ошибок или некорректных значений (например, отрицательная зарплата, некорректные значения для типа занятости или уровня опыта).
- Содержит логически правильное распределение значений (например, для признаков, таких как
experience_level
,employment_type
,job_title
илиcompany_size
, присутствуют только допустимые категории, а значения не противоречат ожидаемым).
Цельность признаков гарантирует, что данные в вашем датасете являются достоверными и могут быть использованы для дальнейшего анализа и построения моделей.
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
# Загрузка данных
file_path = 'data/Diamonds Prices2022.csv'
data = pd.read_csv(file_path)
# Проверка названий столбцов
print(data.columns)
# Признаки для анализа (используем только те, которые есть в датасете)
feature_columns = ['carat', 'cut', 'color', 'clarity', 'depth', 'table', 'price', 'x', 'y', 'z']
# Заполним пропущенные значения для категориальных признаков
data[['cut', 'color', 'clarity']] = data[['cut', 'color', 'clarity']].fillna('Unknown')
# Цельность
for feature in feature_columns:
plt.figure(figsize=(6, 4))
if data[feature].dtype == 'object': # Если категориальный признак
sns.histplot(data[feature], kde=False, bins=30)
else: # Если числовой признак
sns.histplot(data[feature], kde=True, bins=30)
plt.title(f'Цельность: {feature}')
plt.xlabel(feature)
plt.ylabel('Частота')
plt.show()
Избыточность признаков — это ситуация, когда два или более признака содержат схожую или дублирующую информацию.
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
# Загрузка данных
file_path = 'data/Diamonds Prices2022.csv'
data = pd.read_csv(file_path)
# Признаки для анализа (изменено под ваш датасет)
feature_columns = ['carat', 'cut', 'color', 'clarity', 'depth', 'table', 'price', 'x', 'y', 'z']
# Преобразование категориальных признаков в числовые с использованием one-hot кодирования
data_encoded = pd.get_dummies(data[feature_columns], drop_first=True)
# Рассчитаем корреляционную матрицу
corr_matrix = data_encoded.corr()
# Убедимся, что корреляция имеет смысл (например, все ли признаки числовые)
print(corr_matrix)
# Избыточность: построение корреляционной матрицы
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap='coolwarm')
plt.title('Избыточность')
plt.show()