Как справиться с отсутствующими данными для наивного байесовского классификатора Бернулли?

Вопрос или проблема

Я работаю с набором данных категориальных данных, который выглядит так:

    content_1   content_2   content_4   content_5   content_6   
0         NaN         0.0         0.0         0.0         NaN 
1         NaN         0.0         0.0         0.0         NaN   
2         NaN         NaN         NaN         NaN         NaN   
3         0.0         NaN         0.0         NaN         0.0   

Эти данные представляют собой загрузки пользователей с интранета, где пользователю предлагается возможность загрузить определенный контент. 1 означает, что пользователь увидел контент и загрузил его, 0 означает, что пользователь увидел контент, но не загрузил его, а NaN означает, что пользователь не видел/не было показано этот контент.

Я пытаюсь использовать модель наивного байеса Бернулли в scikit-learn, чтобы предсказать вероятность того, что пользователь загрузит content_1, в зависимости от того, видел ли он загруженный / не загруженный content_2-7.

Я удалил все данные, где content_1 равен NaN, так как меня, очевидно, интересуют только те точки данных, где пользователем было принято активное решение. Это дает данные в виде:

    content_1   content_2   content_3   content_4   content_5   content_6   
0         1.0         NaN         1.0         NaN         NaN         1.0 
1         0.0         NaN         NaN         0.0         1.0         0.0    
2         1.0         0.0         NaN         NaN         NaN         1.0    

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

Я знаю из этих вопросов: 1, что есть в основном 3 варианта при работе с пропущенными значениями:

  1. игнорировать точку данных, если какие-либо категории содержат NaN (т.е. удалить строку)
  2. импутировать какое-то другое замещающее значение (например, -1 и т.д.) или
  3. импутировать среднее значение, соответствующее распределению общего набора данных.

Тем не менее, это не лучший вариант по следующим причинам:

  1. Каждая строка содержит хотя бы 1 NaN. Это означает, что при такой организации я бы исключил весь набор данных. Очевидно, это не вариант.
  2. Я не хочу, чтобы пропущенное значение добавляло к расчету вероятности, что произойдет, если я заменю NaN скажем, на -1. Я также использую наивный байес Бернулли, так что, насколько я понимаю, это требует только 0 или 1 значений.
  3. Поскольку это категориальные данные, не имеет смысла делать это таким образом (это либо было увидено, либо нет, и если нет, это не нужно).

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

Я не знаю, как закодировать это при использовании модели наивного байеса в scikit-learn, следует ли это делать как пропущенное значение.

Вот что у меня есть на данный момент:

df=pd.read_clipboard()
from sklearn import datasets
from sklearn.naive_bayes import BernoulliNB
# Создание обучающих входных/выходных данных
y_train = df['content_1'].values
X_train = df.drop('content_1', axis=1).values
# Загрузка модели наивного байеса Бернулли
clf = BernoulliNB()
clf.fit(X_train, y_train)

Очевидно, это вызывает ошибку из-за присутствующих NaN. Итак, как я могу настроить модель Бернулли в scikit-learn, чтобы она автоматически игнорировала столбцы с NaN, а вместо этого принимала только те, у которых 0 или 1?

Я понимаю, что это может быть невозможно с обычной моделью, и просмотр документации кажется это предполагает. Таким образом, это может потребовать значительного кодирования, поэтому я скажу так: Я не прошу кого-либо писать код для меня (да и не ожидаю этого); я ищу направления, например, если кто-то сталкивался с этой проблемой / как они к ней подходили / соответствующие блоги или учебные материалы (мои поиски не дали результатов).

Заранее спасибо – ценю, что вы прочитали.

Ваши результаты поиска точны: не удаляя и не импутируя данные, нет встроенного способа сделать то, что вы хотите с BernoulliNB.

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

Фильтрация

Фильтрация здесь означает:

  • Изоляцию выборок из вашего оригинального df, каждая из которых имеет только подмножество df.columns. Таким образом, у вас будет DataFrame только для content_2, один для content_2, content_3, что-то вроде факториальной комбинации столбцов.
  • Убедитесь, что каждая выборка состоит только из строк, которые не содержат NaN для любых столбцов в подмножестве.

