рекомендации

воскресенье, 20 мая 2018 г.

Лучший способ изучения алгоритма kNN с программированием на R


Перевод. Оригинал здесь.

В этой статье я покажу вам применение алгоритма kNN (k - ближайших соседей) с использованием программирования на R.

Мы также рассмотрим пример, в котором описывается поэтапно процесс использования kNN для построения модели.

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

Что такое алгоритм kNN?

Предположим, у нас есть несколько групп маркированных образцов. Элементы, присутствующие в группах, являются по своей природе однородными. Теперь предположим, что у нас есть немаркированный пример, который нужно отнести к одной из нескольких маркированных групп. Как ты это делаешь? Как правило, используя kNN-алгоритм.

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


Как выбрать подходящее значение k?

Выбор количества ближайших соседей, т. е. определение значения k, играет значительную роль в эффективности модели. То есть, выбор k определит, насколько хорошо данные подходят для обобщения результатов алгоритма kNN. Большое значение k дает преимущество, которое заключается в уменьшении дисперсии для шумных данных; при этом наблюдается побочный эффект смещения, из-за которого обучаемый алгоритм стремится игнорировать более мелкие паттерны, которые могут нести полезную информацию.

В приведенном ниже примере мы на практике рассмотрим выбор подходящего значения k.

Пример алгоритма kNN

Давайте рассмотрим 10 напитков, которые оцениваются по двум параметрам по шкале от 1 до 10. Этими параметрами являются «сладость» и «газированность». Это оценка, скорее основанная на восприятии, и поэтому может отличаться у каждого человека. Оценки нескольких напитков выглядят так:



«Сладость» определяет восприятие содержания сахара в напитках. «Газированность» обнаруживает наличие пузырьков в напитке из-за содержания углекислого газа. Опять же, все эти рейтинги основаны на личном восприятии и являются относительными.



Из приведенного выше рисунка ясно, что мы разделили 10 напитков на 4 группы, а именно: «COLD DRINKS», «ENERGY DRINKS», «HEALTH DRINKS» и «HARD DRINKS». Вопрос здесь в том, к какой группе отнести напиток «Maaza»? Это можно определить путем вычисления расстояния.

Вычисление расстояния

Теперь рассчитаем расстояния между «Maaza» и его ближайшими соседями («ACTIV», «Vodka», «Pepsi» и «Monster»). Для этого нам нужно выбрать формулу расчета расстояния, наиболее популярной из является евклидово расстояние, т.е. кратчайшее расстояние между 2 точками, которые может быть получено с помощью линейки.




Используя координаты Maaza (8,2) и Vodka (2,1), расстояние между «Maaza» и «Vodka» можно рассчитать как:

dist(Maaza,Vodka) = 6.08



Используя евклидово расстояние, мы можем рассчитать расстояние от Maaza до каждого из ближайших соседей. Расстояние между Maaza и ACTIV является наименьшей, можно предположить, что Maaza такой же природы, как ACTIV, который, в свою очередь, относится к группе напитков (Health Drinks).

Если k = 1, алгоритм рассматривает самого ближайшего соседа к Maaza, т.е. ACTIV; если k = 3, алгоритм сравнивает расстояния от 3 ближайших соседей до Maaza (ACTIV, Vodka, Monster) - ближе всего к Maaza стоит ACTIV.

Преимущества и недостатки алгоритма kNN

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

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

Пример: диагностика рака простаты

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

Давайте посмотрим на процесс построения этой модели с использованием алгоритма kNN в R. Ниже вы увидите, что я объясняю каждую строку кода, написанную для выполнения этой задачи.

Этап 1- сбор данных

Мы будем использовать набор данных для 100 пациентов (созданных исключительно для примера) для реализации алгоритма knn и интерпретации результатов. Набор данных был подготовлен с учетом результатов, которые обычно получают из DRE (Digital Rectal Exam). Вы можете загрузить набор данных и повторить этот пример.

Набор данных состоит из 100 наблюдений и 10 переменных (из которых 8 переменных числовых и одна категориальная, а также ID):

