420 KiB
Raw Blame History

Датасет №1 (Использование мобильных устройств и поведение пользователей)

Ссылка: https://www.kaggle.com/datasets/valakhorasani/mobile-device-usage-and-user-behavior-dataset

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

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

In [9]:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from imblearn.over_sampling import SMOTE

df_mobiles = pd.read_csv("..//..//static//csv//user_behavior_data.csv")
print(df_mobiles.columns)
Index(['User ID', 'Device Model', 'Operating System',
       'App Usage Time (min/day)', 'Screen On Time (hours/day)',
       'Battery Drain (mAh/day)', 'Number of Apps Installed',
       'Data Usage (MB/day)', 'Age', 'Gender', 'User Behavior Class'],
      dtype='object')

Атрибуты объектов:

  • User ID — уникальный идентификатор пользователя.
  • Device Model — модель устройства.
  • Operating System — операционная система устройства.
  • App Usage Time (min/day) — время использования приложений в минутах в день.
  • Screen On Time (hours/day) — время включенного экрана в часах в день.
  • Battery Drain (mAh/day) — потребление батареи в мАч в день.
  • Number of Apps Installed — количество установленных приложений.
  • Data Usage (MB/day) — объем данных в мегабайтах в день.
  • Age — возраст пользователя.
  • Gender — пол пользователя.
  • User Behavior Class — класс поведения пользователя (категория для классификации).

Связи между объектами: Атрибуты, такие как модель устройства, ОС и время использования приложений, могут быть связаны с классом поведения, представляя зависимости между действиями пользователя и его характеристиками.

Примеры бизнес-целей и целей технического проекта:

  1. Оптимизация энергопотребления устройств:

    • Бизнес-цель: Оптимизировать работу приложений для снижения расхода батареи, что увеличит время работы устройства и улучшит пользовательский опыт.
    • Эффект: Повышение удовлетворенности клиентов и снижение вероятности перехода на конкурентные приложения.
  2. Сегментация пользователей для рекламы:

    • Бизнес-цель: Создание таргетированной рекламы на основе поведения пользователей (классы поведения).
    • Эффект: Увеличение конверсий и доходов от рекламных кампаний за счет более точной сегментации.
  3. Цель: Построение модели для прогнозирования расхода батареи.

    • Вход: Модель устройства, ОС, время использования приложений, количество приложений, возраст.
    • Целевой признак: Battery Drain (mAh/day).

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

In [12]:
null_values = df_mobiles.isnull().sum()
print("Пустые значения по столбцам:")
print(null_values)

duplicates = df_mobiles.duplicated().sum()
print(f"\nКоличество дубликатов: {duplicates}")
Пустые значения по столбцам:
User ID                       0
Device Model                  0
Operating System              0
App Usage Time (min/day)      0
Screen On Time (hours/day)    0
Battery Drain (mAh/day)       0
Number of Apps Installed      0
Data Usage (MB/day)           0
Age                           0
Gender                        0
User Behavior Class           0
dtype: int64

Количество дубликатов: 0

Пустых значений и дубликатов нет, проверим на выбросы:

In [13]:
columns_to_check = ['App Usage Time (min/day)', 'Screen On Time (hours/day)', 'Battery Drain (mAh/day)', 'Number of Apps Installed', 'Data Usage (MB/day)', 'User Behavior Class']

def count_outliers(data, columns):
    outliers_count = {}
    for col in columns:
        Q1 = data[col].quantile(0.25)
        Q3 = data[col].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        
        outliers = data[(data[col] < lower_bound) | (data[col] > upper_bound)]
        outliers_count[col] = len(outliers)
    
    return outliers_count

outliers_count = count_outliers(df_mobiles, columns_to_check)

for col, count in outliers_count.items():
    print(f"Количество выбросов в столбце '{col}': {count}")

plt.figure(figsize=(15, 10))
for i, col in enumerate(columns_to_check, 1):
    plt.subplot(2, 3, i)
    sns.boxplot(x=df_mobiles[col])
    plt.title(f'Box Plot of {col}')
