LoginSignup
29
4

More than 1 year has passed since last update.

GoでデータフレームパッケージのOSSを作ってみた話

Last updated at Posted at 2022-11-30

はじめに

Goのデータフレームパッケージを作り、OSSとして公開しました。この記事では、このOSSをつくるまでの経緯と、今回作ったGobanの基本的な仕組みの解説をしていきます。

こんな人に読んでほしい

  • OSSを作ってみたいが、何をしたらいいのかわからない
  • Goを使ったデータフレームパッケージを探している
  • Gobanにコントリビュートをしてみたい

データフレームとはなにか

そもそも、データフレームについて聞いたことのない方も多いと思います。データフレームについては、以下の説明がわかりやすいです。

データフレームとは、スプレッドシートのような、行と列からなる二次元のデータ構造です。データフレームは、柔軟かつ直感的にデータを格納し操作できるため、現代のデータ分析において最も一般的なデータ構造です。

引用元:DataFrames – Databricksより筆者訳

この説明の通り、二次元の表を扱い、様々な集計処理を行うのがデータフレームライブラリの役割です。データフレームライブラリとしては、Pythonのpandasが有名で、データ分析や機械学習の世界で非常によく使われています。

開発の経緯

弊社HRBrainではタレントマネジメントシステムの一つのサービスとして、分析ダッシュボードを提供しています。その中で、ユーザーが任意のグラフを作成する機能を開発してきました。この機能を実装する上で、データフレームパッケージの必要性を認識し、このパッケージを自ら実装するにいたりました。

1.ドメイン知識の整理

グラフ作成機能を実装するにあたって、まず、必要なドメイン知識を整理しました。特に、記述統計やデータの視覚化に関する知識が必要だったので、それらの分野の学習をして、情報を集めました。ドメイン知識を整理していく中で、グラフ作成機能のうち、表の集計処理の部分を、データフレームパッケージを導入することで整理できることがわかりました。

また、RDBを使って集計を行うことも検討しました。しかし、動的なスキーマの表に対する集計なので、RDBの基本的な機能では対応できず、アプリケーションで集計を行うのが望ましいと判断しました。

2.既存のOSSの検討

データフレームパッケージが有用であるとわかったところで、既存のOSSの採用を検討しました。検討にあたって、「Go言語で扱えるデータフレーム厳選4つ」などを参考にしました。

既存のパッケージの採用を検討する上で、以下の点を調査しました

  • アクティブにメンテナンスされていること
  • グループ化の操作ができること

しかし、多くのデータフレームパッケージは、十分にメンテナンスされていないか、必要だったグループ化の操作に対応しておらず、検討から外れました。

唯一、Gotaの採用は最後まで検討しましたが、

  • 元の開発者が開発をやめてしまい、2021年11月以降リリースされていないこと1
  • 複数カラムでのソートのような、基本的なイシューが放置されていること2
  • interface{}を多用するなど、型定義が不適切な箇所があること3

といった理由から採用を見送りました。

データフレームの基本的な機能であれば、実装はそれほど難しくなく、チーム内に知識を蓄積できることや、会社としてコントロールできる範囲にソースをおけるメリットがあると判断し、自ら実装することにしました。

3.実装

Gotaのコードを読みつつ、pandasの仕様を参考に実装をしていきました。特に、実装の初期段階においては、Gotaと同じようにつくれば、最低限の実装ができる保証があったので、とても安心感がありました。一方で、開発を進めていく中で、Gotaの実装が不適切な部分を見つけ、それを改善する形でGoban独自の実装をしていきました。

Gobanのデータフレームの仕組み

今回実装したGobanは、主に2つのオブジェクトによって構成されています。

  • Series
    • 同じ型の要素のリスト
  • Dataframe
    • 同じ長さのSeriesのリスト

Seriesは、一種類の変数4の値のリストで、平均値や中央値、標準偏差といった基本的な統計量の計算ができます。5

Dataframeは、複数のSeriesのリストまとめて、表として取り扱えるようにしたものです。現状では、グループごとの集計などの操作に対応しています。

サンプルコード:フルーツ名ごとの平均価格

例えば、フルーツ名と価格の表があるときに、フルーツ名ごとの平均価格を求める処理を考えます。

図示すると、以下のようになります。

処理前

fruits prices
 apple 2
orange 3
orange 2

処理後

fruits prices
 apple 2
orange 2.5

これをGobanを使って求めるコードは以下のようになります。


	df := dataframe.DataFrame{
		Columns: []series.Series{
			{
				Name: "fruits",
				Elements: element.StringElements{
					{
						Value: "apple",
						IsNull: false,
					},
					{
						Value: "orange",
						IsNull: false,
					},
					{
						Value: "orange",
						IsNull: false,
					},
				},
			},
			{
				Name: "prices",
				Elements: element.NumericElements{
					{
						Value: 2,
						IsNull: false,
					},
					{
						Value: 3,
						IsNull: false,
					},
					{
						Value: 2,
						IsNull: false,
					},
				},
			},
		},
		RecordCount: 3,
	}
	groups, _ := df.GroupBy("fruits")
	newDf, _ := groups.Aggregate(dataframe.AggregationConditions{
		{
			ColumnName: "fruits",
			Method: series.None,
		},
		{
			ColumnName: "prices",
			Method: series.Mean,
		},
	})
	log.Printf("[DEBUG] newDf: %+v", newDf)

出力

[DEBUG] newDf: {Columns:[{Name:fruits Elements:[{Value:apple IsNull:false} {Value:orange IsNull:false}] AggregatedMethod:} {Name:prices Elements:[{Value:2 IsNull:false} {Value:2.5 IsNull:false}] AggregatedMethod:Mean}] RecordCount:2}

今後の開発

GobanをOSSとして公開したものの、まだ汎用的なデータフレームパッケージには程遠い状態です。多くの基本的なメソッドが未実装である上、データ構造としても大いに改善の余地があると思っています。

一方で、Goのデータフレームパッケージに対するニーズは、これからさらに高まっていくと考えています。アプリケーションが扱うデータが大きくなるにつれて、Pythonではなく、Goのようなパフォーマンスの優れた言語でデータを処理することが合理的になると思うからです。

コントリビューターの募集

基本的な機能が未実装だからこそ、ジュニアレベルからシニアレベルまで、多くの開発者の方にコントリビュートいただける余地があると考えています。少しでも興味のお持ちの方は、お気軽にイシューやプルリクエスト、ディスカッションへの投稿をいただければと思います。また、開発者向けのSlackワークスペースもありますので、興味のあるかたはご参加ください。

なお、Gobanをご利用される場合は、マイナーバージョンのリリース前であり、後方互換性の無い変更がありうる旨をご理解ください。

おわりに

このOSSをつくることで、記述統計やGoのデータ型についての知見を深めることができ、とても勉強になりました。
最後に、自由に開発させてもらった会社と、レビューとコントリビュートしてくださった同僚に感謝します。ありがとうございました。

参考

  1. Looking for contributors · Issue #78 · go-gota/gota

  2. Incorrect output when sorting on multiple columns using DataFrame.Arrange(). · Issue #61 · go-gota/gota

  3. https://github.com/go-gota/gota/blob/f70540952827cfc8abfa1257391fd33284300b24/dataframe/dataframe.go#L391

  4. ここでの”変数”はプログラミング言語における"変数"とは別の概念。詳細は、「統計用語と調査用語」などを参照。

  5. 2022年11月17日現在で、対応している統計量は、相加平均個数合計のみ。

29
4
0

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
29
4