- радиус
- текстура
- периметр
- гладкость
- компактность
- симметричность
- фрактальная размерность

В реальной жизни для измерения вероятности развития рака используются десятки важных параметров, но для простоты мы рассмотрим только 8 из них.

Вот как выглядит набор данных:


Этап 2- подготовка и исследование данных

Давайте сначала разберем наш код, прежде чем переходить к следующему этапу:

# Эта команда импортирует требуемый набор данных и сохраняет его в data frame с 
#именем  prc. 
> prc <- read.csv="" rostate_cancer.csv="" stringsasfactors="FALSE)</font">
# Эта команда помогает конвертировать каждый символьный вектор в фактор везде, 
#где имеет смысл.
> stringsAsFactors = FALSE
# С помощью этой команды мы просматриваем структуру наших данных.
> str(prc)
'data.frame':   100 obs. of  10 variables:
 $ id               : int  1 2 3 4 5 6 7 8 9 10 ...
 $ diagnosis_result : chr  "M" "B" "M" "M" ...
 $ radius           : int  23 9 21 14 9 25 16 15 19 25 ...
 $ texture          : int  12 13 27 16 19 25 26 18 24 11 ...
 $ perimeter        : int  151 133 130 78 135 83 120 90 88 84 ...
 $ area             : int  954 1326 1203 386 1297 477 1040 578 520 476 ...
 $ smoothness       : num  0.143 0.143 0.125 0.07 0.141 0.128 0.095 0.119 0.127 0.119 ...
 $ compactness      : num  0.278 0.079 0.16 0.284 0.133 0.17 0.109 0.165 0.193 0.24 ...
 $ symmetry         : num  0.242 0.181 0.207 0.26 0.181 0.209 0.179 0.22 0.235 0.203 ...
 $ fractal_dimension: num  0.079 0.057 0.06 0.097 0.059 0.076 0.057 0.075 0.074 0.082 ...

Мы видим, что данные структурированы в 10 переменных и 100 наблюдений. Первая переменная «id» может быть удалена, так как она не предоставляет полезную информацию.

# удаляем первую переменную (id) из набора данных
> prc <- font="" prc="">


Набор данных содержит пациентов, у которых были диагностированы злокачественные (M) или доброкачественные (B) опухоли.

# помогает нам получить количество пациентов
> table(prc$diagnosis_result)

 B  M 
38 62 

(diagnost_result - наша целевая переменная, то есть эта переменная будет определять результаты диагноза на основе 8 числовых переменных)

Если мы хотим переименовать B как «Benign» (доброкачественные) и M как «Malignant» (злокачественные) и увидеть результаты в процентной форме, мы можем написать:

> prc$diagnosis <- diagnosis_result="" factor="" font="" levels="c(" prc="">
labels = c("Benign", "Malignant"))

# выдает результат в процентной форме, округленной до 1-й цифры после запятой
> round(prop.table(table(prc$diagnosis)) * 100, digits = 1)

   Benign Malignant 
       38        62 

Нормализация численных данных

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

> normalize <- font="" function="" x="">
return ((x - min(x)) / (max(x) - min(x))) }

Мы запускаем этот код, когда нам нужно нормализовать числовые признаки в наборе данных. Вместо нормализации каждой из 8 отдельных переменных мы делаем все сразу:

> prc_n <- as.data.frame="" font="" lapply="" normalize="" prc="">

Первой переменной в нашем наборе данных (после удаления id) является «diagn_result», которая не числовая по своей природе. Поэтому мы начинаем со второй переменной. Функция lapply () применяет normalize () к каждому признаку во фрейме данных. Конечный результат с помощью функции as.data.frame () сохраняется в data frame prc_n.

Давайте проверим на переменной «radius», были ли данные нормализованы.

> summary(prc_n$radius)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.1875  0.5000  0.4906  0.7500  1.0000 

Результаты показывают, что данные были нормализованы. Попробуйте другие переменные, такие как perimeter, area и т.д.