plt.tight_layout()
plt.show()
Количество выбросов в столбце 'App Usage Time (min/day)': 0
Количество выбросов в столбце 'Screen On Time (hours/day)': 0
Количество выбросов в столбце 'Battery Drain (mAh/day)': 0
Количество выбросов в столбце 'Number of Apps Installed': 0
Количество выбросов в столбце 'Data Usage (MB/day)': 0
Количество выбросов в столбце 'User Behavior Class': 0
No description has been provided for this image

Выбросов нет

Разбиение набора данных на обучающую, контрольную и тестовую выборки

In [14]:
train_df, test_df = train_test_split(df_mobiles, test_size=0.2, random_state=42)

train_df, val_df = train_test_split(train_df, test_size=0.25, random_state=42)

print("Размер обучающей выборки:", len(train_df))
print("Размер контрольной выборки:", len(val_df))
print("Размер тестовой выборки:", len(test_df))
Размер обучающей выборки: 420
Размер контрольной выборки: 140
Размер тестовой выборки: 140
In [15]:
def check_balance(df, name):
    counts = df['User Behavior Class'].value_counts()
    print(f"Распределение \"Класс поведения пользователя\" в {name}:")
    print(counts)
    print()

check_balance(train_df, "обучающей выборке")
check_balance(val_df, "контрольной выборке")
check_balance(test_df, "тестовой выборке")
Распределение "Класс поведения пользователя" в обучающей выборке:
User Behavior Class
2    88
5    88
4    86
3    84
1    74
Name: count, dtype: int64

Распределение "Класс поведения пользователя" в контрольной выборке:
User Behavior Class
1    35
2    29
4    26
5    25
3    25
Name: count, dtype: int64

Распределение "Класс поведения пользователя" в тестовой выборке:
User Behavior Class
3    34
2    29
4    27
1    27
5    23
Name: count, dtype: int64

Оверсемплинг и андерсемплинг

In [16]:
from imblearn.over_sampling import RandomOverSampler
from imblearn.under_sampling import RandomUnderSampler

def oversample(df, target_column):
    X = df.drop(target_column, axis=1)
    y = df[target_column]
    
    oversampler = RandomOverSampler(random_state=42)
    x_resampled, y_resampled = oversampler.fit_resample(X, y) # type: ignore
    
    resampled_df = pd.concat([x_resampled, y_resampled], axis=1) 
    return resampled_df

def undersample(df, target_column):
    X = df.drop(target_column, axis=1)
    y = df[target_column]
    
    undersampler = RandomUnderSampler(random_state=42)
    x_resampled, y_resampled = undersampler.fit_resample(X, y) # type: ignore
    
    resampled_df = pd.concat([x_resampled, y_resampled], axis=1)
    return resampled_df

train_df_oversampled = oversample(train_df, 'User Behavior Class')
val_df_oversampled = oversample(val_df, 'User Behavior Class')
test_df_oversampled = oversample(test_df, 'User Behavior Class')

train_df_undersampled = undersample(train_df, 'User Behavior Class')
val_df_undersampled = undersample(val_df, 'User Behavior Class')
test_df_undersampled = undersample(test_df, 'User Behavior Class')

print("Оверсэмплинг:")
check_balance(train_df_oversampled, "обучающей выборке")
check_balance(val_df_oversampled, "контрольной выборке")
check_balance(test_df_oversampled, "тестовой выборке")

print("Андерсэмплинг:")
check_balance(train_df_undersampled, "обучающей выборке")
check_balance(val_df_undersampled, "контрольной выборке")
check_balance(test_df_undersampled, "тестовой выборке")
Оверсэмплинг:
Распределение "Класс поведения пользователя" в обучающей выборке:
User Behavior Class
1    88
2    88
5    88
4    88
3    88
Name: count, dtype: int64

Распределение "Класс поведения пользователя" в контрольной выборке:
User Behavior Class
5    35
3    35
1    35
2    35
4    35
Name: count, dtype: int64

Распределение "Класс поведения пользователя" в тестовой выборке:
User Behavior Class
4    34
1    34
2    34
3    34
5    34
Name: count, dtype: int64

Андерсэмплинг:
Распределение "Класс поведения пользователя" в обучающей выборке:
User Behavior Class
1    74
2    74
3    74
4    74
5    74
Name: count, dtype: int64

