[Боевая задача машинного обучения 1] (KNN) применение алгоритма k-ближайшего соседа

машинное обучение
[Боевая задача машинного обучения 1] (KNN) применение алгоритма k-ближайшего соседа

1. Предпосылки

1.1 Обзор алгоритма k-ближайших соседей

(1) Введение в алгоритм k-ближайшего соседа

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

(2) Как работает алгоритм k-ближайшего соседа

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

(3) Случай алгоритма k-ближайших соседей

В настоящее время подсчитано количество сцен поцелуев и драк в фильмах 6. Предположим, есть невиданный фильм, как определить, романтический это фильм или боевик?

название фильма боевой выстрел поцелуй типы фильмов
California Man 3 104 Романтика
Он не очень любит чуваков 2 100 Романтика
Beautiful Woman 1 81 Романтика
Kevin Longblade 101 10 Боевик
Robo Slayer 3000 99 5 Боевик
Amped II 98 2 Боевик
? 18 90 неизвестный

Согласно принципу алгоритма KNN, мы можем найти расстояние между неизвестным фильмом и каждый фильм (здесь используется евклидовое расстояние)

Возьмем, к примеру, мужчину из Калифорнии.

>>>((3-18)**2+(104-90)**2)**(1/2)
20.518284528683193

название фильма расстояние от неизвестного я фильм
California Man 20.5
Он не очень любит чуваков 18.7
Beautiful Woman 19.2
Kevin Longblade 115.3
Robo Slayer 3000 117.4
Amped II 118.9

Следовательно, мы можем найти первые k фильмов с самым близким расстоянием в выборке.Предполагая, что k = 3, первые три фильма все романтические фильмы, поэтому мы определяем, что неизвестные фильмы относятся к мелодрамам.

1.2 Реализовать алгоритм k-ближайших соседей с помощью кода Python

(1) Рассчитать расстояние между каждой точкой в ​​наборе данных известного класса и текущей точкой

(2) Сортировка по возрастанию расстояния

(3) Выберите k точек с наименьшим расстоянием от текущей точки

(4) Определить частоту появления категории первых k точек

(5) Вернуть категорию с наибольшей частотой появления первых k точек в качестве прогнозируемой классификации текущей точки.

import numpy as np
import operator

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

(6) Чехлы

>>>group = np.array([[1, 1.1],
...                 [1, 1],
...                 [0, 0],
...                 [0, 0.1]])
>>>labels = ['A', 'A', 'B', 'B']
>>>classify0([0,0], group, labels, 3)
'B'

1.3 Как протестировать классификатор

Обычно, чтобы проверить эффект классификации, заданный классификатором, мы обычно оцениваем эффект классификатора, вычисляя частоту ошибок классификатора. То есть количество ошибок классификации, деленное на общее количество классификаций. У идеального классификатора частота ошибок равна 0, а у наихудшего классификатора частота ошибок равна 1.

2 Использование алгоритма kNN для повышения эффективности сопоставления сайтов знакомств

2.1 Введение в дело

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

2.2 Подготовка данных

Ниже представлены два канала для загрузки наборов данных:

«Официальная загрузка кода версии python2 для борьбы с машинным обучением»

"202xxx's github скачать код версии python3"

Данные хранятся в файле датированияTestSet2.txt, каждый образец занимает одну строку, всего 1000 строк данных, в основном включая следующие три характеристики:

Мили для часто летающих пассажиров за год, процент времени, проведенного за видеоиграми, литры мороженого, потребляемые в неделю

Перед вводом данных в классификатор данные необходимо преобразовать в стиль, который может распознать классификатор.

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = np.zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

Характеристические данные (datingDataMat), считанные с помощью file2matix, выглядят следующим образом

array([[4.0920000e+04, 8.3269760e+00, 9.5395200e-01],
        [1.4488000e+04, 7.1534690e+00, 1.6739040e+00],
        [2.6052000e+04, 1.4418710e+00, 8.0512400e-01],
        ...,
        [2.6575000e+04, 1.0650102e+01, 8.6662700e-01],
        [4.8111000e+04, 9.1345280e+00, 7.2804500e-01],
        [4.3757000e+04, 7.8826010e+00, 1.3324460e+00]]

Данные метки (datingLabels) следующие:

[3,2,1,1,1,1,3,3,...,3,3,3]

2.3 Анализ данных: использование Matplotlib для создания точечных диаграмм

(1) График корреляции между процентом времени, проведенного за видеоиграми, и количеством литров мороженого, потребляемых в неделю.

import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*np.array(datingDLabels), 15.0*np.array(datingDLabels))
plt.show()

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

