2015-03-09 2 views
4

Я пишу алгоритм интеллектуального анализа данных в Scala, и я хочу написать функцию Euclidean Distance для данного теста и нескольких экземпляров поезда. У меня есть Array[Array[Double]] с экземплярами тестов и поездов. У меня есть метод, который проходит через каждый тестовый экземпляр против всех экземпляров обучения и вычисляет расстояния между ними (выбор одного теста и экземпляра поезда на итерацию) и возвращает Double.Самый простой способ представления Euclidean Distance в scala

Скажет, например, у меня есть следующие точки данных:

testInstance = Array(Array(3.2, 2.1, 4.3, 2.8)) 
trainPoints = Array(Array(3.9, 4.1, 6.2, 7.3), Array(4.5, 6.1, 8.3, 3.8), Array(5.2, 4.6, 7.4, 9.8), Array(5.1, 7.1, 4.4, 6.9)) 

У меня есть метод заглушка (подсветка функции расстояния), которая возвращает сосед вокруг данного экземпляра теста:

def predictClass(testPoints: Array[Array[Double]], trainPoints: Array[Array[Double]], k: Int): Array[Double] = { 

    for(testInstance <- testPoints) 
    { 
     for(trainInstance <- trainPoints) 
     { 
      for(i <- 0 to k) 
      { 
       distance = euclideanDistanceBetween(testInstance, trainInstance) //need help in defining this function 
      } 
     } 
    }  
    return distance 
} 

Я знаю, как написать обобщенную формулу Евклидовой дистанции как:

math.sqrt(math.pow((x1 - y1), 2) + math.pow((x2 - y2), 2)) 

У меня есть несколько псевдонимов O шаги относительно того, что я хочу способ сделать с основным определением функции:

def distanceBetween(testInstance: Array[Double], trainInstance: Array[Double]): Double = { 
    // subtract each element of trainInstance with testInstance 
    // for example, 
    // iteration 1 will do [Array(3.9, 4.1, 6.2, 7.3) - Array(3.2, 2.1, 4.3, 2.8)] 
    // i.e. sqrt(3.9-3.2)^2+(4.1-2.1)^2+(6.2-4.3)^2+(7.3-2.8)^2 
    // return result 
    // iteration 2 will do [Array(4.5, 6.1, 8.3, 3.8) - Array(3.2, 2.1, 4.3, 2.8)] 
    // i.e. sqrt(4.5-3.2)^2+(6.1-2.1)^2+(8.3-4.3)^2+(3.8-2.8)^2 
    // return result, and so on...... 
    } 

Как я могу написать это в коде?

ответ

7

Итак, формула, которую вы вводите, работает только для двумерных векторов. У вас есть четыре измерения, но вы должны, вероятно, написать свою функцию, чтобы быть гибкой в ​​этом. Поэтому проверьте this formula.

Так что вы действительно хотите сказать:

for each position i: 
    subtract the ith element of Y from the ith element of X 
    square it 
add all of those up 
square root the whole thing 

Чтобы сделать это более функционально-программирование стиля он будет больше похож:

square root the: 
    sum of: 
    zip X and Y into pairs 
    for each pair, square the difference 

Так что будет выглядеть так:

import math._ 

def distance(xs: Array[Double], ys: Array[Double]) = { 
    sqrt((xs zip ys).map { case (x,y) => pow(y - x, 2) }.sum) 
} 

val testInstances = Array(Array(5.0, 4.8, 7.5, 10.0), Array(3.2, 2.1, 4.3, 2.8)) 
val trainPoints = Array(Array(3.9, 4.1, 6.2, 7.3), Array(4.5, 6.1, 8.3, 3.8), Array(5.2, 4.6, 7.4, 9.8), Array(5.1, 7.1, 4.4, 6.9)) 

distance(testInstances.head, trainPoints.head) 
// 3.2680269276736382 

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

def findNearestClasses(testPoints: Array[Array[Double]], trainPoints: Array[Array[Double]]): Array[Int] = { 
    testPoints.map { testInstance => 
    trainPoints.zipWithIndex.map { case (trainInstance, c) => 
     c -> distance(testInstance, trainInstance) 
    }.minBy(_._2)._1 
    } 
}  

findNearestClasses(testInstances, trainPoints) 
// Array(2, 0) 

Или, может быть, вы хотите k -ближайших соседи:

def findKNearestClasses(testPoints: Array[Array[Double]], trainPoints: Array[Array[Double]], k: Int): Array[Int] = { 
    testPoints.map { testInstance => 
    val distances = 
     trainPoints.zipWithIndex.map { case (trainInstance, c) => 
     c -> distance(testInstance, trainInstance) 
     } 
    val classes = distances.sortBy(_._2).take(k).map(_._1) 
    val classCounts = classes.groupBy(identity).mapValues(_.size) 
    classCounts.maxBy(_._2)._1 
    } 
}  

findKNearestClasses(testInstances, trainPoints) 
// Array(2, 1) 
+0

Большое вам спасибо за этот ответ. Это было очень полезно. У меня есть несколько разъяснений. Во-первых, что помогает линия 'distance (testInstances.head, trainPoints.head)? Вычитает ли он только элементы головы, а не следующие? –

+0

Во-вторых, в третьем блоке кода, чтобы найти 'kNearestNeighbours', что возвращает результат? Я хочу вернуть индекс 'testInstance' и класс, связанный с этим индексом (например,' Array ((0, ClassA), (1, ClassB), (2, ClassA), ...) ') и класс для каждого теста. Инстанс рассчитывается с использованием голосования большинства поколений k ближайших соседей (выбранных из «учебных очков»). Я буду использовать предсказания для сравнения с фактическим набором данных испытаний и сравнить его точность. Как я могу это сделать? –

+0

'distance (testInstances.head, trainPoints.head)' было просто продемонстрировать, как это работает. Он возвращает массив классов, причем каждая позиция массива соответствует тестовому экземпляру; если вы хотите прикрепить индекс как кортеж, это должно быть тривиально с '.map'. – dhg

Смежные вопросы