Распределение "Класс поведения пользователя" в контрольной выборке:
User Behavior Class
1    25
2    25
3    25
4    25
5    25
Name: count, dtype: int64

Распределение "Класс поведения пользователя" в тестовой выборке:
User Behavior Class
1    23
2    23
3    23
4    23
5    23
Name: count, dtype: int64

Датасет №2 (качество воды)

Ссылка: https://www.kaggle.com/datasets/adityakadiwal/water-potability

Проблемная область: качество питьевой воды и факторы, влияющие на ее безопасность для здоровья.

Объекты наблюдения: водоемы, содержащие воду разного качества.

In [2]:
# вывод всех столбцов
df = pd.read_csv("..//..//static//csv//water_potability.csv")
print(df.columns)
Index(['ph', 'Hardness', 'Solids', 'Chloramines', 'Sulfate', 'Conductivity',
       'Organic_carbon', 'Trihalomethanes', 'Turbidity', 'Potability'],
      dtype='object')

Атрибуты:

  • ph параметр для оценки кислотно-щелочного баланса воды;
  • Hardness жесткость воды, определяемая содержанием кальция и магния;
  • Solids общее количество растворенных веществ, указывающее на минерализацию воды;
  • Chloramines концентрация хлора и хлораминов, использующихся для дезинфекции воды;
  • Sulfate содержание сульфатов, присутствующих в воде;
  • Conductivity электропроводность воды, измеряющая уровень ионов в растворе;
  • Organic_carbon уровень органического углерода, происходящего из разлагающихся органических веществ;
  • Trihalomethanes концентрация трихалометанов, образующихся при обработке хлором;
  • Turbidity мутность воды, указывающая на количество взвешенных твердых частиц;
  • Potability показатель пригодности воды для питья (1 пригодна, 0 непригодна).

Примеры бизнес целей и целей технического проекта:

  1. Совершенствование систем очистки воды.
    • Бизнес-цель: разработка и внедрение инновационных технологий очистки воды, чтобы уменьшить расходы на водоочистные сооружения и повысить их эффективность.
    • Цель технического проекта: проектирование и тестирование новых фильтров и процессов очистки на основе данных о загрязнении воды.
  2. Интеграция данных для управления водными ресурсами.
    • Бизнес-цель: объединение данных о водных ресурсах для комплексного анализа и управления, что позволит более эффективно распределять ресурсы.
    • Цель технического проекта: разработка платформы для интеграции данных с различных датчиков и источников информации, использующей машинное обучение для прогнозирования изменений качества воды.
  3. Повышение осведомленности о качестве воды.
    • Бизнес-цель: информирование населения о состоянии водоемов и возможных рисках для здоровья.
    • Цель технического проекта: разработка платформы для публичного доступа к данным о качестве воды.

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

  1. Входные данные:
    • pH значение;
    • Жесткость воды;
    • Общее количество растворенных веществ;
    • Концентрация хлора и хлораминов;
    • Содержание сульфатов;
    • Электропроводность;
    • Уровень органического углерода;
    • Концентрация трихалометанов;
    • Мутность воды.
  2. Целевой признак:
    • Пригодность воды для питья.

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

Проверяем на выбросы

In [ ]:
columns_to_check = ['Hardness', 'Solids', 'Organic_carbon']

def count_outliers(df, columns):
    outliers_count = {}
    for col in columns:
        Q1 = df[col].quantile(0.25)
        Q3 = df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        
        outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
        outliers_count[col] = len(outliers)
    
    return outliers_count

outliers_count = count_outliers(df, columns_to_check)

for col, count in outliers_count.items():
    print(f"Количество выбросов в столбце '{col}': {count}")

plt.figure(figsize=(15, 10))
for i, col in enumerate(columns_to_check, 1):
    plt.subplot(2, 2, i)
    sns.boxplot(x=df[col])
    plt.title(f'Box Plot of {col}')
plt.tight_layout()
plt.show()
Количество выбросов в столбце 'Hardness': 83
Количество выбросов в столбце 'Solids': 47
Количество выбросов в столбце 'Organic_carbon': 25
No description has been provided for this image