Фиолетовый не нравится, зеленый посредственный, желтый очень привлекательный

(2) График корреляции между количеством миль для часто летающих пассажиров и процентом времени, проведенного за видеоиграми.

import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*np.array(datingDLabels), 15.0*np.array(datingDLabels))
plt.show()

где ось ординат — процент времени, проведенного за видеоиграми, а ось абсцисс — количество миль для часто летающих пассажиров.

Фиолетовый не нравится, зеленый посредственный, желтый очень привлекательный

(3) График корреляции между милями часто летающих пассажиров и еженедельным потреблением литров мороженого.

import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0], datingDataMat[:,2], 15.0*np.array(datingDLabels), 15.0*np.array(datingDLabels))
plt.show()

Среди них по оси Y отложено количество литров мороженого, потребляемых в неделю, а по оси X — количество миль для часто летающих пассажиров.

Фиолетовый не нравится, зеленый посредственный, желтый очень привлекательный

2.4 Подготовка данных: нормированные значения

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

((0-67)**2+(20000-32000)**2+(1.1-0.1)**2)**1/2

Процент времени, проведенного за видеоиграми мили для часто летающих пассажиров Потребление литров мороженого в неделю Пример классификации
1 0.8 400 0.5 1
2 12 134000 0.9 3
3 0 20000 1.1 2
4 67 32000 0.1 2

Обычно, когда мы имеем дело с функциями с разными диапазонами значений, мы часто используем нормализацию для обработки, сопоставляем значения функций в диапазоне от 0-1 или от -1 до 1 путем сопряжения (все значения в столбце - минимальное значение в столбце) / (максимальное значение в столбце - минимальное значение в столбце) для нормализации признаков

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals, (m,1))
    normDataSet = normDataSet/np.tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals

2.5 Тестирование алгоритма: проверка классификатора как законченной программы

Оценка правильной скорости — очень важный шаг в алгоритме машинного обучения.Обычно мы используем только 90% обучающих выборок для обучения классификатора, а оставшиеся 10% используются для проверки правильной скорости классификатора. Чтобы не влиять на случайность данных, нам нужно случайным образом выбрать 10% данных.

(1) Используйте функцию file2matrix для импорта образцов данных

(2) Используйте autoNorm для нормализации данных

(3) Используйте classify0 для обучения 90% данных и тестирования 10% данных.

(4) Выведите частоту ошибок в тестовом наборе.

