# Машинное обучение Golang

# Вычисление простых статических свойств
Статистическое обучение это ветвь применения статистики которая связана с машинным обучением.

Машинное обучение, которое тесно связано с вычислительной статистикой, это часть информатики которая пробует изучить данные и на их основе делать предсказания о их поведении без специального программирования.

В этой статье, мы собираемся изучить как сосчитать базовые статистические свойства, такие как среднее значение, минимальное и максимальное значение примера, медианное значение, а также дисперсию примера. Эти значения дадут вам отличное понимание вашего примера без среёзного погружения в детали. Однако, общие значения которые описывает пример, могут легко обмануть вас, заставив вас поверить, что вы хорошо знаете пример, и без них.

Все эти статистические свойства, будут посчитаны в  `stats.go`, который будет представлен в пяти частях.
Каждая строка входного файла содержит одно число, которое значит, что входной файл читается построчно. Неправильный ввод будет проигнорирован без каких либо предупредительных сообщений.

	Ввод будет сохранен в срезе, чтобы можно было использовать отдельную функцию для подсчета каждого свойства. Так же, увидим, значения среза будут отсортированны перед обработкой.
```go
package main

import (
  "bufio"
  "flag"
  "fmt"
  "io"
  "math"
  "os"
  "sort"
  "strconv"
  "strings"
)


func min(x []float64) float64 {
  return x[0]
}

func max(x []float64) float64 {
  return x[len(x)-1]
}


func meanValue(x []float64) float64 {
 sum := float64(0)
 for _, v := range x {
   sum = sum + v
 }
  return sum / float64(len(x))
}


func medianValue(x []float64) float64 {

 length := len(x)
 if length%2 == 1 {
 // Odd
  return x[(length-1)/2]
 } else {
  // Even
   return (x[length/2] + x[(length/2)-1]) / 2
 }
  return 0
}


func variance(x []float64) float64 {

 mean := meanValue(x)
 sum := float64(0)

 for _, v := range x {
    sum = sum + (v-mean)*(v-mean)
 }
  return sum / float64(len(x))
}


func main() {

  flag.Parse()

  if len(flag.Args()) == 0 {

  fmt.Printf("usage: stats filename\n")
   return
 }

  data := make([]float64, 0)
  file := flag.Args()[0]

 f, err := os.Open(file)
  if err != nil {
   fmt.Println(err)
     return
 }

defer f.Close()
```
# Регрессия
Регрессия это статистический метод для расчета связи между переменными. Эта часть реализует линейную регрессию, которая наиболее популяная и наиболее простая техника, а так же наилучший способ понять наши данные. Заметим, что регрессия не имеет 100% точность, даже если вы использвали многочлен высшего порядка(нелинейный). Цель регрессия, как и в большинстве  ML техник - найти достаточно хорошую технику а не лучшую из лучших.

Линейная регрессия.
За этой регрессией прячется следующее: вы берете модель ваших данных используя уравнение первой степени. его можно представить как `y = a x + b`.

Есть множество методов, которые позволяют найти уравнение первого порядка, которое представит модель ваших данных  и вычислит `a`  и  `b`.

Реализация линейной регрессии.
Go код, этой части будет сохранен в  `regression.go`, который будет представлен в трех частях. Вывод программы будет два числа с плавающей запятой, которые определяют `a` и `b` для ураввнения первого порядка.

Первая часть `regression.go` содержит следующий код:
```go
package main


import (
  "encoding/csv"
  "flag"
  "fmt"
  "gonum.org/v1/gonum/stat"
  "os"
  "strconv"
)

type xy struct {
  x []float64
  y []float64
}


func main() {

  flag.Parse()

  if len(flag.Args()) == 0 {
    fmt.Printf("usage: regression filename\n")
    return
  }

  filename := flag.Args()[0]

  file, err := os.Open(filename)

 if err != nil {

    fmt.Println(err)
   return

 }

defer file.Close()

r := csv.NewReader(file)

records, err := r.ReadAll()

if err != nil {
  fmt.Println(err)
  return
}

size := len(records)

data := xy{
 x: make([]float64, size),
 y: make([]float64, size),
}

for i, v := range records {
if len(v) != 2 {
fmt.Println("Expected two elements")
continue
}
if s, err := strconv.ParseFloat(v[0], 64); err == nil {
data.y[i] = s
}
if s, err := strconv.ParseFloat(v[1], 64); err == nil {
data.x[i] = s

  }
}

b, a := stat.LinearRegression(data.x, data.y, nil, false)

fmt.Printf("%.4v x + %.4v\n", a, b)
fmt.Printf("a = %.4v b = %.4v\n", a, b)

}
```
# Классификация
В статистике и ML, классификация это процесс помещения элементов в существующие наборы которые называются категориями. В ML классификация подразумевает обучение с учителем, в котором набор предполагает содержание верно определенные данные используемые для обучение перед работой с реальными данными.

