Попитах 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 ви е накарала да мислите повече за подробностите.