ISEbd-31_Alimova_M.S._MAI/labs/lab2/lab2.ipynb

421 KiB
Raw Permalink Blame History

Лабораторная работа №2

Ход выполнения работы.

  1. Выбрать три набора данных, которые не соответствуют Вашему варианту задания.
  2. Провести анализ сведений о каждом наборе данных со страницы загрузки в Kaggle. Какова проблемная область?
  3. Провести анализ содержимого каждого набора данных. Что является объектом/объектами наблюдения? Каковы атрибуты объектов? Есть ли связи между объектами?
  4. Привести примеры бизнес-целей, для достижения которых могут подойти выбранные наборы данных. Каков эффект для бизнеса?
  5. Привести примеры целей технического проекта для каждой выделенной ранее бизнес-цели. Что поступает на вход, что является целевым признаком?
  6. Определить проблемы выбранных наборов данных: зашумленность, смещение, актуальность, выбросы, просачивание данных.
  7. Привести примеры решения обнаруженных проблем для каждого набора данных.
  8. Оценить качество каждого набора данных: информативность, степень покрытия, соответствие реальным данным, согласованность меток.
  9. Устранить проблему пропущенных данных. Для каждого набора данных использовать разные методы: удаление, подстановка константного значения (0 или подобное), подстановка среднего значения.
  10. Выполнить разбиение каждого набора данных на обучающую, контрольную и тестовую выборки.
  11. Оценить сбалансированность выборок для каждого набора данных. Оценить необходимость использования методов приращения (аугментации) данных.
  12. Выполнить приращение данных методами выборки с избытком (oversampling) и выборки с недостатком (undersampling). Должны быть представлены примеры реализации обоих методов для выборок каждого набора данных.
  13. Все выводы и программный код должны быть оформлены в виде ноутбука. Для выполнения данной лабораторной работы следует создать новый файл-ноутбук.

Пункты 1-5.

