0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Golangのデータフレームライブラリでデータの結合処理

Posted at

Golangのデータフレームライブラリ QFrameを扱っています。

高速でメソッドチェーンができるのが気に入っているのですが、込み入ったことをしようとすると複雑なコードを書かなければならなくなり、割と大変でした。

この記事では2つのデータフレームの結合を行いたい場合のなんとかやってみたコードを書きました。

サンプルデータのtestpidとteststockを左結合したいです。
要するに、teststockに品名と型式の情報をtestpidから持ってきたいのです。

package main

import (
	"fmt"

	"github.com/tobgu/qframe"
)

var (
	testpid = qframe.New(map[string]interface{}{
		"品番": []string{"AAA-100", "AAA-200", "AAA-300", "BBB-100", "BBB-210"},
		"品名": []string{"製品1", "製品2", "製品3", "製品4", "製品5"},
		"型式": []string{"型式A", "型式B", "型式C", "型式D", "型式E"},
	})
	teststock = qframe.New(map[string]interface{}{
		"品番":   []string{"AAA-100", "AAA-200", "BBB-210"},
		"在庫数":  []float64{1, 2, 3},
		"在庫単価": []float64{100, 1000, 10000},
	})
)

type (
	// Parts : 品番マスタに登録されている
	// 品名と型式情報を品番で管理する
	Parts struct{ Name, Type string }
	// PartsMap : 一意な品番をキーにした品名と型式のマップ
	// PartsMap[品番] で品名と型式が返される。
	PartsMap map[string]Parts
)

// convertToNonPointerSlice : []*string -> []string
func convertToNonPointerSlice(ptrSlice []*string) []string {
	nonPtrSlice := make([]string, len(ptrSlice))
	for i, ptr := range ptrSlice {
		nonPtrSlice[i] = *ptr
	}
	return nonPtrSlice
}

func main() {
	// 品番をキーにしたのマップを作る
	pmap := make(PartsMap, testpid.Len())
	pids := testpid.MustStringView("品番")
	names := testpid.MustStringView("品名")
	types := testpid.MustStringView("型式")
	for i := 0; i < pids.Len(); i++ {
		// ItemAtが返すのはポインタであることに注意
		pid := pids.ItemAt(i)
		pmap[*pid] = Parts{*names.ItemAt(i), *types.ItemAt(i)}
	}

	// 品番に紐づいた品名、型式を追加
	ss := teststock.MustStringView("品番").Slice()
	// stockPidsの型が[]*stringであることに注意
	// Slice()はポインタのスライスを返す。
	stockPids := convertToNonPointerSlice(ss)
	// QFrameを作るためのmapを作成
	newData := map[string]interface{}{"品番": stockPids}

	// 品番をキーにしたマップから品名と型式を引く
	stockNames := make([]string, len(stockPids))
	stockTypes := make([]string, len(stockPids))
	// 品名と型式を在庫品番と同じ長さの配列に入れる
	for i, pid := range stockPids {
		stockNames[i] = pmap[pid].Name
		stockTypes[i] = pmap[pid].Type
	}
	// newDataへ品名, 型式のスライスを追加
	newData["品名"] = stockNames
	newData["型式"] = stockTypes
	// newDataへ在庫情報を追加
	for _, name := range []string{"在庫数", "在庫単価"} {
		f := teststock.MustFloatView(name)
		newData[name] = f.Slice()
	}
	qf := qframe.New(newData)
	fmt.Println(qf)
	/*
		品名(s) 品番(s) 在庫単価(f) 在庫数(f) 型式(s)
		--------- --------- --------------- ------------ ---------
		製品1   AAA-100             100            1   型式A
		製品2   AAA-200            1000            2   型式B
		製品5   BBB-210           10000            3   型式E

		Dims = 5 x 3
	*/
}

コードの流れは、

  1. 品番をキーにしたマップを作ります。
  2. 在庫データの品番だけを抜きます。
  3. 在庫データの品番に基づいた品名と型式を「品番をキーにしたマップ」から引きます。
  4. 在庫データの品番列と、品名、型式をmapにします。
  5. mapに在庫の数量と単価の列を加えます。
  6. mapからQFrameを作成します。

ただの左結合なのにmapを作ったり、しかもそのマップは一般化できなかったりと、扱いづらさを感じるのでした。

フォローになりますが、QFrameの簡単な操作自体は列ごとに型がきちんと決まっていて、軽量で扱いやすいことは間違いないです。

しかしながら、グループ化や結合といった処理は複雑になりがちなので、pandasを使いたい、と思いました。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?