go言語 で一次元、二次元配列を取り扱う package を作る

# go言語 で一次元、二次元配列を取り扱う package を作る
goで一次元、二次元配列を操作する package を作成しKMeansで有用性を確認しました
ソースはこちら
配列package:
int用１次元配列package https://github.com/ikuo0/go_number/tree/main/n1di
float用１次元配列package https://github.com/ikuo0/go_number/tree/main/n1df
float用２次元配列package https://github.com/ikuo0/go_number/tree/main/n2df

KMEANS package：
https://github.com/ikuo0/go_number/blob/main/kmeans/kmeans.go

## KMEANS 実行部

90行ほどでKMEANSに使用する関数がすべて実装できていますのでそれなりにコンパクトかと思います

``` go

package kmeans

import (
    "fmt"
    "math"
    
    "github.com/ikuo0/go_number/n1df"
    "github.com/ikuo0/go_number/n1di"
    "github.com/ikuo0/go_number/n2df"
)

type Model struct {
    Clusters int
    Iteration int
    Threshold float64
    InitMeans n2df.N
    Predict n1di.N
    Means n2df.N
}

func New(clusters int, iteration int, threshold float64) Model {
    return Model {
        Clusters: clusters,
        Iteration: iteration,
        Threshold: threshold,
    }
}

func (me* Model) InitRandom(x n2df.N) {
    indexes := n1di.Arange(0, len(x), 1)
    indexes = n1di.Shuffle(indexes)
    indexes = indexes[:me.Clusters]
    me.InitMeans = n2df.IndexingM(x, indexes)
}

func (me* Model) EStep(x n2df.N, means n2df.N) n1di.N {
    distances := n2df.New(len(x), me.Clusters)
    for m, row := range(x) {
        for cluster := 0; cluster < me.Clusters; cluster += 1 {
            diff := n1df.SubtractI(row, means[cluster])
            pow := n1df.Power(diff, 2)
            distance := n1df.Total(pow)
            distances[m][cluster] = distance
        }
    }
    
    predict := n1di.New(len(x))
    for m, distance := range(distances) {
        pred := n1df.ArgMin(distance)
        predict[m] = pred
    }
    return predict
}

func (me* Model) MStep(x n2df.N, predict n1di.N) n2df.N {
    means := make([][]float64, me.Clusters, len(x[0]))
    for cluster := 0; cluster < me.Clusters; cluster += 1 {
        indexes := n1di.WhereEq(predict, cluster)
        crows := n2df.IndexingM(x, indexes)
        cmeans := n2df.MeanM(crows)
        means[cluster] = cmeans
    }
    return means
}

func (me* Model) CalcMeansDistance(a n2df.N, b n2df.N) float64 {
    dif := n2df.SubtractX(a, b)
    pow := n2df.Power(dif, 2)
    total := n2df.TotalX(pow)
    distance := math.Sqrt(total / float64(me.Clusters))
    return distance
}

func (me* Model) Fit(x n2df.N) {
    me.InitRandom(x)
    
    me.Means = me.InitMeans
    for i := 0; i < me.Iteration; i += 1 {
        predict := me.EStep(x, me.Means)
        newMeans := me.MStep(x, predict)
        distance := me.CalcMeansDistance(me.Means, newMeans)
        me.Predict = predict
        me.Means = newMeans
        
        fmt.Println("distance", distance)
        if distance < me.Threshold {
            break
        }
    }
}


```

## ジェネリクス型が無いので冗長なpackage実装になる
すべての機能を実装しようと思うと下記４種類を作る必要があります。

* int用１次元配列package
* float用１次元配列package
* int用２次元配列package
* float用２次元配列package

当然ですが、min や max 、sort 系機能等も変数型が異なるだけで中身は全く一緒の実装でも各々のpackageに実装する必要があります、go言語だから仕方ないねというところです。

下記情報を見ると近々ジェネリクス型？が実装されるらしいのでこういった冗長さも近々解消されることと思います
https://medium.com/eureka-engineering/golang-generics-design-draft-linked-list-4d1174e2355d
https://text.baldanders.info/golang/generics-in-go-2-update/

## interfaceを使ってもう少し隠蔽できたんじゃないのかという箇所

``` go
func AdditionI(a N, b N) N {// 配列に対応する配列を加算する処理
    count := len(a)
    res := New(count)
    for i := 0; i < count; i += 1 {
        res[i] = a[i] + b[i]
    }
    return res
}

func Addition(a N, b float64) N {// 配列全てに一定の値を加算する処理
    count := len(a)
    res := New(count)
    for i := 0; i < count; i += 1 {
        res[i] = a[i] + b
    }
    return res
}
```

こういう処理は

``` go
func Addition(a N, b interface{}) N {
    // 処理
}
```

として内部で動的に振り分け処理でもすればスッキリさせることも可能ですが、interface使うと型付けしてる意味無いなーと思いそのような実装にはしませんでした、相当追い詰められるまで interface{} は使わないほうが良いとの判断です。

## 色んな言語で１次元、２次元配列クラスを作った

[C++で一次元、二次元配列を取り扱うクラスを作る](https://qiita.com/ikuo0/items/6ead5b8aca7089f28cc1)
[swift で一次元、二次元配列を取り扱うクラスを作る](https://qiita.com/ikuo0/items/6171b75a428228f4ce12)
[go言語 で一次元、二次元配列を取り扱うpackageを作る](https://qiita.com/ikuo0/items/73bd6ce76f584d3b8e6b)（本記事）

各言語の特徴を活かせたかどうかは分かりませんが、まずまずのデキなんじゃないでしょうか、予定してた物を完走できて良かったねというところです

以上です。