Очень простой и легко реализуемая метод классификации называется "k-близжайших соседей"(k-NN). Идея метода такова, что мы можем отсортировать данные основываясь на их схожести с другими предметами. "k" в "k-NN" обозначает число соседей которые должны быть включены в решение, которое значит что k это положительное целое. которое довольно маленькое. 

Ввод алгоритма состоит из k-близжайших примеров обучения, в свойстве пространства. Объект классифицируется множеством голосов его соседей, с объектом назначенным классу который в большинстве обобщен среду его k-NN. Если значение k = 1, значит элемент просто назначен классу, который ближе всего согласно расстоянию используемой метрики. Удаленная метрика зависит от данных с которыми работаете. Как пример вам нуно различное расстояние метрик, когда работает со сложными числами и другими, когда работаете в трехмерном пространстве.

```go
package main


import (

 "flag"
 "fmt"
 "strconv"
 "github.com/sjwhitworth/golearn/base"
 "github.com/sjwhitworth/golearn/evaluation"
 "github.com/sjwhitworth/golearn/knn"

)


func main() {
 flag.Parse()
 if len(flag.Args()) < 2 {
   fmt.Printf("usage: classify filename k\n")
   return
 }

dataset := flag.Args()[0]

rawData, err := base.ParseCSVToInstances(dataset, false)

 if err != nil {
  fmt.Println(err)
   return
 }

k, err := strconv.Atoi(flag.Args()[1])

 if err != nil {
  fmt.Println(err)
    return
 }

cls := knn.NewKnnClassifier("euclidean", "linear", k)
```
Метода `knn.NewKnnClassifier()` возвращает новый классификатор. Последний параметтр функции это количество соседей которые классификатор будет иметь.

Последняя часть `classify.go` показана ниже:
```go
train, test := base.InstancesTrainTestSplit(rawData, 0.50)
cls.Fit(train)

p, err := cls.Predict(test)
 if err != nil {
 fmt.Println(err)
 return
}

confusionMat, err := evaluation.GetConfusionMatrix(test, p)

if err != nil {
 fmt.Println(err)
 return
}

fmt.Println(evaluation.GetSummary(confusionMat))
```

# Работа с tensorflow
TensorFlow известная открытая платформа для ML. Для того чтобы использовать TensorFlow в Golang, нам нужно для начала скачать этот пакет.
```bash
 $ go get github.com/tensorflow/tensorflow/tensorflow/go
```
Однако, для работы вышеупомянутой команды, интерфейс C в TensorFlow должны быть уже установленны. На macOS машине, его можно установить таким образом:
```bash
$ brew install tensorflow
```
Если C интерфейс не установлен, и вы хотите установить Go пакет для TensorFlow, вы получите следующую ошибку:
```bash
$ go get github.com/tensorflow/tensorflow/tensorflow/go
# github.com/tensorflow/tensorflow/tensorflow/go
ld: library not found for -ltensorflow clang: error: linker command failed with exit code 1 (use -v to see invocation)
```
Так как TensorFlow достаточно сложен, он может быть хорош для выполнения следующей команды для проверки установки:
```bash
$ go test github.com/tensorflow/tensorflow/tensorflow/go

ok github.com/tensorflow/tensorflow/tensorflow/go  0.109s
```
Теперь начнем с некоторого кода:
```go
package main

import (
  tf "github.com/tensorflow/tensorflow/tensorflow/go"
  "github.com/tensorflow/tensorflow/tensorflow/go/op"
  "fmt"
 )


func main() {
 s := op.NewScope()
 c := op.Const(s, "Using TensorFlow version: " + tf.Version())

 graph, err := s.Finalize()
 if err != nil {
  fmt.Println(err)
  return
 }

sess, err := tf.NewSession(graph, nil)

 if err != nil {
  fmt.Println(err)
  return
 }

output, err := sess.Run(nil, []tf.Output{c}, nil)
 if err != nil {
  fmt.Println(err)
  return
 }
 fmt.Println(output[0].Value())
}
```