工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

OpenSearchで、Vega-Liteを使ってPrecision、Recall、F1スコアを算出して表示する

概要

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. OpenSearch上のデータを使って表示させる

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
setosasetosasetosa
actualsetosa71210
virsicolor19010
virsinica23510
1013730

となるので、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の扱いに徐々に慣れてきたので、積極的に使用していきたい。