def datingClassTest():
    hoRatio = 0.50      #hold out 10%
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print ("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)

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

2.5 Использование алгоритмов: построение полной пригодной для использования системы

С помощью приведенного выше исследования мы пытаемся разработать программу для Хелен, Найдя чью-то информацию на сайте знакомств и введя ее в программу, программа выдаст прогнозируемое значение симпатии Хелен друг к другу: неприязнь, среднее обаяние, чрезвычайно привлекательная

import numpy as np
import operator

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = np.zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - np.tile(minVals, (m,1))
    normDataSet = normDataSet/np.tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

def classifyPerson():
    resultList = ["not at all", "in small doses", "in large doses"]
    percentTats = float(input("percentage of time spent playing video games?"))
    ffMiles = float(input("ferquent fiter miles earned per year?"))
    iceCream = float(input("liters of ice ice crean consumed per year?"))
    datingDataMat,datingLabels = file2matrix('knn/datingTestSet2.txt')       #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr = np.array([percentTats, ffMiles, iceCream])


    classifierResult = classify0((inArr-minVals)/ranges, normMat, datingLabels,3)
    print ("You will probably like this person:", resultList[classifierResult-1])

if __name__ == "__main__":
    classifyPerson()#10    10000    0.5

Введите тестовые данные:

percentage of time spent playing video games?10
ferquent fiter miles earned per year?10000
liters of ice ice crean consumed per year?0.5
You will probably like this person: not at all

3 Сделайте рукописные идентификационные системы с помощью алгоритма KNN

3.1 Введение в дело

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

Обычно числа, введенные вручную, имеют формат изображения. Нам нужно преобразовать изображение в структурированные данные, которые могут быть распознаны алгоритмом knn. Короче говоря, это чтение пикселей на изображении. Значение пикселя обычно находится между 0 -255, а 0 — черный, 255 — белый, поэтому пиксели со значением больше 250 можно пометить как 1, а остальные пометить как 0, а написанное от руки число 1 можно представить следующим набором данных:

1 1 1 1 1 1 1 1 1 1
1 1 1 1 0 0 0 1 1 1
1 1 1 1 0 0 0 1 1 1
1 1 1 1 0 0 1 1 1 1
1 1 1 1 0 0 1 1 1 1
1 1 1 1 0 0 1 1 1 1
1 1 1 1 0 0 1 1 1 1
1 1 1 1 0 0 1 1 1 1
1 1 1 0 0 0 0 1 1 1
1 1 1 1 1 1 1 1 1 1

3.2 Подготовка данных: преобразование изображений в тестовые векторы

Существует два канала для загрузки наборов данных:

«Официальная загрузка кода версии python2 для борьбы с машинным обучением»

"202xxx's github скачать код версии python3"

Набор данных хранится в файле digits.zip, где 1 представляет рукописную область, а 0 — пустую область.

Прочитайте данные через функцию img2vector и верните массив

def img2vector(filename):
    returnVect = np.zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

3.3 Алгоритм тестирования, используйте kNN для распознавания рукописных цифр

(1) Используйте listdir для чтения всех файлов в каталоге trainingDigits в качестве обучающих данных.

(2) Используйте listdir для чтения всех файлов в каталоге testDigits в качестве тестовых данных.

(3) Подайте обучающие данные и тестовые данные в алгоритм knn.

def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')           #load the training set
    m = len(trainingFileList)
    trainingMat = np.zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
    testFileList = listdir('testDigits')        #iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print ("the classifier came back with: %d, the real answer is: %d"% (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0
    print ("\nthe total number of errors is: %d" % errorCount)
    print ("\nthe total error rate is: %f" % (errorCount/float(mTest)))

Выведите результаты обучения, частота ошибок составляет 1,1628%, и частота ошибок будет меняться при изменении значения k и обучающих выборок.

the classifier came back with: 7, the real answer is: 7
the classifier came back with: 7, the real answer is: 7
the classifier came back with: 9, the real answer is: 9
the classifier came back with: 0, the real answer is: 0
the classifier came back with: 0, the real answer is: 0
the classifier came back with: 4, the real answer is: 4
the classifier came back with: 9, the real answer is: 9
the classifier came back with: 7, the real answer is: 7
the classifier came back with: 7, the real answer is: 7
the classifier came back with: 1, the real answer is: 1
the classifier came back with: 5, the real answer is: 5
the classifier came back with: 4, the real answer is: 4
the classifier came back with: 3, the real answer is: 3
the classifier came back with: 3, the real answer is: 3

the total number of errors is: 11

the total error rate is: 0.011628

4 Резюме

4.1 Преимущества и недостатки алгоритма k-ближайших соседей

(1) Преимущества: высокая точность, нечувствительность к выбросам, отсутствие допущений при вводе данных.

(2) Недостатки: высокая вычислительная сложность и высокая пространственная сложность.

Применимый диапазон данных: числовой и номинальный

4.2 Общий процесс алгоритма k-ближайших соседей

(1) Сбор данных: можно использовать любой метод

(2) Подготовьте данные: значение, необходимое для расчета расстояния, предпочтительно в формате структурированных данных.

(3) Анализ данных L: можно использовать любой метод

(4) Алгоритм обучения: этот шаг не подходит для алгоритма k-ближайших соседей.

(5) Алгоритм тестирования: расчет частоты ошибок

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

4.3 Проблемы, на которые необходимо обратить внимание при использовании алгоритма k-ближайших соседей

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

(2) При расчете расстояния между данными обычно используется евклидово расстояние

(3) Выбор значения K в алгоритме kNN будет иметь большее влияние на результаты.Как правило, значение k меньше, чем квадратный корень из данных обучающей выборки.

(4) Метод перекрестной проверки обычно используется для выбора оптимального значения K.

Reference

«Машинное обучение в действии»