Все задачи
Средне Решено: 0 Процент решений: 0%

Наивный байесовский классификатор

Предскажите класс по категориальным признакам с помощью теоремы Байеса и сглаживания Лапласа.

Чему вы научитесь

  • Вычислять априорные вероятности классов и правдоподобия
  • Сглаживать невиданные значения признаков
  • Выбирать наиболее вероятный класс

Условие

Наивный Байес предполагает, что при известном классе признаки независимы, и выбирает класс с наибольшей оценкой:

score(c) = P(c) × P(x₁ | c) × P(x₂ | c) × … × P(xₙ | c)

Признаки — это категории, закодированные целыми числами. Оцените вероятности по обучающим данным:

  • P(c) = (число примеров класса c) / (число примеров)
  • P(xⱼ = v | c) = (число примеров класса c, у которых признак j равен v, + 1) / (число примеров класса c + Kⱼ)

где Kⱼ — число различных значений признака j среди обучающих примеров и запроса. Слагаемое +1 (сглаживание Лапласа) не даёт невиданному значению обнулить оценку.

Верните класс с наибольшей оценкой; при равенстве — меньший класс. Перемножение множества малых вероятностей может дать потерю точности, поэтому складывайте логарифмы.

Реализуйте naive_bayes_predict(features, labels, query).

Входные данные

features: по строке из n категориальных признаков на обучающий пример.

labels: класс каждого обучающего примера.

query: n признаков примера, который нужно классифицировать.

Выходные данные

Верните предсказанный класс.

Ограничения

1 ≤ число примеров ≤ 1000, 1 ≤ n ≤ 20

0 ≤ каждое значение признака и метка ≤ 100

Примеры

Пример 1
Ввод:
query = [0, 1]
labels = [1, 1, 0, 0, 1]
features = [
    [0, 1],
    [0, 0],
    [1, 1],
    [1, 0],
    [0, 1]
]

Ожидаемый вывод:
expected = 1
Ввод:
std::vector<long long> query = {0, 1};
std::vector<long long> labels = {1, 1, 0, 0, 1};
std::vector<std::vector<long long>> features = {
    {0, 1},
    {0, 0},
    {1, 1},
    {1, 0},
    {0, 1}
};

Ожидаемый вывод:
long long expected = 1;
Ввод:
long[] query = new long[] {0, 1};
long[] labels = new long[] {1, 1, 0, 0, 1};
long[][] features = new long[][] {
    new long[] {0, 1},
    new long[] {0, 0},
    new long[] {1, 1},
    new long[] {1, 0},
    new long[] {0, 1}
};

Ожидаемый вывод:
long expected = 1;

Пояснение

В классе 1 три примера, в классе 0 — два. Признак 1 принимает значения {0, 1} (K = 2), признак 2 — {0, 1} (K = 2). score(1) = 3/5 × (3+1)/(3+2) × (2+1)/(3+2) = 0.6 × 0.8 × 0.6 = 0.288. score(0) = 2/5 × (0+1)/(2+2) × (1+1)/(2+2) = 0.4 × 0.25 × 0.5 = 0.05. Побеждает класс 1.

Пример 2
Ввод:
query = [2]
labels = [0, 0, 1]
features = [
    [0],
    [0],
    [1]
]

Ожидаемый вывод:
expected = 0
Ввод:
std::vector<long long> query = {2};
std::vector<long long> labels = {0, 0, 1};
std::vector<std::vector<long long>> features = {
    {0},
    {0},
    {1}
};

Ожидаемый вывод:
long long expected = 0;
Ввод:
long[] query = new long[] {2};
long[] labels = new long[] {0, 0, 1};
long[][] features = new long[][] {
    new long[] {0},
    new long[] {0},
    new long[] {1}
};

Ожидаемый вывод:
long expected = 0;

Пояснение

Значение 2 ни разу не встречается, поэтому K = 3 (значения 0, 1 и 2). score(0) = 2/3 × (0+1)/(2+3) ≈ 0.133 и score(1) = 1/3 × (0+1)/(1+3) ≈ 0.083. Благодаря сглаживанию ни одна оценка не равна 0, и побеждает более частый класс 0.

Ссылки

Это задание адаптировано для CodeUtility. Следуйте условию и ограничениям выше.

Учитесь у других

Решения сообщества

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