diff --git a/CMake/FindGo.cmake b/CMake/FindGo.cmake index e4a0af57d4..dfccd8a9fe 100644 --- a/CMake/FindGo.cmake +++ b/CMake/FindGo.cmake @@ -19,10 +19,6 @@ if (GO_EXECUTABLE) endif() endif() -if (NOT GO_EXECUTABLE) - unset(BUILD_GO_BINDINGS CACHE) -endif() - include(FindPackageHandleStandardArgs) find_package_handle_standard_args( Go diff --git a/doc/guide/go_quickstart.hpp b/doc/guide/go_quickstart.hpp index 64c130c4e3..9a67642857 100644 --- a/doc/guide/go_quickstart.hpp +++ b/doc/guide/go_quickstart.hpp @@ -15,7 +15,8 @@ and @ref julia_quickstart "Julia". @section go_quickstart_install Installing mlpack -Installing the mlpack bindings for Go is somewhat ticker; you can download +Installing the mlpack bindings for Go is somewhat time-consuming as the library +must be built; you can run the following code: @code{.sh} go get -d mlpack.org/v1/mlpack @@ -53,16 +54,10 @@ func main() { // Extract/Unzip the dataset. mlpack.UnZip("data.csv.gz", "data.csv") - f1, _ := os.Open("data.csv") - defer f1.Close() - data := mlpack.NewReader(f1) - dataset, _ := data.ReadAll() + dataset, _ := mlpack.Load("data.csv") mlpack.UnZip("labels.csv.gz", "labels.csv") - f2, _ := os.Open("labels.csv") - defer f2.Close() - labels_data := mlpack.NewReader(f2) - labels, _ := labels_data.ReadAll() + labels, _ := mlpack.Load("labels.csv") // Split the dataset using mlpack. params := mlpack.PreprocessSplitOptions() @@ -154,11 +149,7 @@ func main() { // Extract dataset. mlpack.UnZip("ratings-only.csv.gz", "ratings-only.csv") - f1, _ := os.Open("ratings-only.csv") - defer f1.Close() - data := mlpack.NewReader(f1) - _, _ = data.ReadHeading() - ratings, _ := data.ReadAll() + ratings, _ := mlpack.Load("ratings-only.csv") mlpack.UnZip("movies.csv.gz", "movies.csv") table, _ := csv.NewTable(csv.FromFile("movies.csv"), csv.LoadHeaders()) @@ -168,8 +159,7 @@ func main() { params := mlpack.PreprocessSplitOptions() params.TestRatio = 0.1 params.Verbose = true - ratings_test, _, ratings_train, _ := - mlpack.PreprocessSplit(ratings, params) + ratings_test, _, ratings_train, _ := mlpack.PreprocessSplit(ratings, params) // Train the model. Change the rank to increase/decrease the complexity of the // model. diff --git a/src/mlpack/bindings/go/CMakeLists.txt b/src/mlpack/bindings/go/CMakeLists.txt index d626c2280c..72b5c76549 100644 --- a/src/mlpack/bindings/go/CMakeLists.txt +++ b/src/mlpack/bindings/go/CMakeLists.txt @@ -1,4 +1,9 @@ if (BUILD_GO_BINDINGS) + + if (NOT GO_EXECUTABLE) + unset(BUILD_GO_BINDINGS CACHE) + endif() + ## We need to check here if Golang is even available. Although actually ## technically, I'm not sure if we even need to know! For the tests though we ## do. So it's probably a good idea to check. @@ -61,6 +66,7 @@ if (BUILD_GO_SHLIB) mlpack/arma_util.go mlpack/cli_util.go mlpack/doc.go + mlpack/numcsv.go ) # These are all the files we need to compile Go bindings for mlpack that are diff --git a/src/mlpack/bindings/go/mlpack/numcsv.go b/src/mlpack/bindings/go/mlpack/numcsv.go new file mode 100644 index 0000000000..15f1b14d89 --- /dev/null +++ b/src/mlpack/bindings/go/mlpack/numcsv.go @@ -0,0 +1,135 @@ +package mlpack + +import ( + "encoding/csv" + "io" + "os" + "strconv" + "net/http" + "compress/gzip" + + "gonum.org/v1/gonum/mat" +) + +// Load reads all of the numeric records from the CSV. +func Load(filename string) (*mat.Dense, error) { + var elements int + var rows int + var numbers []float64 + + // Open the file + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + + lines, err := csv.NewReader(file).ReadAll() + if err != nil { + return nil, err + } + + var str_err error + for _, args := range lines[0:] { + for _, arg := range args { + n, err := strconv.ParseFloat(arg, 64) + str_err = err + if err == nil { + numbers = append(numbers, n) + elements = elements + 1 + } + } + if str_err == nil { + rows = rows + 1 + } + } + data := numbers[:elements] + columns := elements/rows + output := mat.NewDense(rows , columns, data) + return output, nil +} + +// Save writes all of the records to the CSV. +func Save(filename string, mat *mat.Dense) error { + // Create the file + file, err := os.Create(filename) + if err != nil { + return err + } + defer file.Close() + + writer := csv.NewWriter(file) + defer writer.Flush() + + if mat != nil { + rows, cols := mat.Dims() + for i := 0; i < rows; i++ { + var strings []string + for j := 0; j < cols; j++ { + s := strconv.FormatFloat(mat.At(i,j), 'e', 16, 64) + strings = append(strings, s) + } + err := writer.Write(strings) + if err != nil { + return err + } + } + } + return nil +} + +// Unizp unzips the given input to the given the output file. +func UnZip(input string, output string) error { + // Create the file + out, err := os.Create(output) + if err != nil { + return err + } + defer out.Close() + + // Open the file + in, err := os.Open(input) + if err != nil { + return err + } + defer in.Close() + + // Unzip the data + resp, err := gzip.NewReader(in) + if err != nil { + return err + } + defer resp.Close() + + // Write the body to file + _, err = io.Copy(out, resp) + if err != nil { + return err + } + return nil +} + +// DownloadFile downloads the file from the given url and save it to the given filename. +func DownloadFile (url string, filename string) error { + // Create the file + out, err := os.Create(filename) + if err != nil { + return err + } + defer out.Close() + + // Get the data + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + // Write the body to file + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + + return nil +}