Vor etwas mehr als einem Monat habe ich das MLB-Baseball-Datenskript "[py-retrosheet](https://github.com/Shinichi-Nakagawa/py-retrosheet" py-retrosheet ")" kopiert, das mit Python 3.5 mit Golang kompatibel ist. Es war.
Es ist ein Skript auf Retrosheet (http://www.retrosheet.org/), das Übereinstimmungsdaten und Ergebnisse (hauptsächlich At-Bat-Daten) herunterlädt, sie auf eine Ebene analysiert, die für die Aggregation und Analyse verwendet werden kann, und CSV ausspuckt.
Das Original hat eine Funktion zum Durchsuchen der Datenbank (MySQL usw.), aber ich werde dies später vornehmen (Grund: Ngo, der die Schlafzeit nicht verkürzen möchte ... w).
Es spielt keine Rolle, aber der Name "Go! Retrosheet" hat viel Schwung und ist cool (Lesesticks)
Es gibt zwei Gründe.
In Last #gocon heißt es: "Ich habe noch nie Golang gemacht, obwohl ich gehen kann, also habe ich etwas mit Golang gemacht." Mit der Motivation von "Lass uns in LT springen!" [Ich habe in einem halben Tag eine Tour of Go gemacht und die Django-Anwendung mit Martini umgeschrieben und einen wunderbaren Sprung in LT gemacht](http://shinyorke.hatenablog.com/entry/2015/06/21 / 195656 "Golang Ich habe einen halben Tag später eine Baseball-App geschrieben und den Sommerbericht #gocon der LT ~ Go Conference 2015 gestartet.") Aber wenn ich darüber nachdenke, denke ich, dass ich Golang seitdem nicht mehr geschrieben habe (da war PyCon unterwegs). ..), ich werde diesmal schreiben, um an die Teilnahme von #gocon im Winter zu erinnern! Ich habe mit diesem Gefühl angefangen. LT dachte darüber nach, es rechtzeitig zu tun.
Auch als schwerwiegender Grund
Gehen Sie parallel verarbeiten ~
Go ist stark gegen ◯◯, also ist Baseball auch Go ~
Ich weiß nicht, ob Go genug ist, um zu sagen ... (oder besser gesagt, ich bin ein Anfänger im Knirschen), also lasst uns die Güte und Eigenschaften von Go beim Kopieren erneut bestätigen! Die Bedeutung von "Lernen" ist ebenfalls enthalten.
Ich habe gofmt und golint bestanden, aber es gibt insgesamt nur wenige Kommentare und es kann angebracht sein ... Experten, ich warte auf Meinungen m (_ _) m
Außerdem habe ich keine Tests geschrieben, daher handelt es sich um einen knusprigen Legacy-Code.
download.go
Dies ist der Code, der das Archiv (Zip-Datei) mit der CSV von Retrosheet im Dateiverzeichnis herunterlädt und dekomprimiert.
Ich habe den Code zum Entpacken der Zip-Datei unter Bezugnahme auf [hier] geschrieben (https://gist.github.com/hnaohiro/4572580 "Beispiel zum Entpacken der Zip-Datei mit Golang") und danke, dass Sie ordnungsgemäß funktioniert haben! Aber ich frage mich, ob ich schlauer schreiben kann? Ich dachte.
Außerdem habe ich zum ersten Mal Parallelverarbeitung in Go geschrieben, aber ich war überrascht, dass ich es so klar schreiben konnte.
download.go
// Copyright The Shinichi Nakagawa. All rights reserved.
// license that can be found in the LICENSE file.
package main
import (
"archive/zip"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"sync"
)
const (
// DirName a saved download file directory
DirName = "files"
)
// IsExist return a file exist
func IsExist(filename string) bool {
// Exists check
_, err := os.Stat(filename)
return err == nil
}
// MakeWorkDirectory a make work directory
func MakeWorkDirectory(dirname string) {
if IsExist(dirname) {
return
}
os.MkdirAll(dirname, 0777)
}
// DownloadArchives a download files for retrosheet
func DownloadArchives(url string, dirname string) string {
// get archives
fmt.Println(fmt.Sprintf("download: %s", url))
response, err := http.Get(url)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(fmt.Sprintf("status: %s", response.Status))
// download
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_, filename := path.Split(url)
fmt.Println(filename)
fullfilename := fmt.Sprintf("%s/%s", dirname, filename)
file, err := os.OpenFile(fullfilename, os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
fmt.Println(err)
}
defer func() {
file.Close()
}()
file.Write(body)
return fullfilename
}
// Unzip return error a open read & write archives
func Unzip(fullfilename string, outputdirectory string) error {
r, err := zip.OpenReader(fullfilename)
if err != nil {
return err
}
defer r.Close()
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
path := filepath.Join(outputdirectory, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
f, err := os.OpenFile(
path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
}
return nil
}
// GetEventsFileURL return a events file URL
func GetEventsFileURL(year int) string {
return fmt.Sprintf("http://www.retrosheet.org/events/%deve.zip", year)
}
// GetGameLogsURL return a game logs URL
func GetGameLogsURL(year int) string {
return fmt.Sprintf("http://www.retrosheet.org/gamelogs/gl%d.zip", year)
}
func main() {
// Commandline Options
var fromYear = flag.Int("f", 2010, "Season Year(From)")
var toYear = flag.Int("t", 2014, "Season Year(To)")
flag.Parse()
MakeWorkDirectory(DirName)
wait := new(sync.WaitGroup)
// Generate URL
urls := []string{}
for year := *fromYear; year < *toYear+1; year++ {
urls = append(urls, GetEventsFileURL(year))
wait.Add(1)
urls = append(urls, GetGameLogsURL(year))
wait.Add(1)
}
// Download files
for _, url := range urls {
go func(url string) {
fullfilename := DownloadArchives(url, DirName)
err := Unzip(fullfilename, DirName)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
wait.Done()
}(url)
}
wait.Wait()
}
dataset.go
chadwick ist ein Skript, das ein Dataset erstellt, indem ein Befehl in einer Bibliothek zum Auswerten von Daten gedrückt wird.
Es fiel mir schwer, die in der Chadwick-Bibliothek implementierten Befehle "cwgame" und "cwevent" auszuführen.
Es ist dasselbe wie die Python-Version bis zu dem Punkt, an dem Change Directory zum Ausführen von Befehlen verwendet wird (Argumente in / out sind relative Pfade), aber die Pfadeinstellungen sind beim Schreiben verwirrt, und es gibt viele Argumente für das Format der Zeichenfolge (this). Ist mein Designfehler, aber ich wusste nicht, wie man Python "" {hoge} ".format (hoge =" fuga ")") schreibt, und ich kämpfte mit langweiliger Sucht.
dataset.go
// Copyright The Shinichi Nakagawa. All rights reserved.
// license that can be found in the LICENSE file.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"sync"
)
const (
// ProjectRootDir : Project Root
ProjectRootDir = "."
// InputDirName : inputfile directory
InputDirName = "./files"
// OutputDirName : outputfile directory
OutputDirName = "./csv"
// CwPath : chadwick path
CwPath = "/usr/local/bin"
// CwEvent : cwevent command
CwEvent = "%s/cwevent -q -n -f 0-96 -x 0-62 -y %d ./%d*.EV* > %s/events-%d.csv"
// CwGame : cwgame command
CwGame = "%s/cwgame -q -n -f 0-83 -y %d ./%d*.EV* > %s/games-%d.csv"
)
// ParseCsv a parse to eventfile(output:csv file)
func ParseCsv(command string, rootDir string, inputDir string) {
os.Chdir(inputDir)
out, err := exec.Command("sh", "-c", command).Output()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(string(out))
os.Chdir(rootDir)
}
func main() {
// Commandline Options
var fromYear = flag.Int("f", 2010, "Season Year(From)")
var toYear = flag.Int("t", 2014, "Season Year(To)")
flag.Parse()
// path
rootDir, _ := filepath.Abs(ProjectRootDir)
inputDir, _ := filepath.Abs(InputDirName)
outputDir := OutputDirName
wait := new(sync.WaitGroup)
// Generate URL
commandList := []string{}
for year := *fromYear; year < *toYear+1; year++ {
commandList = append(commandList, fmt.Sprintf(CwEvent, CwPath, year, year, outputDir, year))
wait.Add(1)
commandList = append(commandList, fmt.Sprintf(CwGame, CwPath, year, year, outputDir, year))
wait.Add(1)
}
for _, command := range commandList {
fmt.Println(command)
go func(command string) {
ParseCsv(command, rootDir, inputDir)
wait.Done()
}(command)
}
wait.Wait()
}
Jetzt, da ich einen Datensatz (CSV) nach Belieben erstellen kann, hat es meiner Meinung nach funktioniert.
Es gibt Raum für Verbesserungen in Design und Konfiguration, aber ich bin der Meinung, dass es klarer geschrieben werden kann als die Python-Version.
Der Editor verwendete übrigens das Go-Plug-In von IntelliJ IDEA.
Ich habe es benutzt, weil ich dafür bezahlt habe, einschließlich PyCharm, also dachte ich, ich würde es verbrauchen, aber es ist gut. Go wird weiterhin mit IntelliJ arbeiten.
Außerdem hatte ich das Gefühl, dass ich gerade v0.1 veröffentlicht hatte, also hörte ich auf, in LT zu springen (enttäuschend)
Ich werde eine Implementierung durchführen, die den Datensatz in MySQL überträgt.
Danach habe ich es mit der Python-Version auf der Bank verglichen, und da ich Go on Docker noch nie verwendet habe, werde ich es mit dieser Bibliothek studieren.
Recommended Posts