Language R
Метод | Параметры | Loo |
---|---|---|
KWNN | k=9 | 0.0333 |
KNN | k=6 | 0.0333 |
Парзеновские окна | h=0.4 ( Прямоугольное ядро ) | 0.04 |
Парзеновские окна | h=0.4 ( Треугольное ядро ) | 0.04 |
Парзеновские окна | h=0.4 ( ядро Епанечникова ) | 0.04 |
Парзеновские окна | h=0.4 ( Квартическое ядро ) | 0.04 |
Парзеновские окна | h=0.1 ( Гауссовское ядро ) | 0.04 |
Потенциальные функции | h=0.4 ( Прямоугольное ядро ) | Подбор гамма |
Метрические методы обучения -- методы, основанные на анализе сходства объектов.
Метрические алгоритмы классификации опираются на гипотезу компактности: схожим объектам соответствуют схожие ответы.
Метрические алгоритмы классификации с обучающей выборкой Xl относят объект u к тому классу y, для которого суммарный вес ближайших обучающих объектов максимален:
где весовая функция w(i, u) оценивает степень важности i-го соседа для классификации объекта u.
Функция называется оценкой близости объекта u к классу y. Выбирая различную весовую функцию w(i, u) можно получать различные метрические классификаторы.
Классификация ирисов Фишера методом 1NN (ближайшего соседа)
Решалась задача классификации. В качестве обучающей выборки была взята матрица ирисов фишера по длине и ширине лепестка. Требовалось построить карту классификации на основе данных обучающей выборки. В качестве метода классификации использовался метод 1NN.
1.Для классифицируемого объекта вычисляются расстояния от него до каждого объекта обучающей выборки.
2.Обучающая выборка сортируется по возрастанию расстояния от каждого объекта выборки до классифицируемого
3.Классифицируемому объекту присваивается тот же класс, что и ближайшего к нему объекта выборки.
Классификация ирисов Фишера методом kNN (k ближайших соседей)
Решалась задача классификации. В качестве обучающей выборки была взята матрица ирисов фишера по длине и ширине лепестка. Требовалось построить карту классификации на основе данных обучающей выборки. В качестве метода классификации использовался метод kNN.
Метод kNN состоит в следующем: 1.Для классифицируемого объекта вычисляются расстояния от него до каждого объекта обучающей выборки 2.Обучающая выборка сортируется по возрастанию расстояния от каждого объекта выборки до классифицируемого 3.Подсчитывается, какой класс доминирует среди k ближайших соседей, и этот класс присваивается классифицируемому объекту ## Алгоритм k ближайших соседей (kNN) Алгоритм 1NN относит классифицируемый объект U к тому классу, которому принадлежит его ближайший сосед. ὠ(i,u)=[i=1];
Алгоритм kNN относит объект к тому классу, элементов которого больше среди k ближайших соседей x(i), i=1,..,k.
Для оценки близости классифицируемого объекта u к классу y алгоритм kNN использует следующую функцию:
ὠ(i,u)=[i<=k], где i -- порядок соседа по расстоянию к классифицируемому объекту u, k-количество параметровю=. Реализация весовой функции производится следующим образом:
distances <- matrix(NA, l, 2) # расстояния от классифицируемого объекта u до каждого i-го соседа
for(i in 1:l) {
distances[i, ] <- c(i, eDist(xl[i, 1:n], u))
}
orderedxl <- xl[order(distances[ , 2]), ] # сортировка расстояний
classes <- orderedxl[1:k, n + 1] # названия первых k классов (k ближайших соседей) в classes
- Простота реализации.
- При k, подобранном около оптимального, алгоритм "неплохо" классифицирует.
- Нужно хранить всю выборку.
- При k = 1 неустойчивость к погрешностям (выбросам -- объектам, которые окружены объектами чужого класса), вследствие чего этот выброс классифицировался неверно и окружающие его объекты, для которого он окажется ближайшим, тоже.
- При k = l алгоритм наоборот чрезмерно устойчив и вырождается в константу.
- Крайне бедный набор параметров.
- Точки, расстояние между которыми одинаково, не все будут учитываться.
Реализаця метода kwNN
В каждом классе выбирается
k ближайших к U объектов, и объект u относится к тому классу, для
которого среднее расстояние до k ближайших соседей минимально.
где,
— строго убывающая последовательность вещественных весов, задающая
вклад i-го соседа при классификации объекта u.
weightsKWNN = function(i, k)
{
(k + 1 - i) / k
}
Метод | Параметры | Точность |
---|---|---|
KWNN | k=9 | 0.0333 |
KNN | k=6 | 0.0333 |
kNN — один из простейших алгоритмов классификации, поэтому на реальных задачах он зачастую оказывается неэффективным. Помимо точности классификации, проблемой этого классификатора является скорость классификации: если в обучающей выборке N объектов, в тестовой выборе M объектов, и размерность пространства K, то количество операций для классификации тестовой выборки может быть оценено как O(KMN).
kwNN отличается от kNN, тем что учитывает порядок соседей классифицируемого объекта, улчшая качество классификации.
Пример, показывающий преимущество метода kwNN над kNN:
В примере передаем параметр k=5. Kwnn в отличии от Knn оценивает не только индекс соседа, но и расстояние до него, из-за этого результат получается более точный, что и продемонстрировано в данном примере.
Число k выбирается методом LOO (скользящего контроля)
- Элемент удаляется из выборки
- Запускается алгоритм классификации (в данном случае kNN) для полученной выборки и удалённого объекта
- Полученный класс объекта сравнивается с реальным. В случае несовпадения классов, величина ошибки увеличивается на 1
- Процесс повторяется для каждого объекта выборки
- Полученная ошибка усредняется
- Процесс повторяется для других значений k. В итоге выбирается число k с наименьшей ошибкой LOO
##Составляем таблицу встречаемости каждого класса
counts <- table(classes)
class <- names(which.max(counts))
return (class)
}
## Метод скользящего контроля
Loo <- function(k,xl)
{
sum =0
for(i in 1:dim(xl)[1]
{
tmpXL <- rbind(xl[1:i-1, ],
xl[i+1:dim(xl)[1],])
xi <- c(xl[i,1], xl[i,2])
class <-kNN(tmpXL,xi,k)
if(class != xl[i,3])
sum=sum+1
}
sum=sum/dim(xl)[1]
return(sum)
}
Преимущество LOO состоит в том, что каждый объект ровно один раз участвует в контроле, а длина обучающих подвыборок лишь на единицу меньше длины полной выборки.
Недостатком LOO является большая ресурсоёмкость, так как обучаться приходится L раз. Некоторые методы обучения позволяют достаточно быстро перенастраивать внутренние параметры алгоритма при замене одного обучающего объекта другим. В этих случаях вычисление LOO удаётся заметно ускорить.
Для оценки близости объекта u к классу y алгоритм использует следующую функцию:
Наиболее часто используются следующие типы ядер
Код для реализации данных типов ядер:
kernelE = function(r){ return ((3/4*(1-r^2)*(abs(r)<=1)))} #епанечникова
kernelQ = function(r){ return ((15 / 16) * (1 - r ^ 2) ^ 2 * (abs(r) <= 1))} #квартическое
kernelT = function(r){ return ((1 - abs(r)) * (abs(r) <= 1)) } #треугольное
kernelG = function(r){ return (((2*pi)^(-1/2)) * exp(-1/2*r^2))} #гауссовское
kernelR = function(r){ return ((0.5 * (abs(r) <= 1) ))} #прямоугольное
Алгоритм вокруг нашей классифицируемой точки u строит окружность с радиусом h. Далее убираем точки, которые не вошли в окружность. Затем для оставшихся, считаем weights, суммируем по class, и с помощью names(which.max(weights)) возвращаем название класса "победителя".
Код алгоритма:
PW = function(XL,y,h,metricFunction = euclideanDistance){
l <- dim(xl)[1]
weights = rep(0,3)
names(weights) = unique(xl[,3])
for(i in 1:l)
{
x=XL[i,1:2]
class=XL[i,3]
r = metricFunction(x,y)/h
weights[class]=kernelR(r)+weights[class];
}
#no p in w
if(max(weights)==0){ return ("0") }
else{ return (names(which.max(weights))) }
}
В отличии от предыдущих ядер, Гауссовское ядро устраняет проблему с классификацией точек, не попавших ни в одно окно.
Наблюдения при реализации: Если h сделать слишком маленьким, классифицуруется заметно меньшее количество точек. Если же h сделать слишком большим, то учитываются точки, находящиеся на очень большом расстоянии.
Плюсы:
- прост в реализации
- хорошее качество классификации при правильно подобраном h
- все точки с одинаковым расстоянием будут учитаны
Минусы:
- необходимо хранить всю выборку целиком
- небольшой набор параметров
- диапазон параметра h необходимо подбирать самостоятельно(в зависимости от плотности расположения т.)
- если ни одна точка не попала в радиус h, алгоритм не способен ее классифицировать (кроме гауссовского ядра)
Метод потенциальных функций - относится к метрическим классификаторам. В отличии от метода парзеновсуих окон, окно строится вокруг обучающих точек. При классификации объект проверяется на близость к объектам из обучающей выборки. Простыми словами, объекты из обучающей выборки «заряжены» своим классом, а вес каждого из них при классификации зависит от «заряда» и расстояния до классифицируемого объекта.
Алгоритм метода PF
- Изначально для каждого объекта выборки задаём ширину окна
эмпирически (выбирается из собственных соображений).
- Затем для обучающих объектов вычисляем силу потенциала
.
- После чего каждому объекту выборки присваивается вес по формуле
,
- функция ядра.
- Суммируем веса объектов одинаковых классов. Класс "победитель" присваивается точке.
Код метода потенциальных функций:
PF = function(potentials,XL,y,h,metricFunction = euclideanDistance)
{
l <- nrow(XL)
n <- ncol(XL)
weights = rep(0,3)
names(weights) = unique(XL[,3])
for(i in 1:l)
{
x=XL[i,1:2]
class=XL[i,3]
r = metricFunction(x,y)/h
weights[class] = weights[class] + potentials[i]*kernelR(r);
}
class = names(which.max(weights))
#no p in w
if (max(weights) == 0) return("0")
return(class)
}
- Множество потенциалов
зануляется. Задается максимально допустимое число ошибок(eps).
- Из обучающей выборки выбирается очередной объект
.
- Затем Для
запускаю алгоритм классификации.
- Если полученный класс не совпал с реальным, то сила потенциала для выбранного объекта увеличивается на 1. Иначе снова выбирается объект и классифицируется.
- Алгоритм классификации с полученными значениями потенциалов запускается для каждого объекта выборки. Подсчитывается число ошибок.
- Если число ошибок меньше заданного, то алгоритм завершает работу. Иначе снова выбирается объект из выборки.
getPotentials <- function(XL,eps,h,class)
{
# get pots all elements
l <- nrow(XL)
n <- ncol(XL)
potentials <- rep(0,l)
err <- eps + 1
while (err > eps)
{
while (TRUE)
{
# Пока не получим несоответствие классов, чтобы обновить потенциалы
rand <- sample(1:l, 1)
x=XL[rand,1:2]
u <- PF(potentials,XL,x,h)
if(colors[u] != colors[class[rand]]) {
potentials[rand] = potentials[rand] + 1
break
}
}
# Подсчет числа ошибок
err <- 0
for (i in 1:l)
{
x = XL[i,1:2]
points=XL[-i,1:3]
if(colors[PF(potentials,points,x,h)]!= colors[class[i]])
{
err = err + 1
}
}
}
return (potentials)
}
В данной программе использовал прямоугольное ядро. Алгоритм подбирает только силу потенциала , радиус потенциалов h задаются эмпирически(по собственным соображениям).
Список ненулевых потенциалов(15 номеров)
[1] 3
[1] 66
[1] 71
[1] 78
[1] 84
[1] 87
[1] 94
[1] 102
[1] 105
[1] 107
[1] 119
[1] 120
[1] 122
[1] 134
[1] 139
Задать значение ширины окна для каждого класса
SvoiH <- function(xl)
{
l <- nrow(xl)
h <- rep(0, l)
for(i in 1:l) {
if (xl[i, ncol(xl)] == "setosa") h[i] <- 1
else h[i] <- 0.4
}
return (h)
}
h <- SvoiH(xl)
Подбор потенциалов происходит до тех пор, пока точность алгоритма, не будет меньше заданной ошибки eps. Иллюстрация результата работы алгоритма:
Преимущества метода потенциальных функций:
- Большое количество параметров для подбора.
- Возможность использования не всей выборки
Недостатки метода:
- Метод непрост для понимания и алгоритмической реализации;
- Неопределённое время работы алгоритма подбора(если взять маленькое eps)
;
- Параметры
. и h настраиваются слишком грубо;
Алгоритм СТОЛП (STOLP) — алгоритм отбора эталонных объектов для метрического классификатора.
Отступ - величина, показывающая, насколько объект является типичным представителем своего класса. Отступ равен разности между степенью близости объекта к своему классу и суммой близостей объекта ко всем остальным классам.
Все объекты обучающей выборки можно разделить на несколько типов:
- Эталонные объекты - наиболее типичные представители своего класса
- Неинформативные - объекты, не влияющие значительным образом на качество классификации
- Пограничные - объекты, имеющие отступ, близкий к нулю. Незначительное изменение в выборке, алгоритме, метрике и т.п. может повлиять на их классификацию.
- Ошибочные - объекты с отрицательными отступами, классифицируемые неверно.
- Шумовые объекты (выбросы) - малая группа объектов с большими отрицательными отступами. Их удаление улучшает качество классификации.
Идея алгоритма STOLP состоит в том, чтобы уменьшить исходную выборку, выбрав из неё эталонные объекты. Такой подход уменьшит размер выборки, и может улучшить качество классификации. На вход подаётся выборка, допустимый порог ошибок и порог фильтрации выбросов.
Алгоритм:
- Удалить из выборки все выбросы (объекты, отступ которых меньше порога фильтрации выбросов).
- Пересчитать все отступы заново, взять по одному эталону из каждого класса (объекты с наибольшим положительным отступом), и добавить их в множество эталонов.
- Проклассифицировать объекты обучающей выборки, взяв в качестве обучающей выборки для этого множество эталонов. Посчитать число ошибок.
- Если число ошибок меньше заданного порога, то алгоритм завершается.
- Иначе присоединить ко множеству эталонов объекты с наименьшим отступом из каждого класса из числа классифицированных неправильно.
- Повторять шаги 3-5 до тех пор, пока множество эталонов и обучающая выборка не совпадут, или не сработает проверка в пункте 4.
Реализация функции для нахождения отступа наших объектов
margin = function(points,classes,point,class){
Myclass = points[which(classes==class), ]
OtherClass = points[which(classes!=class), ]
MyMargin = Parzen(Myclass,point[1:2],1,FALSE)
OtherMargin = Parzen(OtherClass,point[1:2],1,FALSE)
return(MyMargin-OtherMargin)
}
В итоге осталось 5 эталонных объектов, скорость работы метода после алгоритма заметно улучшилась,а именно с 1.7 mins секунд до 3.5sec.
start <- Sys.time()
for(i in 1:150){
parsen(learn_data[, 1:3], my_iris[i,1:2])
}
print(Sys.time() - start)
}
Точность ухудшилась незначительно. Точность алгоритма До отбора эталонных составляла: 0.96 (6 ошибок), а после: 0.94 (8 ошибок)
Отступы для парзвеновского окна:
С разделением ошибочных объектов от выбросов.
Код:
badpoints = which(margins < 0)
badmargins = rep(0,length(badpoints))
for (i in 1:length(badpoints)){
badmargins[i]=margins[badpoints[i]]
}
badmargins = rev(sort(badmargins))
print(badmargins)
for (i in 2:length(badpoints)){
vubros<-0
if(abs(badmargins[i]-badmargins[i-1])>1)
{
vubros=i
print(badmargins[vubros])
}
}
Задание | Shiny |
---|---|
Изолинии(Линии уровня) | + |
Байесовский подход опирается на теорему о том, что если плотности распределения классов известны, то алгоритм классификации, можно выписать в явном виде(если алгоритм имеет минимальную вероятность ошибок). Для оценивания плотностей классов по выборке применяются различные подходы. В этом курсе лекций рассматриваем три: непараметрический, параметрический и оценивание смесей распределений.
При решении задачи классификации, необходимо по известному вектору признаков x, определить класс y к которому принадлежит объект a(x) по формуле : a(x) = argmax P(y|x), для которого при условии x, вероятность класса y - наиболее высока.
В случае когда P(y) одинаковы для всех классов, то следует выбрать класс у, у которого в точке x, плотность больше.
- Апостериорная вероятности, т.е. вероятность того, что объект x принадлежит классу y.
- функция правдободобия.
- Априорная вероятность, т.е. вероятность появления класса.
Наивный байесовский классификатор – это семейство алгоритмов классификации, которые принимают одно допущение: Каждый параметр классифицируемых данных рассматривается независимо от других параметров класса.
Метод называется наивным т.к. предполагается, что все параметры набора данных независимы, что встречается крайне редко.
Обычно он используется, как эталон при сравнении различных алгоритмов классификации.
Решающее правило принимает вид:
Визуализация работы алгоритма:
В приведённых примерах все признаки действительно взяты независимо, поэтому алгоритм показывает хорошее качество классификации. В практических задачах результат был бы намного хуже.
Достоинства алгоритма:
- Простота реализации.
- Низкие вычислительные затраты при обучении и классификации.
- Если признаки (почти) независимы, то алгоритм (почти) оптимален.
Недостатки алгоритма:
- В общем случае - низкое качество классификации.
Непосредственно реализация задания.
Случайная величина x ∈ R имеет нормальное (гауссовское) распределение с параметрами µ и σ^2, если ее плотность задается выражением:
Параметры µ и σ^2 определяют, соответственно, мат.ожидание и дисперсию нормальной случайной величины. По центральной предельной теореме среднее арифметическое независимых случайных величин с ограниченными мат.ожиданием и дисперсией стремится к нормальному распределению. Поэтому это распределение часто используется в качестве модели шума, который определяется суммой большого количества независимых друг от друга случайных факторов.
Собственно, реализация задания.
Визуализация:
Нормальный дискриминантный анализ - это специальный случай байесовской классификации, предполагающий, что плотности всех классов являются многомерными нормальными.
Случайная величина x имеет многомерное нормальное распределение, если ее плотность задается выражением:
где 𝜇 ∈ ℝ - математическое ожидание (центр), а 𝛴 ∈ ℝ - ковариационная матрица (симметричная, невырожденная, положительно определённая).
Алгоритм заключается в том, чтобы найти неизвестные параметры 𝜇 и 𝛴 для каждого класса y и подставить их в формулу оптимального байесовского классификатора. В отличие от линейного дискриминанта Фишера(ЛДФ), в данном алгоритме мы предполагаем, что ковариационные матрицы не равны.
Оценка параметров нормального распределения производится на основе параметров функций правдоподобия:
Программная реализация восстановления данных параметров:
Для математического ожидания 𝜇, то есть находим центр нормального распределения элементов класса:
for (col in 1:cols){
mu[1, col] = mean(objects[,col])
}
Для восстановления ковариационной матрицы 𝛴:
for (i in 1:rows){
sigma <- sigma + (t(objects[i,] - mu) %*% (objects[i,] - mu)) / (rows - 1)
}
Результаты работы подстановочного алгоритма:
- Здесь по 250 элементов в каждом классе и ковариационные матрицы равны, поэтому разделяющая линия, как видим, вырождается в прямую:
Sigma1 <- matrix(c(10, 0, 0, 1), 2, 2)
Sigma2 <- matrix(c(3, 0, 0, 3), 2, 2)
- Здесь по 70 эелементов каждом классе. Ковариационные матрицы не равны, разделяющая плотность является квадратичной и прогибается таким образом, что менее плотный класс охватывает более плотный.
Ковариационные матрицы:
Sigma1 <- matrix(c(3, 0, 0, 1), 2, 2)
Sigma2 <- matrix(c(10, 0, 0, 15), 2, 2)
Дискриминатная функция: гипербола:
Алгоритм ЛДФ отличается от подстановочного алгоритма тем, что ковариационые матрицы классов равны, поэтому для их восстановления необходимо использовать все объекты выборки. В этом случае разделяющая кривая вырождается в прямую.
Если оценить неизвестную 𝛴(ковариационная матрица, то есть их равенство), с учетом смещенности, то получим следующую формулу:
Восстановление ковариационных матриц в коде алгоритма:
for (i in 1:rows1){
sigma = sigma + (t(points1[i,] - mu1) %*% (points1[i,] - mu1))
}
for (i in 1:rows2){
sigma = sigma + (t(points2[i,] - mu2) %*% (points2[i,] - mu2))
}
Разделяющая плоскость здается формулой:
,
коэффициенты которой находятся следующим образом:
Программная реализация данной функции нахождения коэффициентов ЛДФ выглядит следующим образом:
inverseSigma <- solve(Sigma)
alpha <- inverseSigma %*% t(mu1 - mu2)
beta <- (mu1 %*% inverseSigma %*% t(mu1) - mu2 %*% inverseSigma %*% t(mu2)) / 2
Результат работы алгоритма выглядит следующим образом:
Можно сравнить результаты работы алгоритмов с одинаковыми параметрами:
Здесь параметры следующие:
Sigma1 <- matrix(c(2, 0, 0, 2), 2, 2)
Sigma2 <- matrix(c(2, 0, 0, 2), 2, 2)
Количество элементов в каждом классе: 50.
ЛДФ алгоритм.
При чем, при малом количестве элементов в каждом классе ЛДФ превосходит подстановочный алгоритм. Чем меньше элементов, тем хуже работает подстановочный алгоритм.
Пусть , тогда алгоритм
называется линейным алгоритмом.
В данном пространстве классы разделяет гиперплоскость, которая задается уравнением:.
Если x находится по одну сторону гиперплоскости с её направляющим вектором w, то объект x относится к классу +1, в противном случае - к классу -1.
Эмпирический риск представлен следующей формулой: .
Для того, чтобы минимизировать его и подобрать оптимальный вектор весов w, рекомендуется пользоваться методом стохастического градиента.
Метод стохастического градиента - это итерационный процесс, на каждом шаге которого сдвигаемся в сторону, противоположную вектору градиента 𝑄′(𝑤, 𝑋ℓ)) до тех пор, пока вектор весов 𝑤 не перестанет изменяться, причем вычисления градиента производится не на всех объектах обучения, а выбирается случайный объект (отсюда и название метода «стохастический»), на основе которого и происходят вычисления. В зависимости от функции потерь, которая используется в функционале эмпирического риска, будем получать различные линейные алгоритмы классификации.
Существует величина , которая называется отступом объекта относительно алгоритма клссификации. Если данный отступ отрицательный, тогда алгоритм совершает ошибку.
L(M) - функция потерь.
- данную функцию потерь называют кусочно-линейной.
- правило обновления весов, которое называют правилом Хебба.
Программная реализация функции потерь:
lossPerceptron <- function(x)
{
return (max(-x, 0))
}
- логистическая функция потерь.
- правило обновления весов, которое называют логистическим, где сигмоидная функция:
.
Программная реализация функции потерь и сигмоидной функции:
##Функция потерь
lossLog <- function(x)
{
return (log2(1 + exp(-x)))
}
## Сигмоидная функция
sigmoidFunction <- function(z)
{
return (1 / (1 + exp(-z)))
}
- это квадратичная функция потерь.
- правило обновления весов на каждом шаге итерации метода стохастического градиента. Данное правило получено путем дифференцирования квадратичной функции.
Пусть дана обучающая выборка: множество входных значений X и множество выходящих значений Y, такие что каждому входу xj соответствует yj - выход, j = 1..m. Необходимо по этим данным построить ADALINE, которая допускает наименьшее количество ошибок на этой обучающей выборке. Обучение ADALINE заключается в подборе "наилучших" значений вектора весов w. Какие значение весов лучше определяет функционал потерь.
В ADALINE применяется квадратичная функция потерь, которая представлена выше.
Обучения ADALINE происходит следующим образом:
Для начала нужно инициализировть веса * w_j; j = 0,..., n* и начальную оценку функционала Q.
w <- c(1/2, 1/2, 1/2)
iterCount <- 0
## initialize Q
Q <- 0
for (i in 1:l)
{
## calculate the scalar product <w,x>
wx <- sum(w * xl[i, 1:n])
## calculate a margin
margin <- wx * xl[i, n + 1]
Q <- Q + lossQuad(margin)
}
Выбрать объект x_i из Xl, затем посчитать ошибку и сделать шаг градиентного спуска:
ex <- lossQuad(margin)
eta <- 1 / sqrt(sum(xi * xi))
w <- w - eta * (wx - yi) * xi ##шаг градиентного спуска
Затем нужно оценить значение функционала Q:
Qprev <- Q
Q <- (1 - lambda) * Q + lambda * ex
}
Повторять все, что вычисляется после инициализации веса и начального значения Q пока значение Q не стабилизируется и/или веса w не перестанут изменяться.
Визуализация:
Реализация в shiny: ссылка.После сравнения понял, что ADALINE и Логистическая регрессия выигрывают в точности у правила Хебба, когда выборка линейно разделима. Но когда выборка плохо разделима, или не разделима, ADALINE проигрывает Логистической регрессии и правилу Хебба. Следовательно, алгоритм классификации для конкретной задачи в зависимости от исходных данных.