В каждом из выбранных столбцов присутствуют выбросы. Очистим их.

In [4]:
# Выбираем столбцы для очистки
columns_to_clean = ['Hardness', 'Solids', 'Organic_carbon']

# Функция для удаления выбросов
def remove_outliers(df, columns):
    for col in columns:
        Q1 = df[col].quantile(0.25)
        Q3 = df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        
        # Удаляем строки, содержащие выбросы
        df = df[(df[col] >= lower_bound) & (df[col] <= upper_bound)]
    
    return df

# Удаляем выбросы
df_cleaned = remove_outliers(df, columns_to_clean)

# Выводим количество удаленных строк
print(f"Количество удаленных строк: {len(df) - len(df_cleaned)}")

# Создаем диаграммы размаха для очищенных данных
plt.figure(figsize=(15, 6))

# Диаграмма размаха для Hardness
plt.subplot(1, 3, 1)
sns.boxplot(x=df_cleaned['Hardness'])
plt.title('Box Plot of Hardness (Cleaned)')
plt.xlabel('Hardness')

# Диаграмма размаха для Solids
plt.subplot(1, 3, 2)
sns.boxplot(x=df_cleaned['Solids'])
plt.title('Box Plot of Solids (Cleaned)')
plt.xlabel('Solids')

# Диаграмма размаха для Organic_carbon
plt.subplot(1, 3, 3)
sns.boxplot(x=df_cleaned['Organic_carbon'])
plt.title('Box Plot of Organic_carbon (Cleaned)')
plt.xlabel('Organic_carbon')

plt.tight_layout()
plt.show()

# Сохраняем очищенный датасет
df_cleaned.to_csv("..//..//static//csv//water_potability_cleaned.csv", index=False)
df = df_cleaned
Количество удаленных строк: 145
No description has been provided for this image

Теперь проверим на пустые значения

In [5]:
# Количество пустых значений признаков
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}")
ph                 466
Hardness             0
Solids               0
Chloramines          0
Sulfate            746
Conductivity         0
Organic_carbon       0
Trihalomethanes    154
Turbidity            0
Potability           0
dtype: int64

ph                  True
Hardness           False
Solids             False
Chloramines        False
Sulfate             True
Conductivity       False
Organic_carbon     False
Trihalomethanes     True
Turbidity          False
Potability         False
dtype: bool

ph процент пустых значений: %14.88
Sulfate процент пустых значений: %23.83
Trihalomethanes процент пустых значений: %4.92

В трех столбцах встречается большое число пустых значений. Поэтому вместо удаления заменим их значения на медиану.

In [6]:
# Замена значений
df["ph"] = df["ph"].fillna(df["ph"].median())
df["Sulfate"] = df["Sulfate"].fillna(df["Sulfate"].median())
df["Trihalomethanes"] = df["Trihalomethanes"].fillna(df["Trihalomethanes"].median())

# Проверка на пропущенные значения после замены
missing_values_after_drop = df.isnull().sum()

# Вывод результатов после замены
print("\nКоличество пустых значений в каждом столбце после замены:")
print(missing_values_after_drop)
Количество пустых значений в каждом столбце после замены:
ph                 0
Hardness           0
Solids             0
Chloramines        0
Sulfate            0
Conductivity       0
Organic_carbon     0
Trihalomethanes    0
Turbidity          0
Potability         0
dtype: int64

Выборки

In [7]:
X = df.drop('Potability', axis=1)
y = df['Potability']

X_train, X_rem, y_train, y_rem = train_test_split(X, y, train_size=0.6, random_state=42)

X_val, X_test, y_val, y_test = train_test_split(X_rem, y_rem, test_size=0.5, random_state=42)

print("Размер обучающей выборки:", X_train.shape)
print("Размер контрольной выборки:", X_val.shape)
print("Размер тестовой выборки:", X_test.shape)
Размер обучающей выборки: (1878, 9)
Размер контрольной выборки: (626, 9)
Размер тестовой выборки: (627, 9)
In [8]:
def analyze_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))