Эта часть является относительно простой в вашем случае, но немного длинной: у вас будет $n!$ (n факториал) комбинаций столбцов, каждая из которых приведет к отдельной выборке. Например, вы можете иметь выборку с именем df_c2, содержащую только строки content_2, значения 0 или 1, df_c2_c3 с только столбцами content_2 и content_3 и так далее.

Эти выборки сделают значения NaN несуществующими для каждой модели, которую вы будете обучать. Реализация этого в умном виде может быть громоздкой, поэтому я советую начать с самых простых сценариев – например, две выборки, две модели; вы будете постепенно улучшаться и достигнете надежного решения в коде.

Стекинг Байесовских Моделей

Это называется Bayesian Model Averaging (BMA), и как концепция это подробно рассмотрено в этой статье. Там вес, приписываемый предсказаниям байесовской модели, это ее апостериорная вероятность.

Содержимое может быть подавляющим, чтобы усвоить за раз, не волнуйтесь, если что-то из этого не запоминается. Основная мысль здесь состоит в том, что вам следует умножить предсказанные вероятности каждой модели на вес 0 < w < 1, а затем сложить (результаты суммы должны находиться в $[0, 1]$). Вначале вы можете приписать веса эмпирически и посмотреть, к чему это вас приведет.


Редактировать:

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

Один из вариантов — это sklearn.impute.IterativeImputer от scikit-learn. initial_strategy можно установить на “most_frequent”, что является полезным способом моделирования распределения Бернулли признаков.

Ответ или решение

Как обработать отсутствующие данные для модели Бернулли Наивного Байеса

Когда вы работаете с набором данных, содержащим категориальные переменные, такие как в вашем случае с пользовательскими загрузками контента, отсутствие данных (NaN) может стать серьезной помехой для анализа. В частности, если вы планируете использовать модель Бернулли Наивного Байеса из библиотеки scikit-learn для предсказания вероятности загрузки контента, важно правильно справляться с отсутствующими значениями.

Проблема отсутствующих данных

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

Опции для обработки отсутствующих данных

  1. Удаление строк: Это крайний вариант, который не подходит в вашем случае, так как приведет к удалению всех наблюдений.

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

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

Подход через фильтрацию и комбинирование моделей

Фильтрация данных:

  • Избавьтесь от NaN в каждой подгруппе, создавая подмножества данных с уникальными наборами колонок, содержащими только непустые значения. Таким образом, каждая модель будет тренироваться только на полных строках данных.

Например, если вы хотите создать модель, использующую только content_2 и content_3, вам нужно выглядеть следующим образом:

filtered_df = df[['content_1', 'content_2', 'content_3']].dropna()
y_train = filtered_df['content_1'].values
X_train = filtered_df[['content_2', 'content_3']].values

clf = BernoulliNB()
clf.fit(X_train, y_train)
  • Проделайте это для каждого возможного сочетания колонок, избегая NaN.

Комбинирование предсказаний:

  • Используйте метод Bayesian Model Averaging (BMA) для объединения предсказаний от разных моделей. Построив модели на различных подмножеств данных, вы можете комбинировать их предсказания, что обеспечит более устойчивый результат. Взвешивайте каждое предсказание в зависимости от его вероятности.

Пример реализации

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

import pandas as pd
from sklearn.naive_bayes import BernoulliNB

# Загрузите данные
df = pd.read_clipboard()

# Список всех доступных колонок
columns = df.columns.tolist()
predictions = []

# Генерация всех возможных сочетаний предикторов
from itertools import combinations

for r in range(1, len(columns)):
    for combo in combinations(columns[1:], r):  # исключите target column
        filtered_df = df[list(combo)].dropna()
        if not filtered_df.empty:
            y_train = filtered_df['content_1'].values
            X_train = filtered_df[combo].values

            clf = BernoulliNB()
            clf.fit(X_train, y_train)

            # Получите предсказания для каждого выбора
            predictions.append((combo, clf.predict_proba(X_train)))

# Объединение предсказаний
# Ваш метод для объединения предсказаний

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...