Были выбраны датасеты:

  1. Объекты вокруг Земли (https://www.kaggle.com/datasets/sameepvani/nasa-nearest-earth-objects)
  2. Экономика стран (https://www.kaggle.com/datasets/pratik453609/economic-data-9-countries-19802020)
  3. Цены на мобильное устройство (https://www.kaggle.com/datasets/dewangmoghe/mobile-phone-price-prediction)

Объекты вокруг Земли

Проблемная область: космические объекты и их угроза для Земли

Объект наблюдения: астероиды и другие малые тела Солнечной системы

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

Пример бизнес-цели:

  1. Разработка и продажа страховых продуктов для космических рисков. Цель технического проекта: разработка системы оценки рисков и ценообразования для страховых продуктов, защищающих от космических угроз.

  2. Разработка и продажа технологий для мониторинга и предотвращения космических угроз. Цель технического проекта: создание системы мониторинга и прогнозирования траекторий небесных тел для предотвращения космических угроз.

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

Экономика стран

Проблемная область: экономические данные по странам

Объект наблюдения: каждая страна (например, США, Франция) выступает отдельным объектом наблюдения.

Атрибуты: фондовый индекс: среднегодовая цена индекса, инфляция (inflationrate): годовой уровень инфляции, цена на нефть (oil prices): среднегодовая стоимость нефти, обменный курс (exchange_rate): курс национальной валюты к доллару США, ВВП в процентах (gdppercent): прирост ВВП, доход на душу населения (percapitaincome): средний доход на человека в стране.

Пример бизнес-цели:

  1. Определение факторов, влияющих на рост фондового рынка в различных странах (эффект для бизнеса: позволяет финансовым компаниям и инвесторам создавать более эффективные стратегии вложений)
  2. Прогнозирование инфляции и курсов валют (эффект для бизнеса: помогает компаниям адаптироваться к колебаниям на валютных рынках и снижать риски при операциях с иностранной валютой)

Цены на мобильные устройства

Проблемная область: цены, характеристики мобильных устройств разных компаний.

Объект наблюдения: каждый мобильный телефон представляет собой отдельный объект.

Атрибуты: фондовый индекс: рейтинг, спецификации, количество SIM-карт, поддержка сетей (3G, 4G, 5G), оперативная память (RAM), батарея: емкость батареи, экран (размер и разрешение), камера: характеристика камеры (основной и фронтальной), встроенная и внешняя память, версия Android, процессор, поддержка быстрой зарядки.

Пример бизнес-цели:

  1. Анализ характеристик, влияющих на рейтинг и популярность модели. Эффект для бизнеса: помогает производителям оптимизировать параметры устройства для увеличения спроса.
  2. Оптимизация ценовой стратегии в зависимости от характеристик. Эффект для бизнеса: позволяет разработать ценовые сегменты, соответствующие характеристикам, и повысить конкурентоспособность.

№6. Сперва напишем функции для определения проблем выбранных наборов данных: зашумленности, смещения, актуальности, выбросов, просачивания данных.

In [ ]:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt


#Проверка на зашумленность
def check_noise(dataframe):
    total_values = dataframe.size
    missing_values = dataframe.isnull().sum().sum()
    noise_percentage = (missing_values / total_values) * 100
    return f"Зашумленность: {noise_percentage:.2f}%"


#Проверка на смещение 
def check_bias(dataframe, target_column):
    if target_column in dataframe.columns:
        unique_values = dataframe[target_column].nunique()
        total_values = len(dataframe)
        bias_percentage = (unique_values / total_values) * 100
        return (
            f"Смещение по {target_column}: {bias_percentage:.2f}% уникальных значений"
        )
    return "Целевой признак не найден."


#Проверка на дубликаты
def check_duplicates(dataframe):
    duplicate_percentage = dataframe.duplicated().mean() * 100
    return f"Количество дубликатов: {duplicate_percentage:.2f}%"


#Проверка на выбросы
def check_outliers(dataframe, column):
    if column in dataframe.columns:
        Q1 = dataframe[column].quantile(0.25)
        Q3 = dataframe[column].quantile(0.75)
        IQR = Q3 - Q1
        lower_bound = Q1 - 1.5 * IQR
        upper_bound = Q3 + 1.5 * IQR
        outlier_count = dataframe[
            (dataframe[column] < lower_bound) | (dataframe[column] > upper_bound)
        ].shape[0]
        total_count = dataframe.shape[0]
        outlier_percentage = (outlier_count / total_count) * 100
        return f"Выбросы по {column}: {outlier_percentage:.2f}%"
    return f"Признак {column} не найден."


#Проверка на просачивание данных
def check_data_leakage(dataframe, target_column):
    if target_column in dataframe.columns:
        correlation_matrix = dataframe.select_dtypes(include=[np.number]).corr()
        leakage_info = correlation_matrix[target_column].abs().nlargest(10)
        leakage_report = ", ".join(
            [
                f"{feature}: {value:.2f}"
                for feature, value in leakage_info.items()
                if feature != target_column
            ]
        )
        return f"Признаки просачивания данных: {leakage_report}"
    return "Целевой признак не найден."

Датасет 1. Объекты вокруг земли

In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Вывод всех столбцов

df_neo = pd.read_csv("neo.csv")
print(df_neo.columns)
Index(['id', 'name', 'est_diameter_min', 'est_diameter_max',
       'relative_velocity', 'miss_distance', 'orbiting_body', 'sentry_object',
       'absolute_magnitude', 'hazardous'],
      dtype='object')
In [19]:
noise_columns = check_noise(df_neo)
bias_info = check_bias(df_neo, "miss_distance")
duplicate_count = check_duplicates(df_neo)
outliers_data = check_outliers(df_neo, "relative_velocity")
leakage_info = check_data_leakage(df_neo, "absolute_magnitude")

print(noise_columns)
print(bias_info)
print(duplicate_count)
print(outliers_data)
print(leakage_info)
Зашумленность: 0.00%
Смещение по miss_distance: 99.67% уникальных значений
Количество дубликатов: 0.00%
Выбросы по relative_velocity: 1.73%
Признаки просачивания данных: est_diameter_min: 0.56, est_diameter_max: 0.56, relative_velocity: 0.35, id: 0.28, miss_distance: 0.26

Датасет 7. Экономика стран

In [44]:
df_ed = pd.read_csv("economic_data.csv")
print(df_ed.columns)
Index(['stock index', 'country', 'year', 'index price', 'log_indexprice',
       'inflationrate', 'oil prices', 'exchange_rate', 'gdppercent',
       'percapitaincome', 'unemploymentrate', 'manufacturingoutput',
       'tradebalance', 'USTreasury'],
      dtype='object')
In [50]:
noise_columns = check_noise(df_ed)
bias_info = check_bias(df_ed, "index price")
duplicate_count = check_duplicates(df_ed)
outliers_data = check_outliers(df_ed, "unemploymentrate")
leakage_info = check_data_leakage(df_ed, "inflationrate")

print(noise_columns)
print(bias_info)
print(duplicate_count)
print(outliers_data)
print(leakage_info)
Зашумленность: 4.51%
Смещение по index price: 85.64% уникальных значений
Количество дубликатов: 0.00%
Выбросы по unemploymentrate: 4.88%
Признаки просачивания данных: percapitaincome: 0.51, USTreasury: 0.49, year: 0.47, log_indexprice: 0.34, gdppercent: 0.26, oil prices: 0.22, unemploymentrate: 0.18, manufacturingoutput: 0.11, index price: 0.08

Датасет 18. Цена на мобильные устройства

In [51]:
df_mp = pd.read_csv("mobile_phone_price_prediction.csv")
print(df_mp.columns)
Index(['Unnamed: 0', 'Name', 'Rating', 'Spec_score', 'No_of_sim', 'Ram',
       'Battery', 'Display', 'Camera', 'External_Memory', 'Android_version',
       'Price', 'company', 'Inbuilt_memory', 'fast_charging',
       'Screen_resolution', 'Processor', 'Processor_name'],
      dtype='object')
In [53]:
noise_columns = check_noise(df_mp)
bias_info = check_bias(df_mp, "Name")
duplicate_count = check_duplicates(df_mp)
outliers_data = check_outliers(df_mp, "Spec_score")
leakage_info = check_data_leakage(df_mp, "Rating")

print(noise_columns)
print(bias_info)
print(duplicate_count)
print(outliers_data)
print(leakage_info)
Зашумленность: 2.36%
Смещение по Name: 97.37% уникальных значений
Количество дубликатов: 0.00%
Выбросы по Spec_score: 1.24%
Признаки просачивания данных: Spec_score: 0.06, Unnamed: 0: 0.03

Датасет 1. Объекты вокруг Земли

In [56]:
df_neo.isnull().sum()
Out[56]:
id                    0
name                  0
est_diameter_min      0
est_diameter_max      0
relative_velocity     0
miss_distance         0
orbiting_body         0
sentry_object         0
absolute_magnitude    0
hazardous             0
dtype: int64

Пропущенных значений нет, поэтому пропускаем.

Датасет 7. Экономика стран

In [57]:
df_ed.isnull().sum()
Out[57]:
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

Имеются пустые значения. На их место поставим "No value"

In [58]:
df_ed["index price"] = df_ed["index price"].fillna("No value")
df_ed["inflationrate"] = df_ed["inflationrate"].fillna("No value")
df_ed["exchange_rate"] = df_ed["exchange_rate"].fillna("No value")
df_ed["gdppercent"] = df_ed["gdppercent"].fillna("No value")
df_ed["percapitaincome"] = df_ed["percapitaincome"].fillna("No value")
df_ed["unemploymentrate"] = df_ed["unemploymentrate"].fillna("No value")
df_ed["manufacturingoutput"] = df_ed["manufacturingoutput"].fillna("No value")
df_ed["tradebalance"] = df_ed["tradebalance"].fillna("No value")
In [ ]:
df_ed["index price"] = df_ed["index price"].replace("No value", 0)
df_ed["inflationrate"] = df_ed["inflationrate"].replace("No value", 0)
df_ed["exchange_rate"] = df_ed["exchange_rate"].replace("No value", 0)
df_ed["gdppercent"] = df_ed["gdppercent"].replace("No value", 0)
df_ed["percapitaincome"] = df_ed["percapitaincome"].replace("No value", 0)
df_ed["unemploymentrate"] = df_ed["unemploymentrate"].replace("No value", 0)
df_ed["manufacturingoutput"] = df_ed["manufacturingoutput"].replace("No value", 0)
df_ed["tradebalance"] = df_ed["tradebalance"].replace("No value", 0)

Снова проверим датафрейм на наличие пустых значений:

In [59]:
df_ed.isnull().sum()
Out[59]:
stock index            0
country                0
year                   0
index price            0
log_indexprice         0
inflationrate          0
oil prices             0
exchange_rate          0
gdppercent             0
percapitaincome        0
unemploymentrate       0
manufacturingoutput    0
tradebalance           0
USTreasury             0
dtype: int64

Датасет 18. Цены на мобильные устройства

In [65]:
df_mp.isnull().sum()
Out[65]:
Unnamed: 0             0
Name                   0
Rating                 0
Spec_score             0
No_of_sim              0
Ram                    0
Battery                0
Display                0
Camera                 0
External_Memory        0
Android_version      443
Price                  0
company                0
Inbuilt_memory        19
fast_charging         89
Screen_resolution      2
Processor             28
Processor_name         0
dtype: int64
In [66]:
df_mp["Android_version"] = df_mp["Android_version"].fillna("No value")
df_mp["Inbuilt_memory"] = df_mp["Inbuilt_memory"].fillna("No value")
df_mp["fast_charging"] = df_mp["fast_charging"].fillna("No value")
df_mp["Screen_resolution"] = df_mp["Screen_resolution"].fillna("No value")
df_mp["Processor"] = df_mp["Processor"].fillna("No value")
In [ ]:
df_mp["Android_version"] = df_mp["Android_version"].replace("No value", 0)
df_mp["Inbuilt_memory"] = df_mp["Inbuilt_memory"].replace("No value", 0)
df_mp["fast_charging"] = df_mp["fast_charging"].replace("No value", 0)
df_mp["Screen_resolution"] = df_mp["Screen_resolution"].replace("No value", 0)
df_mp["Processor"] = df_mp["Processor"].replace("No value", 0)
In [67]:
df_mp.isnull().sum()
Out[67]:
Unnamed: 0           0
Name                 0
Rating               0
Spec_score           0
No_of_sim            0
Ram                  0
Battery              0
Display              0
Camera               0
External_Memory      0
Android_version      0
Price                0
company              0
Inbuilt_memory       0
fast_charging        0
Screen_resolution    0
Processor            0
Processor_name       0
dtype: int64
  1. Выполнить разбиение каждого набора данных на обучающую, контрольную и тестовую выборки.
In [71]:
from sklearn.model_selection import train_test_split
In [72]:
# Разбиение df_neo

original_df_neo_size = len(df_neo)
train_df_neo, temp_df_neo = train_test_split(df_neo, test_size=0.2, random_state=42)
val_df_neo, test_df_neo = train_test_split(temp_df_neo, test_size=0.5, random_state=42)

print("df_neo Dataset:")
print(f"Train: {len(train_df_neo)/original_df_neo_size*100:.2f}%")
print(f"Validation: {len(val_df_neo)/original_df_neo_size*100:.2f}%")
print(f"Test: {len(test_df_neo)/original_df_neo_size*100:.2f}%\n")
df_neo Dataset:
Train: 80.00%
Validation: 10.00%
Test: 10.00%

In [85]:
# Разбиение df_ed

original_df_ed_size = len(df_ed)
train_df_ed, temp_df_ed = train_test_split(df_ed, test_size=0.2, random_state=42)
val_df_ed, test_df_ed = train_test_split(temp_df_ed, test_size=0.5, random_state=42)

print("df_ed Dataset:")
print(f"Train: {len(train_df_ed)/original_df_ed_size*100:.2f}%")
print(f"Validation: {len(val_df_ed)/original_df_ed_size*100:.2f}%")
print(f"Test: {len(test_df_ed)/original_df_ed_size*100:.2f}%\n")
df_ed Dataset:
Train: 79.95%
Validation: 10.03%
Test: 10.03%

In [88]:
# Разбиение df_mp

original_df_mp_size = len(df_mp)
train_df_mp, temp_df_mp = train_test_split(df_mp, test_size=0.2, random_state=42)
val_df_mp, test_df_mp = train_test_split(temp_df_mp, test_size=0.5, random_state=42)

print("df_mp Dataset:")
print(f"Train: {len(train_df_mp)/original_df_mp_size*100:.2f}%")
print(f"Validation: {len(val_df_mp)/original_df_mp_size*100:.2f}%")
print(f"Test: {len(test_df_mp)/original_df_mp_size*100:.2f}%\n")
df_mp Dataset:
Train: 80.00%
Validation: 10.00%
Test: 10.00%

  1. Оценить сбалансированность выборок для каждого набора данных. Оценить необходимость использования методов приращения (аугментации) данных.
In [77]:
def plot_sample_balance(y, sample_name):
    plt.figure(figsize=(8, 5))
    sns.histplot(y, bins=30, kde=True)
    plt.title(f"Распределение целевой переменной для {sample_name}")
    plt.xlabel(sample_name)
    plt.ylabel("Частота")
    plt.show()


# Оценка сбалансированности выборок
plot_sample_balance(train_df_neo["relative_velocity"], "Train df_neo")
plot_sample_balance(val_df_neo["relative_velocity"], "Validation df_neo")
plot_sample_balance(test_df_neo["relative_velocity"], "Test df_neo")
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Кажется, выборки сбалансированы.

In [86]:
# Оценка сбалансированности выборок
plot_sample_balance(train_df_ed["inflationrate"], "Train df_ed")
plot_sample_balance(val_df_ed["inflationrate"], "Validation df_ed")
plot_sample_balance(test_df_ed["inflationrate"], "Test df_ed")
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

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

In [90]:
# Оценка сбалансированности выборок
plot_sample_balance(train_df_mp["Ram"], "Train df_mp")
plot_sample_balance(val_df_mp["Ram"], "Validation df_mp")
plot_sample_balance(test_df_mp["Ram"], "Test df_mp")
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

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

  1. Выполнить приращение данных методами выборки с избытком (oversampling) и выборки с недостатком (undersampling). Должны быть представлены примеры реализации обоих методов для выборок каждого набора данных.
In [93]:
from imblearn.over_sampling import SMOTE

Датасет 1.

In [97]:
X_df_neo = df_neo.drop("hazardous", axis=1)
y_df_neo = df_neo["hazardous"]

# Кодирование категориальных признаков
for column in X_df_neo.select_dtypes(include=["object"]).columns:
    X_df_neo[column] = X_df_neo[column].astype("category").cat.codes

# Теперь применяем SMOTE
smote = SMOTE(random_state=42)
X_resampled_df_neo, y_resampled_df_neo = smote.fit_resample(X_df_neo, y_df_neo)

# Получаем результаты
print(f"После oversampling (df_neo): {pd.Series(y_resampled_df_neo).value_counts()}")
После oversampling (df_neo): hazardous
False    81996
True     81996
Name: count, dtype: int64
In [98]:
from imblearn.under_sampling import RandomUnderSampler

# Undersampling df_neo
undersample = RandomUnderSampler(random_state=42)
X_under_df_neo, y_under_df_neo = undersample.fit_resample(X_df_neo, y_df_neo)

print(f"После undersampling (df_neo): {pd.Series(y_under_df_neo).value_counts()}")
После undersampling (df_neo): hazardous
False    8840
True     8840
Name: count, dtype: int64

Датасет 7.

In [101]:
X_df_ed = df_ed.drop("country", axis=1)
y_df_ed = df_ed["country"]

# Кодирование категориальных признаков
for column in X_df_ed.select_dtypes(include=["object"]).columns:
    X_df_ed[column] = X_df_ed[column].astype("category").cat.codes

# Теперь применяем SMOTE
smote = SMOTE(random_state=42)
X_resampled_df_ed, y_resampled_df_ed = smote.fit_resample(X_df_ed, y_df_ed)

# Получаем результаты
print(f"После oversampling (df_ed): {pd.Series(y_resampled_df_ed).value_counts()}")
После oversampling (df_ed): country
United States of America    41
United Kingdom              41
India                       41
Japan                       41
Hong Kong                   41
China                       41
Germany                     41
France                      41
Spain                       41
Name: count, dtype: int64
In [102]:
from imblearn.under_sampling import RandomUnderSampler

# Undersampling df_ed
undersample = RandomUnderSampler(random_state=42)
X_under_df_ed, y_under_df_ed = undersample.fit_resample(X_df_ed, y_df_ed)

print(f"После undersampling (df_ed): {pd.Series(y_under_df_ed).value_counts()}")
После undersampling (df_ed): country
China                       41
France                      41
Germany                     41
Hong Kong                   41
India                       41
Japan                       41
Spain                       41
United Kingdom              41
United States of America    41
Name: count, dtype: int64

Датасет 18.

In [107]:
X_df_mp = df_mp.drop("Battery", axis=1)
y_df_mp = df_mp["Battery"]

# Кодирование категориальных признаков
for column in X_df_mp.select_dtypes(include=["object"]).columns:
    X_df_mp[column] = X_df_mp[column].astype("category").cat.codes

# Теперь применяем SMOTE
smote = SMOTE(random_state=42)
X_resampled_df_mp, y_resampled_df_mp = smote.fit_resample(X_df_mp, y_df_mp)

# Получаем результаты
print(f"После oversampling (df_mp): {pd.Series(y_resampled_df_mp).value_counts()}")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[107], line 10
      8 # Теперь применяем SMOTE
      9 smote = SMOTE(random_state=42)
---> 10 X_resampled_df_mp, y_resampled_df_mp = smote.fit_resample(X_df_mp, y_df_mp)
     12 # Получаем результаты
     13 print(f"После oversampling (df_mp): {pd.Series(y_resampled_df_mp).value_counts()}")

File c:\Users\nemar\AppData\Local\Programs\Python\Python312\Lib\site-packages\imblearn\base.py:208, in BaseSampler.fit_resample(self, X, y)
    187 """Resample the dataset.
    188 
    189 Parameters
   (...)
    205     The corresponding label of `X_resampled`.
    206 """
    207 self._validate_params()
--> 208 return super().fit_resample(X, y)

File c:\Users\nemar\AppData\Local\Programs\Python\Python312\Lib\site-packages\imblearn\base.py:112, in SamplerMixin.fit_resample(self, X, y)
    106 X, y, binarize_y = self._check_X_y(X, y)
    108 self.sampling_strategy_ = check_sampling_strategy(
    109     self.sampling_strategy, y, self._sampling_type
    110 )
--> 112 output = self._fit_resample(X, y)
    114 y_ = (
    115     label_binarize(output[1], classes=np.unique(y)) if binarize_y else output[1]
    116 )
    118 X_, y_ = arrays_transformer.transform(output[0], y_)

File c:\Users\nemar\AppData\Local\Programs\Python\Python312\Lib\site-packages\imblearn\over_sampling\_smote\base.py:389, in SMOTE._fit_resample(self, X, y)
    386 X_class = _safe_indexing(X, target_class_indices)
    388 self.nn_k_.fit(X_class)
--> 389 nns = self.nn_k_.kneighbors(X_class, return_distance=False)[:, 1:]
    390 X_new, y_new = self._make_samples(
    391     X_class, y.dtype, class_sample, X_class, nns, n_samples, 1.0
    392 )
    393 X_resampled.append(X_new)

File c:\Users\nemar\AppData\Local\Programs\Python\Python312\Lib\site-packages\sklearn\neighbors\_base.py:834, in KNeighborsMixin.kneighbors(self, X, n_neighbors, return_distance)
    832     else:
    833         inequality_str = "n_neighbors <= n_samples_fit"
--> 834     raise ValueError(
    835         f"Expected {inequality_str}, but "
    836         f"n_neighbors = {n_neighbors}, n_samples_fit = {n_samples_fit}, "
    837         f"n_samples = {X.shape[0]}"  # include n_samples for common tests
    838     )
    840 n_jobs = effective_n_jobs(self.n_jobs)
    841 chunked_results = None

ValueError: Expected n_neighbors <= n_samples_fit, but n_neighbors = 6, n_samples_fit = 1, n_samples = 1

В данном случае у нас есть два датасета, предназначенных для решения задачи классификации (df_neo, df_ed). Проблему дисбаланса в них мы решили применив undersampling и oversampling.

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