analyze_balance(y_train, y_val, y_test)
Распределение классов в обучающей выборке:
Potability
0    0.613951
1    0.386049
Name: proportion, dtype: float64

Распределение классов в контрольной выборке:
Potability
0    0.616613
1    0.383387
Name: proportion, dtype: float64

Распределение классов в тестовой выборке:
Potability
0    0.614035
1    0.385965
Name: proportion, dtype: float64

Используем метод оверсемплинг

In [ ]:
smote = SMOTE(random_state=42)

# Применение SMOTE для балансировки обучающей выборки
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)

# Проверка сбалансированности после SMOTE
print("Сбалансированность обучающей выборки после SMOTE:")
print(y_train_resampled.value_counts(normalize=True))
Оверсэмплинг:
Распределение "Комбинированный расход топлива" в обучающей выборке:
combination_mpg
21    32
22    32
25    32
19    32
29    32
23    32
28    32
18    32
27    32
20    32
16    32
30    32
32    32
31    32
24    32
26    32
17    32
36    32
34    32
33    32
14    32
Name: count, dtype: int64

Распределение "Комбинированный расход топлива" в контрольной выборке:
combination_mpg
20    17
19    17
17    17
27    17
22    17
26    17
24    17
32    17
21    17
18    17
30    17
23    17
29    17
28    17
34    17
25    17
14    17
33    17
31    17
Name: count, dtype: int64

Распределение "Комбинированный расход топлива" в тестовой выборке:
combination_mpg
28    14
32    14
30    14
23    14
20    14
26    14
21    14
18    14
27    14
25    14
22    14
19    14
29    14
24    14
31    14
17    14
Name: count, dtype: int64

Андерсэмплинг:
Распределение "Комбинированный расход топлива" в обучающей выборке:
combination_mpg
14    1
16    1
17    1
18    1
19    1
20    1
21    1
22    1
23    1
24    1
25    1
26    1
27    1
28    1
29    1
30    1
31    1
32    1
33    1
34    1
36    1
Name: count, dtype: int64

Распределение "Комбинированный расход топлива" в контрольной выборке:
combination_mpg
14    1
17    1
18    1
19    1
20    1
21    1
22    1
23    1
24    1
25    1
26    1
27    1
28    1
29    1
30    1
31    1
32    1
33    1
34    1
Name: count, dtype: int64

Распределение "Комбинированный расход топлива" в тестовой выборке:
combination_mpg
17    1
18    1
19    1
20    1
21    1
22    1
23    1
24    1
25    1
26    1
27    1
28    1
29    1
30    1
31    1
32    1
Name: count, dtype: int64

Датасет №3 (Экономика стран)

Ссылка: https://www.kaggle.com/datasets/pratik453609/economic-data-9-countries-19802020

Проблемная область: экономический анализ и прогнозирование макроэкономических показателей.

Объекты наблюдения: экономические индексы по странам за определённые годы.

In [19]:
df_countries = pd.read_csv("..//..//static//csv//economic_data.csv")
print(df_countries.columns)
Index(['stock index', 'country', 'year', 'index price', 'log_indexprice',
       'inflationrate', 'oil prices', 'exchange_rate', 'gdppercent',
       'percapitaincome', 'unemploymentrate', 'manufacturingoutput',
       'tradebalance', 'USTreasury'],
      dtype='object')

Атрибуты объектов:

  1. stock index — индекс акций.
  2. country — страна.
  3. year — год.
  4. index price — цена индекса.
  5. log_indexprice — логарифм цены индекса.
  6. inflationrate — уровень инфляции.
  7. oil prices — цены на нефть.
  8. exchange_rate — валютный курс.
  9. gdppercent — процент роста ВВП.
  10. percapitaincome — доход на душу населения.
  11. unemploymentrate — уровень безработицы.
  12. manufacturingoutput — объём производства.
  13. tradebalance — торговый баланс.
  14. USTreasury — доходность казначейских облигаций США.

Связи между объектами: Некоторые атрибуты могут быть связаны друг с другом, например, уровень инфляции и процент роста ВВП могут коррелировать с ценами на нефть, уровнем безработицы и торговым балансом.

