Машинное обучение Golang
Вычисление простых статических свойств
Статистическое обучение это ветвь применения статистики которая связана с машинным обучением.
Машинное обучение, которое тесно связано с вычислительной статистикой, это часть информатики которая пробует изучить данные и на их основе делать предсказания о их поведении без специального программирования.
В этой статье, мы собираемся изучить как сосчитать базовые статистические свойства, такие как среднее значение, минимальное и максимальное значение примера, медианное значение, а также дисперсию примера. Эти значения дадут вам отличное понимание вашего примера без среёзного погружения в детали. Однако, общие значения которые описывает пример, могут легко обмануть вас, заставив вас поверить, что вы хорошо знаете пример, и без них.
Все эти статистические свойства, будут посчитаны в stats.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
содержит следующий код:
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 это положительное целое. которое довольно маленькое.
The input of the algorithm consists of the k-closest training examples in the feature space. An object is classified by a plurality vote of its neighbors, with the object being assigned to the class that is the most common among its k-NN. If the value of k is 1 , then the element is simply assigned to the class that is the nearest neighbor according to the distance metric used. The distance metric depends on the data you are dealing with. As an example, you will need a different distance metric when working with complex numbers and another when working with points in three-dimensional space.
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)
The knn.NewKnnClassifier() method returns a new classifier. The last parameter of the function is the number of neighbors that the classifier will have.
The final part of classify.go is as follows:
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))
Working with tensorflow
TensorFlow is a rather famous open-source platform for machine learning. In order to use TensorFlow with Go, you will first need to download a Go package:
$ go get github.com/tensorflow/tensorflow/tensorflow/go
However, for the aforementioned command to work, the C interface for TensorFlow should be already installed. On a macOS Mojave machine, this can be installed as follows:
$ brew install tensorflow
If the C interface is not installed, and you try to install the Go package for TensorFlow, you will get the following error message:
$ 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) As TensorFlow is pretty complex, it would be good to execute the following command in order to validate your installation:
$ go test github.com/tensorflow/tensorflow/tensorflow/go
ok github.com/tensorflow/tensorflow/tensorflow/go 0.109s
Now let's begin with some code:
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())
}