Вопрос или проблема
Я работаю над реализацией алгоритма классификации Наивного Байеса. У меня есть метод def prob_continous_value
, который должен возвращать функцию плотности вероятности для атрибута, заданного классовым атрибутом. Задача заключается в классификации следующих наборов данных:
Venue,color,Model,Category,Location,weight,Veriety,Material,Volume
1,6,4,4,4,1,1,1,6
2,5,4,4,4,2,6,1,1
1,6,2,1,4,1,4,2,4
1,6,2,1,4,1,2,1,2
2,6,5,5,5,2,2,1,2
1,5,4,4,4,1,6,2,2
1,3,3,3,3,1,6,2,2
1,5,2,1,1,1,2,1,2
1,4,4,4,1,1,5,3,6
1,4,4,4,4,1,6,4,6
2,5,4,4,4,2,4,4,1
2,4,3,3,3,2,1,1,1
Venue,color,Model,Category,Location,weight,Veriety,Material,Volume
2,6,4,4,4,2,2,1,1
1,2,4,4,4,1,6,2,6
1,5,4,4,4,1,2,1,6
2,4,4,4,4,2,6,1,4
1,4,4,4,4,1,2,2,2
2,4,3,3,3,2,1,1,1
1,5,2,1,4,1,6,2,6
1,2,3,3,3,1,2,1,6
2,6,4,4,4,2,3,1,1
1,4,4,4,4,1,2,1,6
1,5,4,4,4,1,2,1,4
1,4,5,5,5,1,6,2,4
2,5,4,4,4,2,3,1,1
Код для этого написан так:
from numpy.core.defchararray import count, index
import pandas as pd
import numpy as np
import math
from sklearn.decomposition import PCA
from numpy import linalg as LA
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
test_set_Bayes = pd.read_csv("Assignment 2--Training set for Bayes.csv")
training_set_Bayes = pd.read_csv("Assignment 2--Test set for Bayes.csv")
def calculate_metrics(tp, tn, fn, fp, p, n):
# вычислить точность, уровень ошибок, чувствительность, специфичность и точность для выбранного классификатора в отношении соответствующего тестового набора.
accuracy = tp + tn /(p+n)
error_rate = fp + fn /(p + n)
sensitivity = tp/ p
precision = tp/ (tp+fp)
specificity = tn/n
display_metrics(accuracy, error_rate, sensitivity, precision, specificity)
def display_metrics(accuracy, error_rate, sensitivity, precision, specificity):
print(f'Точность: {accuracy}, Уровень ошибок:{error_rate}, Чувствительность:{sensitivity}, Точность:{precision}, специфичность:{specificity}')
def prob_continous_value(A, v, classAttribute, dataset, x):
# вычислить среднее для всех значений A в наборе данных с классом = x
a = dataset[dataset[classAttribute] == x][A].mean()
# вычислить стандартное отклонение для всех значений A в наборе данных с классом = x
stdev = 1
stdev = dataset[dataset[classAttribute] == x][A].std()
v = dataset[A].iloc[0]
if stdev == 0.0:
stdev = 0.00000000000001
return (1/(math.sqrt(2*math.pi)*stdev))*math.exp(-((v-a)*(v-a))/(2*stdev*stdev))
def BayesClassifier(training_set,test_set):
classAttribute="Volume"
products = []
max = -math.inf
classWithMaxValue = ""
for x in training_set[classAttribute].unique():
D = len(training_set[classAttribute].index)
d = len(training_set[training_set[classAttribute] == x].index)
pClassAttribute = d/D
print("********")
print(f'Шаг 1 вычислить p({classAttribute}={x})={pClassAttribute}')
p = 0
probabilitiesProduct = 1
print("********")
print("Шаг 2 вычислить произведение вероятностей")
for A, values in training_set.iteritems():
if not A == classAttribute:
v = training_set[A].iloc[0]
p = prob_continous_value(A, v, classAttribute, training_set, x)
print(f'p({A}={v}|{classAttribute}={x})={p}')
probabilitiesProduct *= p
print(f"probabilitiesProduct={probabilitiesProduct}")
print("********")
# products.append(probabilitiesProduct)
ptotal = pClassAttribute*probabilitiesProduct
print(f'p({classAttribute}={x}|x)={ptotal}')
if ptotal > max:
max = ptotal
classWithMaxValue = x
print(f"победитель это {classAttribute}={classWithMaxValue}")
tp = len(test_set[test_set[classAttribute] == classWithMaxValue].index)
tn = len(test_set[test_set[classAttribute] != classWithMaxValue].index)
p = len(test_set[classAttribute].index)
n = len(test_set[classAttribute].index)
fp = len(test_set[classAttribute].index)
fn = len(test_set[classAttribute].index)
calculate_metrics(tp, tn, fn, fp, p, n)
# запросите пользователя выбрать классификатор ID3 или Байеса.
selection = "Bayes" #= input("Пожалуйста, введите ваш выбор для классификации ID3 или Bayes: ")
if(selection == "Bayes"):
BayesClassifier(training_set_Bayes,test_set_Bayes)
Ожидается:
Общие показатели, отображающие следующие метрики: точность, уровень ошибок, чувствительность, специфичность и точность для выбранного классификатора в отношении соответствующего тестового набора.
Фактически:
Точность: 56.42328767123288, Уровень ошибок:365.5, Чувствительность:0.15342465753424658, Точность:0.1330166270783848, специфичность:0.8465753424657534
Последняя итерация выводит:
Шаг 1 вычислить p(Volume=5)=0.06818181818181818
********
Шаг 2 вычислить произведение вероятностей
p(Venue=1|Volume=5)=0.5849089671682236
p(color=6|Volume=5)=0.00019621509920999636
p(Model=4|Volume=5)=0.04484934763369217
p(Category=4|Volume=5)=0.0
p(Location=4|Volume=5)=0.0
p(Weight=1.5|Volume=5)=0.46792717373457876
p(Variety=1|Volume=5)=0.0003021925272993778
p(Material=1.1|Volume=5)=0.31395152365343143
probabilitiesProduct=0.0
********
p(Volume=5|x)=0.0
победитель это Volume=2
Этот блок кода – это то, в чем мне нужна помощь
tp = len(test_set[test_set[classAttribute] == classWithMaxValue].index)
tn = len(test_set[test_set[classAttribute] != classWithMaxValue].index)
p = len(test_set[classAttribute].index)
n = len(test_set[classAttribute].index)
fp = len(test_set[classAttribute].index)
fn = len(test_set[classAttribute].index)
calculate_metrics(tp, tn, fn, fp, p, n)
Если кто-то мог бы объяснить, как определить эти параметры
p = len(test_set[classAttribute].index)
n = len(test_set[classAttribute].index)
fp = len(test_set[classAttribute].index)
fn = len(test_set[classAttribute].index)
Я был бы очень признателен. Спасибо.
В вашем решении есть серьезные ошибки:
- В настоящее время часть вашей оценки (tp и tn) использует обучающи набор. Крайне важно использовать только тестовый набор для оценки.
- Статус классификации не работает так, как вы это делаете, см. ниже.
Я думаю, что основная неясность заключается в том, что вы не знаете/не определяете, какой из классов является положительным. Я не знаю ваши данные, и вы не показываете класс, но давайте предположим, что метки 0 и 1, и что 0 – это отрицательный класс, а 1 – положительный:
- Истинно Положительный (TP) – это экземпляр, для которого истинная метка равна 1, и предсказанная метка равна 1.
- Ложно Положительный (FP) – это экземпляр, для которого истинная метка равна 0, но предсказанная метка равна 1.
- Ложно Отрицательный (FN) – это экземпляр, для которого истинная метка равна 1, но предсказанная метка равна 0.
- Истинно Отрицательный (TN) – это экземпляр, для которого истинная метка равна 0, и предсказанная метка равна 0.
Таким образом, строка для TP должна быть следующей:
tp = len(test_set[test_set[classAttribute] == 1 and classWithMaxValue == 1].index)
То же самое для других случаев.
Могут быть и другие проблемы, но я не понимаю всего в коде (и не имею столько времени, чтобы тратить его на это). В частности, у меня есть большие сомнения по поводу classWithMaxValue
, является ли это вектором с значением для каждого экземпляра? Если нет, то у вас есть еще одна серьезная проблема.
Я думаю, что это сработает.
from numpy.core.defchararray import count, index
import pandas as pd
import numpy as np
import math
from sklearn.decomposition import PCA
from numpy import linalg as LA
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
test_set_Bayes = pd.read_csv("Assignment 2--Training set for Bayes.csv")
training_set_Bayes = pd.read_csv("Assignment 2--Test set for Bayes.csv")
def calculate_metrics(training_set,test_set,classAttribute,classValue):
# вычислить точность, уровень ошибок, чувствительность, специфичность и точность для выбранного классификатора в отношении соответствующего тестового набора.
tp = len(training_set[training_set[classAttribute] == classValue].index)
fp = len(test_set[test_set[classAttribute] == classValue].index)
tn = len(training_set[training_set[classAttribute] == classValue].index)
fn = len(test_set[test_set[classAttribute] != classValue].index)
p = tp + fp
n = tn + fn
print(f" \t \t\t {classValue} \t not {classValue} \t \t TOTAL")
print(f" \t \t\t \t \t \t ")
print(f" \t \t {classValue} \t {tp} \t {fp} \t {p}")
print(f" \t not \t {classValue} \t {fn} \t {tn} \t {n}")
print(f" \t total\t\t {tp+fn} \t {fn+tn} \t {p+n} \t")
accuracy = tp + tn /(p+n)
error_rate = fp + fn /(p + n)
sensitivity = tp/ p
precision = tp/ (tp+fp)
specificity = tn/n
display_metrics(accuracy, error_rate, sensitivity, precision, specificity)
def display_metrics(accuracy, error_rate, sensitivity, precision, specificity):
print(f'Точность: {accuracy}, Уровень ошибок:{error_rate}, Чувствительность:{sensitivity}, Точность:{precision}, специфичность:{specificity}')
def prob_continous_value(A, v, classAttribute, dataset, x):
# вычислить среднее для всех значений A в наборе данных с классом = x
a = dataset[dataset[classAttribute] == x][A].mean()
# вычислить стандартное отклонение для всех значений A в наборе данных с классом = x
stdev = 1
stdev = dataset[dataset[classAttribute] == x][A].std()
v = dataset[A].iloc[0]
if stdev == 0.0:
stdev = 0.00000000000001
return (1/(math.sqrt(2*math.pi)*stdev))*math.exp(-((v-a)*(v-a))/(2*stdev*stdev))
def BayesClassifier(training_set,test_set):
classAttribute="Volume"
products = []
max = -math.inf
classWithMaxValue = ""
for x in training_set[classAttribute].unique():
D = len(training_set[classAttribute].index)
d = len(training_set[training_set[classAttribute] == x].index)
pClassAttribute = d/D
print("********")
print(f'Шаг 1 вычислить p({classAttribute}={x})={pClassAttribute}')
p = 0
probabilitiesProduct = 1
print("********")
print("Шаг 2 вычислить произведение вероятностей")
for A, values in training_set.iteritems():
if not A == classAttribute:
v = training_set[A].iloc[0]
p = prob_continous_value(A, v, classAttribute, training_set, x)
print(f'p({A}={v}|{classAttribute}={x})={p}')
probabilitiesProduct *= p
print(f"probabilitiesProduct={probabilitiesProduct}")
print("********")
# products.append(probabilitiesProduct)
ptotal = pClassAttribute*probabilitiesProduct
print(f'p({classAttribute}={x}|x)={ptotal}')
if ptotal > max:
max = ptotal
classWithMaxValue = x
print(f"победитель это {classAttribute}={classWithMaxValue}")
calculate_metrics(tp, tn, fn, fp, p, n)
# запросите пользователя выбрать классификатор ID3 или Байеса.
selection = "Bayes" #= input("Пожалуйста, введите ваш выбор для классификации ID3 или Bayes: ")
if(selection == "Bayes"):
BayesClassifier(training_set_Bayes,test_set_Bayes)
```
Ответ или решение
Для реализации алгоритма классификации наивного Байеса и корректного расчета показателей True Positive (TP), True Negative (TN), False Positive (FP), False Negative (FN), давайте подробно рассмотрим, какие метрики необходимы, как вычислить их значения и почему это важно для оценки производительности модели.
Понимание основ
Алгоритм наивного Байеса служит для классификации объектов на основе их признаков. Основная цель — предсказать вероятность принадлежности экземпляра к определенному классу. Чтобы оценить качество такого классификатора, важно правильно вычислить TP, TN, FP и FN на тестовой выборке. Давайте разберемся, как это делается.
Определения метрик
- True Positive (TP): количество единиц (положительных примеров), которые были правильно классифицированы как положительные.
- False Positive (FP): количество единиц (отрицательных примеров), которые были ошибочно классифицированы как положительные.
- True Negative (TN): количество нулей (отрицательных примеров), которые были правильно классифицированы как отрицательные.
- False Negative (FN): количество единиц (положительных примеров), которые были ошибочно классифицированы как отрицательные.
Для корректного расчета этих значений необходимо знать, какое значение мы считаем положительным (например, 1) и отрицательным (например, 0).
Корректная реализация
Теперь давайте подправим вашу реализацию, чтобы все вычисления выполнялись правильно. Ниже представлен откорректированный блок кода, который осуществляет расчет TP, TN, FP и FN, а также вычисляет остальные метрики:
def calculate_metrics(test_set, classAttribute, classWithMaxValue):
tp = len(test_set[(test_set[classAttribute] == classWithMaxValue) & (test_set['predicted'] == classWithMaxValue)])
tn = len(test_set[(test_set[classAttribute] != classWithMaxValue) & (test_set['predicted'] != classWithMaxValue)])
fp = len(test_set[(test_set[classAttribute] != classWithMaxValue) & (test_set['predicted'] == classWithMaxValue)])
fn = len(test_set[(test_set[classAttribute] == classWithMaxValue) & (test_set['predicted'] != classWithMaxValue)])
p = tp + fn # Все положительные примеры
n = tn + fp # Все отрицательные примеры
accuracy = (tp + tn) / (p + n)
error_rate = (fp + fn) / (p + n)
sensitivity = tp / p if p > 0 else 0
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
specificity = tn / n if n > 0 else 0
display_metrics(accuracy, error_rate, sensitivity, precision, specificity)
def BayesClassifier(training_set,test_set):
# Логика вашей классификации...
# После предсказания добавим 'predicted' колонку в тестовый набор данных
test_set['predicted'] = classWithMaxValue
calculate_metrics(test_set, classAttribute, classWithMaxValue)
Объяснение процесса
- Подсчет TP, TN, FP и FN: Мы используем логические условия для определения, соответствует ли предсказанный класс истине. Например,
test_set[classAttribute] == classWithMaxValue
находит все реальные положительные примеры. - Расчет метрик: Важно тщательно проверять на деление на ноль, чтобы избежать исключений.
- Добавление колонки ‘predicted’: Это позволит нам анализировать результаты классификации без необходимости повторного обращения к всему набору данных.
Заключение
Правильное вычисление TP, TN, FP и FN является критически важным для оценки точности модели наивного Байеса. Каждая ошибка в этих расчетах может приводить к недостоверным показателям и, следовательно, к неверным выводам. Убедитесь, что все шаги выполняются корректно и данные разделяются на тренировочные и тестовые выборки, чтобы достичь наилучшей оценки производительности модели.