Примеры бизнес-целей и эффект:

  1. Прогнозирование экономического роста и планирование инвестиций:

    • Бизнес-цель: Создать модель прогнозирования роста экономики для стран, чтобы принять стратегические инвестиционные решения.
    • Эффект: Повышение точности экономических прогнозов и улучшение прибыльности инвестиционных стратегий.
  2. Анализ и оптимизация торговой политики:

    • Бизнес-цель: Изучение влияния изменений торгового баланса и валютных курсов на экономику стран.
    • Эффект: Улучшение торговых соглашений и политики, что приведёт к более устойчивому экономическому росту.

Примеры целей технического проекта:

  1. Цель: Построение модели для прогнозирования уровня инфляции.

    • Вход: Уровень безработицы, ВВП, доход на душу населения, валютный курс, цены на нефть.
    • Целевой признак: inflationrate.
  2. Цель: Построение модели для оценки экономического роста.

    • Вход: Торговый баланс, доход на душу населения, валютный курс, инфляция.
    • Целевой признак: gdppercent.

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

In [21]:
null_values = df_countries.isnull().sum()
print("Пустые значения по столбцам:")
print(null_values)

duplicates = df_countries.duplicated().sum()
print(f"\nКоличество дубликатов: {duplicates}")
Пустые значения по столбцам:
stock index             0
country                 0
year                    0
index price            52
log_indexprice          0
inflationrate          43
oil prices              0
exchange_rate           2
gdppercent             19
percapitaincome         1
unemploymentrate       21
manufacturingoutput    91
tradebalance            4
USTreasury              0
dtype: int64

Количество дубликатов: 0

Видим, что есть пустые данные, но нет дубликатов. Удаляем их

In [22]:
def drop_missing_values(dataframe, name):
    before_shape = dataframe.shape 
    cleaned_dataframe = dataframe.dropna()  
    after_shape = cleaned_dataframe.shape 
    print(f"В наборе данных '{name}' было удалено {before_shape[0] - after_shape[0]} строк с пустыми значениями.")
    return cleaned_dataframe

df_countries = drop_missing_values(df_countries, "Countries")
В наборе данных 'Countries' было удалено 150 строк с пустыми значениями.

Проверка на выбросы:

In [23]:
columns_to_check = ['year', 'index price', 'log_indexprice',
       'inflationrate', 'oil prices', 'exchange_rate', 'gdppercent',
       'percapitaincome', 'unemploymentrate', 'manufacturingoutput',
       'tradebalance', 'USTreasury']

outliers_count = count_outliers(df_countries, columns_to_check)

for col, count in outliers_count.items():
    print(f"Количество выбросов в столбце '{col}': {count}")

plt.figure(figsize=(15, 10))
for i, col in enumerate(columns_to_check, 1):
    plt.subplot(3, 4, i)
    sns.boxplot(x=df_countries[col])
    plt.title(f'Box Plot of {col}')
plt.tight_layout()
plt.show()
Количество выбросов в столбце 'year': 0
Количество выбросов в столбце 'index price': 17
Количество выбросов в столбце 'log_indexprice': 1
Количество выбросов в столбце 'inflationrate': 35
Количество выбросов в столбце 'oil prices': 0
Количество выбросов в столбце 'exchange_rate': 53
Количество выбросов в столбце 'gdppercent': 13
Количество выбросов в столбце 'percapitaincome': 0
Количество выбросов в столбце 'unemploymentrate': 9
Количество выбросов в столбце 'manufacturingoutput': 29
Количество выбросов в столбце 'tradebalance': 47
Количество выбросов в столбце 'USTreasury': 9
No description has been provided for this image

В большинстве из выбранных столбцов присутствуют выбросы. Очистим их.

In [24]:
columns_to_clean = ['index price', 'log_indexprice',
       'inflationrate', 'exchange_rate', 'gdppercent', 'unemploymentrate', 'manufacturingoutput',
       'tradebalance', 'USTreasury']

df_countries_clean = remove_outliers(df_countries, columns_to_clean)

print(f"Количество удаленных строк: {len(df_countries) - len(df_countries_clean)}")

plt.figure(figsize=(15, 6))