Создание обучающего и тестового наборов данных

Алгоритм kNN применяется к обучающему набору данных, и затем результаты проверяются на тестовом наборе.

Для этого мы разделим набор данных на 2 части в соотношении 65: 35 для обучающего и тестового набора данных соответственно. Вы можете использовать другое соотношение в зависимости от ваших требований.

Мы разделим data frame prc_n на prc_train и prc_test.

> prc_train <- font="" prc_n="">
> prc_test <- font="" prc_n="">

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

Наша целевая переменная - «diagn_result».

#Этот код принимает фактор diagnosis в первом столбце prc, и создает data 
#frame prc_train_labels и prc_test_labels. 
> prc_train_labels <- 1="" font="" prc="">
> prc_test_labels <- 1="" font="" prc="">
Этап 3 – Обучение модели

Для обучения модели используется функция knn (), для этого нам необходимо установить пакет «class». Функция knn () идентифицирует k-ближайших соседей, используя эвклидово расстояние, где k - заданное пользователем число.

Для этого вам нужно ввести следующие команды:

> install.packages("class")
> library(class)

Теперь мы готовы использовать функцию knn() для классификации тестовых данных.

> prc_test_pred <- font="" knn="" prc_train_labels="" test="prc_test,cl" train="prc_train,">
 k=10)

Значение k обычно выбирается как квадратный корень из числа наблюдений.

knn() возвращает значение коэффициента для прогнозируемых столбцов для каждого из примеров в наборе тестовых данных, которое затем присваивается prc_test_pred

Этап 4 – оценка эффективности модели

Мы построили модель, но нам также нужно проверить точность предсказанных значений в prc_test_pred, соответствуют ли они известным значениям в prc_test_labels. Для этого нам нужна функция CrossTable () из пакета gmodels.

Мы можем установить этот пакет с помощью следующей команды:

> install.packages("gmodels")

Далее проверяем точность предсказанных значений:

> library(gmodels)
> CrossTable(x=prc_test_labels, y=prc_test_pred, prop.chisq = FALSE)

 
   Cell Contents
|-------------------------|
|                       N |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  35 

 
                | prc_test_pred 
prc_test_labels |         B |         M | Row Total | 
----------------|-----------|-----------|-----------|
              B |         7 |        12 |        19 | 
                |     0.368 |     0.632 |     0.543 | 
                |     0.875 |     0.444 |           | 
                |     0.200 |     0.343 |           | 
----------------|-----------|-----------|-----------|
              M |         1 |        15 |        16 | 
                |     0.062 |     0.938 |     0.457 | 
                |     0.125 |     0.556 |           | 
                |     0.029 |     0.429 |           | 
----------------|-----------|-----------|-----------|
   Column Total |         8 |        27 |        35 | 
                |     0.229 |     0.771 |           | 
----------------|-----------|-----------|-----------|

Тестовые данные состояли из 35 наблюдений. Из них 7 случаев были точно предсказаны (TN-> True Negatives) как Benign (B), что составляет 20%. Кроме того, 15 из 35 наблюдений были точно предсказаны (TP-> True Positives) как Malignant (M), что составляет 42,8%.

Был один случай False Negatives (FN), когда на самом деле опухоль была злокачественной по своей природе, но была предсказана как доброкачественная.

Было 12 случаев ложных положительных результатов (FP), что означает, что 12 случаев были фактически доброкачественными по своей природе, но были предсказаны как злокачественные.

Общая точность модели составляет 62,8% ((TN + TP) / 35), таким образом, могут быть шансы улучшить ее эффективность.

Этап 5 – улучшение эффективности модели

Это можно сделать, повторив шаги 3 и 4 с другими значениями k. Как правило, в качестве k берется квадратный корень числа наблюдений, и в нашем случае мы взяли k = 10. Для повышения точности прогнозирования значение k можно менять в определенном диапазоне. Попробуйте сделать это со значениями по вашему выбору. Также помните, что необходимо сохранять минимально возможное значение FN.

Комментариев нет:

Отправить комментарий