Попитах ChatGPT за втория най-прост алгоритъм за машинно обучение и той ме посъветва k-най-близките съседи. Отново ще поискаме скрипт на Python без никакви фантастични пакети и ще го възпроизведем в JavaScript, за да сме сигурни, че трябва ръчно да кодираме всички подробности.
Източници
K-най-близки съседи
Мисля, че ChatGPT излъга, като каза, че Perceptron е най-лесният модел за машинно обучение, тъй като този изглежда много по-лесен. По същество начертавате всички точки от данни за различни категории върху диаграма и проверявате кои са най-близки до вашите тестови променливи. Можете да вземете произволен брой (k
) брой съседи. Ако има съседи от няколко категории, вземете най-често срещаната.
Ще направим прогнози за множество тестови стойности, така че прогнозната част ще бъде цикъл. Това са стъпките за намиране на прогнозираните стойности:
Първо ще настроим някои данни за обучение и някои настройки. По желание можете да регистрирате всяка стъпка, за да видите какво се случва, като зададете extraLogging
на true
.
const X_train = [[1, 2], [2, 1], [2, 3], [3, 2]] const y_train = [0, 0, 1, 1] // settings const k = 3 const extraLogging = false
Функция на евклидовото разстояние
Евклидовото разстояние е просто разстоянието от една точка на диаграмата до следващата. Ще трябва да го изчислим за всяка входна точка към всяка точка в набора за обучение. За да започнем, трябва да извадим всички стойности в масива за обучение от стойността в масива за тестване. След това тези стойности трябва да бъдат повдигнати на квадрат, сумирани и корен квадратен → Евклидово разстояние.
function euclidean_distance(testArr, trainArr) { const sub = testArr.map((testVal, i) => { return testVal - trainArr[i] }) if (extraLogging) console.log(`sub ${sub}`) const power = sub.map(val => val**2) if (extraLogging) console.log(`power ${power}`) const sum = power.reduce((total, val) => total + val, 0) if (extraLogging) console.log(`sum ${sum}`) const sqrt = Math.sqrt(sum) if (extraLogging) console.log(`sqrt ${sqrt}`) return sqrt }
Функция Knn
function knn(X_train, y_train, X_test, k) { const y_pred = [] // for multiple predictions X_test.forEach(test_point => { // Calculate distance between the test point and all training points let distances = [] X_train.forEach((train_point, i) => { const label = y_train[i] const distance = euclidean_distance(test_point, train_point) distances.push([distance, label]) }) if (extraLogging) console.log({distances}) // Ascending const sortedDistances = distances.sort(([distance], [distance2]) => { return distance - distance2 }) if (extraLogging) console.log({sortedDistances}) // Get labels for k nearest neighbors const k_nearest_labels = sortedDistances.slice(0,3).map(([x,lab]) => lab) if (extraLogging) console.log({k_nearest_labels}) // Predict label by majority vote const setval = new Set(k_nearest_labels) if (extraLogging) console.log(setval) // const max = Math.max(...setval) const pred_label = [...setval].reduce((a, b) => k_nearest_labels.filter(v => v === a).length >= k_nearest_labels.filter(v => v === b).length ? a : b); y_pred.push(pred_label) }) return y_pred }
Тези разстояния сега трябва само да бъдат сортирани, като изберете горните k
съседи, изберете най-често срещаното и ето вашата прогноза.
// Predict X_test = [[1, 1], [3, 3], [1, 3], [3, 1], [2, 3], [3, 2], [2, 2]] const y_pred = knn(X_train, y_train, X_test, k) X_test.forEach((test, i) => console.log({ test, pred: y_pred[i] }))
Визуализирайте
За да видим всъщност какво се случва, можем да разгледаме две прогнози: 1, 1
и 3, 3
, които и двете не са в набора за обучение. В резултата по-долу можете да видите 1, 1
най-близките съседи са 2, 1
и 1, 2
, които и двамата са предвидили 0
. 3, 3
е най-близо до 3, 1
и 1, 3
с IV стойност 1
:
Заключение
Още веднъж фантастичните функции на Python се опитаха да ни улеснят твърде много, като направиха няколко неща в един ред код. Надяваме се, че тази неефективна версия на JavaScript ви е накарала да мислите повече за подробностите.