概要
OpenSearchで、Vega-Liteを使ってPrecision、Recall、F1スコアを算出して表示できた。
背景と目的
先日、Vega-LiteでPrecision、Recall、F1スコアを算出して表示ができたので、OpenSearchのVegaタイプのVisualizeで同様に表示をしてみる。
詳細
0. 環境
1. サンプルデータでコーディング
ひとまず、以前Vega-LiteでコーディングしたものをそのままOpenSearchに書いてみる。データもその時と同じものをべた書き。
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"predicted": "1", "actual": "1"},
{"predicted": "1", "actual": "0"},
{"predicted": "0", "actual": "1"},
{"predicted": "1", "actual": "1"},
{"predicted": "1", "actual": "1"},
{"predicted": "0", "actual": "1"},
{"predicted": "1", "actual": "1"},
{"predicted": "1", "actual": "1"},
{"predicted": "0", "actual": "1"},
{"predicted": "1", "actual": "0"},
{"predicted": "0", "actual": "0"}
]
},
transform: [
{
"joinaggregate": [
{
"op": "count",
"as": "actual-count"
}
],
"groupby": ["actual"]
},
{
"joinaggregate": [
{
"op": "count",
"as": "predicted-count"
}
],
"groupby": ["predicted"]
},
{
"joinaggregate": [
{
"op": "count",
"as": "confusion-matrix"
}
],
"groupby": ["predicted", "actual"]
},
{
"calculate": "datum['confusion-matrix'] / datum['actual-count']",
"as": "recall"
},
{
"calculate": "datum['confusion-matrix'] / datum['predicted-count']",
"as": "precision"
},
{
"calculate": "2 / (1 / datum.recall + 1 / datum.precision)",
"as": "F1-score"
},
{
"filter": "datum.predicted == datum.actual"
}
],
"repeat": {"layer": ["recall", "precision", "F1-score"]},
"spec": {
"mark": "rect",
"encoding": {
"x": {
"field": "predicted",
"type": "nominal"
},
"y": {
"field": {"repeat": "layer"},
"type": "quantitative",
"title": "score"
},
"color": {"datum": {"repeat": "layer"}, "title": "性能指標"},
"xOffset": {"datum": {"repeat": "layer"}}
}
},
"config": {
"mark": {"invalid": null}
}
}
実績のあるコードなので、当然ちゃんと表示される。

2.1 使うデータ
以下のような疑似的な予測、正解のラベルがセットになった30アイテムが"iris-result"というindexに挿入されているものとする。
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "virsicolor", "actual": "setosa"},
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "virsinica", "actual": "setosa"},
{"predicted": "virsinica", "actual": "setosa"},
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "setosa", "actual": "setosa"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "setosa", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsicolor", "actual": "virsicolor"},
{"predicted": "virsinica", "actual": "virsinica"},
{"predicted": "virsinica", "actual": "virsinica"},
{"predicted": "setosa", "actual": "virsinica"},
{"predicted": "setosa", "actual": "virsinica"},
{"predicted": "virsinica", "actual": "virsinica"},
{"predicted": "virsinica", "actual": "virsinica"},
{"predicted": "virsicolor", "actual": "virsinica"},
{"predicted": "virsicolor", "actual": "virsinica"},
{"predicted": "virsicolor", "actual": "virsinica"},
{"predicted": "virsinica", "actual": "virsinica"}
混同行列は、
| predicted | 計 |
setosa | setosa | setosa |
actual | setosa | 7 | 1 | 2 | 10 |
virsicolor | 1 | 9 | 0 | 10 |
virsinica | 2 | 3 | 5 | 10 |
計 | 10 | 13 | 7 | 30 |
となるので、Precision、Recall、F1スコアの正解は、
|
setosa |
virsicolor |
virginica |
precision |
0.7 |
0.692307692307692 |
0.714285714285714 |
recall |
0.7 |
0.9 |
0.5 |
F1 |
0.7 |
0.782608695652174 |
0.588235294117647 |
である。
2.2 データ参照部分を少し変更
上記データを取り出すために変更したものが以下。data.format.propertyはクエリで何も集計しない場合hits.hitsから取り出す必要がある。また、encoding.xやyのfield参照先は、_source.フィールド名とする必要がある。
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json"
"title": "混同行列",
"data": {
"url": {
"index": "iris-result",
"body": {
"size": 30
}
},
"format": {"property": "hits.hits"}
},
"encoding": {
"y": {
"field": "_source.actual",
"type": "ordinal",
"title": "実データ"
},
"x": {
"field": "_source.predicted",
"type": "ordinal",
"title": "予測"
}
},
"layer": [
{
"mark": "rect",
"encoding": {
"color": {
"aggregate": "count",
"type": "quantitative",
"legend": false,
"scheme": "rainbow"
}
}
},
{
"mark": "text",
"encoding": {
"text": {
"aggregate": "count",
"type": "quantitative"
},
"color": {
"value": "black"
}
}
}
],
"config": {
"axis": {"grid": true, "tickBand": "extent"}
}
}
表示させた結果は以下。正しく表示できている。

まとめと今後の課題
OpenSearchで、Vega-Liteを使ってPrecision、Recall、F1スコアを算出して表示することができた。Vega-Liteの扱いに徐々に慣れてきたので、積極的に使用していきたい。