54 KiB
Лабораторная работа №2¶
Описание датасетов¶
Первый датасет: Diamonds Prices¶
Описание: Данный набор данных включает информацию о 53 940 бриллиантах круглой огранки и содержит 10 уникальных характеристик, которые описывают бриллиант с разных сторон. Большинство переменных являются числовыми, однако характеристики огранка, цвет и чистота представлены в виде категорий. Цена указана в долларах США.
Объект исследования: Объектом исследования данного датасета являются круглые бриллианты с разными характеристиками, которые влияют на их стоимость.
Атрибуты объекта:
id - Уникальный идентификатор каждого бриллианта
carat - Вес бриллианта в каратах. Карат — это мера массы, где один карат равен 0,2 грамма.
cut - Оценка огранки бриллианта, которая влияет на его способность отражать свет.
color - Цвет бриллианта, который оценивается по шкале, где более высокие уровни означают меньший оттенок желтого и более высокую ценность.
clarity - Чистота бриллианта, измеряемая по количеству и размеру внутренних дефектов или внешних недостатков.
depth - Общая глубина бриллианта, выраженная как процент от его среднего диаметра.
table - Ширина верхней плоской грани бриллианта ("стола"), выраженная как процент от его среднего диаметра.
price - Цена бриллианта в долларах США.
X - Длина бриллианта в миллиметрах.
Y - Ширина бриллианта в миллиметрах.
Z - Глубина бриллианта в миллиметрах.
Цель исследования: Анализ взаимосвязей между различными характеристиками бриллиантов (такими как карат, чистота и огранка) и их ценой. Этот анализ может помочь определить, какие атрибуты оказывают наибольшее влияние на стоимость бриллианта и предоставить информацию для прогнозирования цен на основе параметров.
Ссылка на датасет: https://www.kaggle.com/datasets/nancyalaswad90/diamonds-prices
Второй датасет: Forbes 2022 Billionaires data¶
Описание: Этот набор данных содержит ежегодный рейтинг миллиардеров с самыми высокими состояниями, составленный журналом Forbes. Информация включает чистую стоимость активов каждого человека, оцененную в долларах США на основе подтвержденных активов за вычетом долгов. Исключены лица, чье богатство не может быть задокументировано, а также представители монархий и диктатуры, чье богатство зависит от их положения. Методология сбора данных включает интервьюирование миллиардеров, анализ публичных данных и оценку активов по рыночным ценам.
Объект исследования: Объектом исследования данного датасета являются документально подтверждённые состояния миллиардеров по всему миру на 2022 год.
Атрибуты объекта:
Rank - Ранг в списке миллиардеров Forbes, который показывает позицию человека по величине состояния среди всех миллиардеров, начиная с самого богатого.
Name - Имя и фамилия миллиардера.
Networth - Чистая стоимость активов миллиардера, выраженная в миллиардах долларов США.
Age - Возраст миллиардера на момент составления рейтинга.
Country - Страна проживания миллиардера, которая показывает национальную принадлежность или основное место жительства.
Source - Источник состояния, указывающий на основные компании, отрасли или типы бизнеса, благодаря которым было накоплено богатство.
Industry - Отрасль, к которой относится основной источник дохода миллиардера.
Цель исследования: Определить распределение и влияние различных факторов (например, происхождения состояния, географического региона) на величину состояния. Это поможет выявить тренды в распределении богатства и дать более глубокое понимание ключевых факторов, влияющих на богатство миллиардеров.
Ссылка на датасет: https://www.kaggle.com/datasets/surajjha101/forbes-billionaires-data-preprocessed
Третий датасет: Tesla Insider Trading¶
Описание: Этот датасет представляет собой небольшой фрагмент данных о торговле акциями компании Tesla с участием инсайдеров и содержит записи крупных сделок с ноября 2021 года по июль 2022 года. Включает в себя информацию о личности, совершившей сделку, её должности, типе транзакции (покупка, продажа или опцион), стоимости и количестве акций, дате и общей стоимости сделки. Дополнительно указана дата подачи отчета в SEC (Форма 4).
Объект исследования: Объектом исследования данного датасета являются транзакции с акциями Tesla, совершенные инсайдерами компании в период с ноября 2021 года по июль 2022 года.
Атрибуты объекта:
Insider Trading - Лицо, совершившее транзакцию.
Relationship - Статус этого лица в компании.
Date - Дата, когда транзакция была завершена.
Transaction - Тип транзакции.
Cost - Стоимость акций в этой транзакции.
Shares - Сколько акций участвует в транзакции.
Value ($) - Общая стоимость транзакции.
Shares Total - Общее количество акций лица на данный момент.
SEC Form 4 - Дата, когда транзакция была зарегистрирована.
Цель исследования: Анализ инсайдерских сделок, выявление трендов в покупке или продаже акций инсайдерами, а также определение потенциального влияния этих действий на стоимость акций Tesla. Информация может быть полезной для прогнозирования динамики акций компании и принятия инвестиционных решений на основе анализа действий крупных держателей акций.
Ссылка на датасет: https://www.kaggle.com/datasets/ilyaryabov/tesla-insider-trading
Работа с наборами данных¶
Загрузим три датасета и оценим их структуру
import pandas as pd
df = pd.read_csv("..//static//csv//DiamondsPrices2022.csv")
df2 = pd.read_csv("..//static//csv//ForbesBillionaires.csv")
df3 = pd.read_csv("..//static//csv//TSLA.csv")
df.info()
df2.info()
df3.info()
Получение сведений о пропущенных данных¶
Типы пропущенных данных:
- None - представление пустых данных в Python
- NaN - представление пустых данных в Pandas
- ' ' - пустая строка
# цены на бриллианты
print("Цены на бриллианты")
# Количество пустых значений признаков
print(df.isnull().sum())
print()
# Есть ли пустые значения признаков
print(df.isnull().any())
print()
# Процент пустых значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f"{i} процент пустых значений: %{null_rate:.2f}\n")
# рейтинг миллиардеров с Forbes
print("Рейтинг миллиардеров с Forbes")
# Количество пустых значений признаков
print(df2.isnull().sum())
print()
# Есть ли пустые значения признаков
print(df2.isnull().any())
print()
# Процент пустых значений признаков
for i in df2.columns:
null_rate = df2[i].isnull().sum() / len(df2) * 100
if null_rate > 0:
print(f"{i} процент пустых значений: %{null_rate:.2f}\n")
# Инсайдерские акции компании Tesla
print("Торговля акциями компании Tesla")
# Количество пустых значений признаков
print(df3.isnull().sum())
print()
# Есть ли пустые значения признаков
print(df3.isnull().any())
print()
# Процент пустых значений признаков
for i in df3.columns:
null_rate = df3[i].isnull().sum() / len(df3) * 100
if null_rate > 0:
print(f"{i} процент пустых значений: %{null_rate:.2f}\n")
В результате проверки на пустые строки и значения мы видим, что таковых не обнаружено
Проверка набора данных на аномальные распределения¶
Проверим датасет по числовым данным, для выявления аномальных распределений
print(df.describe())
print(df2.describe())
print(df3.describe())
Здесь можно определить, что в некоторых областях присутствует аномальное распределение. Следовательно аномальное рапределение будем искать по z-индексу. Он показывает нам, насколько далеко значение находится от среднего в стандартных отклонениях. Значения Z-индекса больше 3 или меньше -3 обычно считаются аномальными.
from scipy import stats
# Вычисляем Z-индексы только для числовых столбцов
df_zscores = df.select_dtypes(include=['float64', 'int64']).apply(stats.zscore, nan_policy='omit')
df2_zscores = df2.select_dtypes(include=['float64', 'int64']).apply(stats.zscore, nan_policy='omit')
df3_zscores = df3.select_dtypes(include=['float64', 'int64']).apply(stats.zscore, nan_policy='omit')
# Порог для поиска аномалий
threshold = 3
def find_anomalies(zscores, data):
for column in zscores.columns:
# Проверка на присутствие аномалии
anomalies = data[column][(zscores[column].abs() > threshold)]
if not anomalies.empty:
print(f"В атрибуте '{column}' обнаружены аномалии: {anomalies.tolist()}")
try:
print("Аномалии в наборе данных Diamonds Prices:")
find_anomalies(df_zscores, df)
print("\nАномалии в наборе данных Forbes Billionaires:")
find_anomalies(df2_zscores, df2)
print("\nАномалии в наборе данных Tesla:")
find_anomalies(df3_zscores, df3)
except Exception as e:
print(f"Произошла ошибка: {e}")
Разбиение набора данных на выборки¶
Следующим этапом разбиваем набор данных на выборки. Прежде всего стоит избавиться от большого количества уникальных значений в столбцах с целевыми признаками. Для этого добавим новый столбец в датасет Forbes Billionaires с малым количеством значений.
df2['networth_segment'] = pd.cut(df2['Networth'], bins=[0,10,80,250], labels=['Ultra High Networth','High Networth','Medium Networth'], include_lowest=True)
from sklearn.model_selection import train_test_split
def split_data(data, target_column, test_size=0.2, random_state=42):
# Разделяем данные на обучающую и временную выборки
X_train, X_temp, y_train, y_temp = train_test_split(data.drop(columns=[target_column]),
data[target_column],
test_size=test_size,
random_state=random_state,
stratify=data[target_column])
# Делим временную выборку на контрольную и тестовую
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp,
test_size=0.5,
random_state=random_state,
stratify=y_temp)
return X_train, X_val, X_test, y_train, y_val, y_test
# Для набора данных Diamonds Prices
df_train, df_val, df_test, df_train_labels, df_val_labels, df_test_labels = split_data(df, 'cut')
# Для набора данных Forbes Billionaires
df2_train, df2_val, df2_test, df2_train_labels, df2_val_labels, df2_test_labels = split_data(df2, 'networth_segment')
# Для набора данных Tesla
df3_train, df3_val, df3_test, df3_train_labels, df3_val_labels, df3_test_labels = split_data(df3, 'Transaction')
def check_balance(y_train, y_val, y_test):
print("Обучающая выборка:")
print(y_train.value_counts(normalize=True))
print("\nКонтрольная выборка:")
print(y_val.value_counts(normalize=True))
print("\nТестовая выборка:")
print(y_test.value_counts(normalize=True))
print("Набор данных Diamonds Prices:")
check_balance(df_train_labels, df_val_labels, df_test_labels)
print("\nНабор данных Forbes Billionaires:")
check_balance(df2_train_labels, df2_val_labels, df2_test_labels)
print("\nНабор данных Tesla:")
check_balance(df3_train_labels, df3_val_labels, df3_test_labels)
Набор данных Diamonds Prices¶
Пропорция классов в обучающей выборке довольно сбалансирована, хотя класс Ideal составляет 39.95%, что значительно больше, чем у остальных классов. Остальные классы представлены следующим образом: Premium (25.57%), Very Good (22.40%), Good (9.10%) и Fair (2.98%).
Если модель будет обучаться только на этих данных, она может показать высокую точность, просто предсказывая, что большинство объектов относятся к классу Ideal, что может привести к снижению её способности определять менее представленные классы, такие как Fair.
Набор данных Forbes Billionaires¶
Пропорция классов в этом наборе данных крайне несбалансирована: Ultra High Networth составляет 92.45%, в то время как High Networth и Medium Networth составляют лишь 7.02% и 0.53% соответственно.
В случае обучения модели на этих данных, она может иметь высокую точность, просто предсказывая, что все объекты принадлежат классу Ultra High Networth. Это негативно скажется на способности модели правильно классифицировать более редкие классы, такие как Medium Networth.
Набор данных Tesla¶
Пропорция классов в обучающей выборке менее выражена, чем в предыдущих примерах, но все же классы не являются полностью сбалансированными: класс Sale составляет 63.71%, а класс Option Exercise — 36.29%.
Модель может научиться распознавать оба класса, однако если точность по классу Option Exercise будет низкой, стоит рассмотреть применение методов аугментации данных или выборки для улучшения её производительности на этом классе.
Приращение наборов данных¶
Заключительным этапом проводим приращение наборов данных методами выборки с избытком (oversampling) и выборки с недостатком (undersampling)
Oversampling (приращение данных): Увеличение числа примеров для меньшинства классов.
Undersampling (уменьшение данных): Уменьшение числа примеров для большинства классов.
from imblearn.over_sampling import RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler
# Oversampling для Diamonds Prices
X_df = df.drop('cut', axis=1)
y_df = df['cut']
ros_df = RandomOverSampler(random_state=42)
X_df_resampled, y_df_resampled = ros_df.fit_resample(X_df, y_df)
df_resampled = pd.DataFrame(X_df_resampled, columns=X_df.columns)
df_resampled['cut'] = y_df_resampled
print("Oversampling для Diamonds Prices:")
print(df_resampled['cut'].value_counts())
X_df2 = df2.drop('networth_segment', axis=1)
y_df2 = df2['networth_segment']
# Undersampling для Forbes Billionaires
rus_df2 = RandomUnderSampler(random_state=42)
X_df2_resampled_under, y_df2_resampled_under = rus_df2.fit_resample(X_df2, y_df2)
df2_resampled_under = pd.DataFrame(X_df2_resampled_under, columns=X_df2.columns)
df2_resampled_under['networth_segment'] = y_df2_resampled_under
print("\nUndersampling для Forbes Billionaires:")
print(df2_resampled_under['networth_segment'].value_counts())
# Oversampling для Tesla
X_df3 = df3.drop('Transaction', axis=1)
y_df3 = df3['Transaction']
ros_df3 = RandomOverSampler(random_state=42)
X_df3_resampled, y_df3_resampled = ros_df3.fit_resample(X_df3, y_df3)
df3_resampled = pd.DataFrame(X_df3_resampled, columns=X_df3.columns)
df3_resampled['Transaction'] = y_df3_resampled
print("\nOversampling для Tesla:")
print(df3_resampled['Transaction'].value_counts())