LoginSignup
2

More than 3 years have passed since last update.

GoでIrisDataSetの散布図を描く

Last updated at Posted at 2019-12-04

GoでIrisDatasetの散布図を作成する

この記事は Go4 Advent Calendar 2019 の4日目の記事です。

モチベーション

「機械学習と言えばPython、Pythonと言えば機械学習。」と言っても過言では無いくらいです。
沢山の書籍と、沢山のWeb上の記事、Kaggleでのノートやディスカッションの情報、沢山あります。
しかし、ライブラリは揃いきって無いかも知れませんが足りない物は自分で作りながら、Goで機械学習をしたいと思います。
とりあえずの、目標は、ゼロから作るディープラーニングをGoで実装して、Kaggleのチュートリアルをいくつか挑戦する事です。
今回はIrisのデータセットを散布図にしてみたいと思います。
今回のコードですhttps://github.com/yujiteshima/plot_test

散布図を作る

使うデータ:https://gist.github.com/netj/8836201
がく片の長さと幅、花びらの長さと幅、アヤメの種類の名前という、5つの値が入ったデータが151個あります。
アヤメの種類は3種類です。このデータはとても有名なデータです。

まず、使うライブラリですが、gonumというライブライを使います。
gonumには、Pythonで言う、行列計算の提供するnumpy、表や図の出力を行うmatplotlibや、統計の機能を提供する、scipyの機能を提供するライブラリです。あまり、使い方のサンプルも多く無いので、使いながら足らないところがあるのか等しらべて行きます。

ディレクトリ構成は以下のようにしました。
DRYでは無いので、今後直していきます。

.
├── go.mod
├── go.sum
├── iris.csv
├── main.go
├── main.go_bk
├── plot
│   ├── plotPetal.go
│   └── plotSepal.go
├── plotPetal.png
└── plotSepal.png

main.go

"github.com/yujiteshima/plot_test/plot"の部分はご自身の環境に合わせてモジュールのパスを入れて下さい。
相対パスではgo moduleを使っている際はgo run go build通りません。
参考:https://qiita.com/yujiteshima/items/8dc2f782f27f147a1e3e

main.go
package main

import (
    "github.com/yujiteshima/plot_test/plot"
)

func main() {
    plot.PlotSepal()
    plot.PlotPetal()
}

mainでは、PlotSepalというがく片の幅と長さの散布図とPlotPetalという花びらの幅と長さの散布図の2つの散布図をpngファイルとして出力するだけの内容になっています。

PlotSepal.go

package plot

import (
    "encoding/csv"
    "image/color"
    "os"
    "strconv"

    "gonum.org/v1/plot"
    "gonum.org/v1/plot/plotter"
    "gonum.org/v1/plot/vg"
)

func plotPointsSepal(x string) plotter.XYs {
    pts := make(plotter.XYs, 150)

    file, err := os.Open("./iris.csv")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    reader := csv.NewReader(file)
    var line []string

    for i := range pts {
        line, err = reader.Read()
        if err != nil {
            panic(err)
        }
        if line[4] == x {
            pts[i].X, _ = strconv.ParseFloat(line[0], 64)
            pts[i].Y, _ = strconv.ParseFloat(line[1], 64)
        }
    }
    return pts
}

func PlotSepal() {

    // 図の生成
    p, err := plot.New()
    if err != nil {
        panic(err)
    }
    //label
    p.Title.Text = "Sepal"
    p.X.Label.Text = "length"
    p.Y.Label.Text = "width"
    // 補助線
    p.Add(plotter.NewGrid())

    x1 := "Setosa"
    x2 := "Versicolor"
    x3 := "Virginica"

    // 散布図の作成
    plot1, err := plotter.NewScatter(plotPointsSepal(x1))
    if err != nil {
        panic(err)
    }

    plot2, err := plotter.NewScatter(plotPointsSepal(x2))
    if err != nil {
        panic(err)
    }
    plot3, err := plotter.NewScatter(plotPointsSepal(x3))
    if err != nil {
        panic(err)
    }

    //色を指定する.
    plot1.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 55}
    plot2.GlyphStyle.Color = color.RGBA{R: 155, B: 128, A: 255}
    plot3.GlyphStyle.Color = color.RGBA{R: 55, B: 255, A: 128}
    //plot1,plot2をplot
    p.Add(plot1)
    p.Add(plot2)
    p.Add(plot3)

    //label
    p.Legend.Add("Seotsa", plot1)
    p.Legend.Add("Versicolor", plot2)
    p.Legend.Add("Virginica", plot3)

    // 座標範囲
    p.X.Min = 0
    p.X.Max = 10
    p.Y.Min = 0
    p.Y.Max = 10

    // plotSepal.pngに保存
    if err := p.Save(6*vg.Inch, 6*vg.Inch, "plotSepal.png"); err != nil {
        panic(err)
    }
}

このように使いますが、今回CSVファイルをos.Openで開き順番に読み込んで、if文で花の種類を分けてプロットしました。
goの外部ライブラリに、pythonでいうpandasと同じようにdataframeを扱える、その名もdataframeというライブラリがあります。
データのnull値を調べたり、型の違うデータが入り混じっていたりした時のデータハンドリングを簡単に行えるライブラリを用いていかないと他のデータでは使えないと感じました。次はdataframeを使ってgonum.plotを使ってみたいです。

出力した散布図

plotSepal.png
plotPetal.png

見ただけでアヤメの種類ががく片のデータと花びらのデータから分類が可能な感じがすると思います。

まとめ

がく片と花びらの散布図を作るのにほぼ同じ関数を二つ定義して使っているので、そこをDRYにしたい。また、データ数を150と自分が決めた外部パラメータのようにコードの中に入れてしまっているので、そこも直して、使い回しが出来る形に直す工夫をしていきたい。
次は、実際に分類をする部分を実装していきます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2