plt.figure(figsize=(15, 10))
for i, col in enumerate(columns_to_clean, 1):
    plt.subplot(3, 3, i)
    sns.boxplot(x=df_countries_clean[col])
    plt.title(f'Box Plot of {col}')
plt.tight_layout()
plt.show()

plt.tight_layout()
plt.show()

df_countries = df_countries_clean
Количество удаленных строк: 136
<Figure size 1500x600 with 0 Axes>
No description has been provided for this image
<Figure size 640x480 with 0 Axes>

Разбиение набора данных на обучающую, контрольную и тестовую выборки

In [25]:
train_df, test_df = train_test_split(df_countries, test_size=0.2, random_state=42)

train_df, val_df = train_test_split(train_df, test_size=0.25, random_state=42)

print("Размер обучающей выборки:", len(train_df))
print("Размер контрольной выборки:", len(val_df))
print("Размер тестовой выборки:", len(test_df))
Размер обучающей выборки: 49
Размер контрольной выборки: 17
Размер тестовой выборки: 17
In [26]:
def check_balance(df, name):
    counts = df['inflationrate'].value_counts()
    print(f"Распределение \"Уровень инфляции\" в {name}:")
    print(counts)
    print()

check_balance(train_df, "обучающей выборке")
check_balance(val_df, "контрольной выборке")
check_balance(test_df, "тестовой выборке")
Распределение "Уровень инфляции" в обучающей выборке:
inflationrate
0.02    25
0.03    11
0.01     9
0.04     4
Name: count, dtype: int64

Распределение "Уровень инфляции" в контрольной выборке:
inflationrate
0.03    6
0.01    6
0.02    5
Name: count, dtype: int64

Распределение "Уровень инфляции" в тестовой выборке:
inflationrate
0.02    6
0.03    6
0.01    4
0.04    1
Name: count, dtype: int64

Оверсемплинг и андерсемплинг

In [27]:
def binning(target, bins):
    return pd.qcut(target, q=bins, labels=False)

train_df['inflationrate_binned'] = binning(train_df['inflationrate'], bins=2)
val_df['inflationrate_binned'] = binning(val_df['inflationrate'], bins=2)
test_df['inflationrate_binned'] = binning(test_df['inflationrate'], bins=2)

train_df_oversampled = oversample(train_df, 'inflationrate_binned')
val_df_oversampled = oversample(val_df, 'inflationrate_binned')
test_df_oversampled = oversample(test_df, 'inflationrate_binned')

train_df_undersampled = undersample(train_df, 'inflationrate_binned')
val_df_undersampled = undersample(val_df, 'inflationrate_binned')
test_df_undersampled = undersample(test_df, 'inflationrate_binned')

print("Оверсэмплинг:")
check_balance(train_df_oversampled, "обучающей выборке")
check_balance(val_df_oversampled, "контрольной выборке")
check_balance(test_df_oversampled, "тестовой выборке")

print("Андерсэмплинг:")
check_balance(train_df_undersampled, "обучающей выборке")
check_balance(val_df_undersampled, "контрольной выборке")
check_balance(test_df_undersampled, "тестовой выборке")
Оверсэмплинг:
Распределение "Уровень инфляции" в обучающей выборке:
inflationrate
0.03    26
0.02    25
0.01     9
0.04     8
Name: count, dtype: int64

Распределение "Уровень инфляции" в контрольной выборке:
inflationrate
0.03    11
0.01     6
0.02     5
Name: count, dtype: int64

Распределение "Уровень инфляции" в тестовой выборке:
inflationrate
0.03    8
0.02    6
0.01    4
0.04    2
Name: count, dtype: int64

Андерсэмплинг:
Распределение "Уровень инфляции" в обучающей выборке:
inflationrate
0.03    11
0.02    10
0.01     5
0.04     4
Name: count, dtype: int64

Распределение "Уровень инфляции" в контрольной выборке:
inflationrate
0.03    6
0.01    4
0.02    2
Name: count, dtype: int64

Распределение "Уровень инфляции" в тестовой выборке:
inflationrate
0.03    6
0.02    5
0.01    2
0.04    1
Name: count, dtype: int64