QGISのLLMプラグインでリュウグウのデータを解析してみた

## はじめに

大規模言語モデル（LLM）に指示を与えることで、これまで人間が行ってきた処理を代行させる仕組みを「**エージェント**」といいます。
代表的な製品・サービスとして、 Windows Copilot のように OS やオフィス製品に組み込んだものが知られており、LLM分野の技術進展にともなって普及が進んでいます。

GIS 分野で利用できる LLM エージェントとして、2024年11月に **[Spatial Analysis Agent](https://github.com/Teakinboyewa/SpatialAnalysisAgent)** という QGIS プラグインが登場しました。
このプラグインは、自然言語で出した指示をもとに LLM (GPT-4o など) が GIS データの処理フローを計画し、分析を行う、というものです。
これまで、GIS データの処理は専門家でないと難しい、という印象を持たれがちでしたが、こうしたツールは、より多くの人に GIS データ分析の門戸を開く可能性を秘めています。

この記事では、Spatial Analysis Agent を使った GIS データ解析の流れをご紹介します。

### データ選定

GIS データのほとんどは地球上の地理空間情報ですが、地球以外の天体でも「GIS データ」を作成・利用することが可能です。
当社では小惑星探査機「はやぶさ2」が撮影した小惑星リュウグウの画像データを CesiumJS で可視化し、その経緯を[2023年のFOSS4Gで発表](https://speakerdeck.com/nssv/foss4g-2023-japan-at-fukui-ta-tian-ti-niokerucesium-nohuo-yong-cesium-woshi-tutexiao-huo-xing-nixing-kou)しましたが、そこで使われた観測機器データも一種のGISデータと言えます。

今回は、こうした特殊なデータも Spatial Analysis Agent を使って解析できるかを探るため、はやぶさ2が収集した科学データの解析を試みました。
筆者は宇宙科学の専門家ではないので、分析方法も含めて LLM に聞きながら作業をしていくことになります。

はやぶさ2の観測データは [FITS 形式](https://ja.wikipedia.org/wiki/FITS) などのデータフォーマットで提供されています。
FITS 形式は宇宙工学分野では一般的なデータフォーマットのようですが、QGIS では直接読み込むことができません。
そこで、QGIS での読み込みに適したデータがないか調べたところ、[はやぶさ2ワークショップ2024](https://sites.google.com/view/hyb2ws/materials)で標準的なGISデータ形式に変換したものが試験公開されていたので、今回はこれを使うことにします。

ラスタデータは GeoTIFF 、ベクタデータは GeoPackage 形式で配布されており、QGIS にドラッグ＆ドロップするだけで読み込めます。

![QGIS でワークショップのデータを読み込んだところ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58671/61345d9c-f7a6-d2d2-2da0-cb893a7d6f21.png)


## はやぶさ2のデータを解析する

地球のGISデータならともかく、惑星探査データをどのように分析すればよいか、惑星科学者ではない筆者には見当もつきません。
そこで、次のような手順で分析作業を進めることにします。

1. ChatGPT と相談しながら、解析するデータの種類や分析手順を検討する
2. Spatial Analysis Agent を使って分析処理をしてもらう

### 解析方法の検討

まず、どのようなデータを分析するかを ChatGPT と相談しながら決めていきます[^chat-mode]。

[^chat-mode]: この記事では ChatGPT を使いましたが、Spatial Analysis Agent の "Chat mode" を使うと QGIS プラグイン内で普通の会話ができるため、解析方法の検討も QGIS 内で完結できるはずです。

はやぶさ2の大きな科学成果として真っ先に思い浮かぶのは「小惑星に水の痕跡を見つけた」というものです ([NHK](https://www3.nhk.or.jp/news/special/sci_cul/2019/03/news/news_190320/))。
地球上に存在する水や有機物は小惑星からもたらされたのではないか――という仮説を裏付ける重要な証拠として、大きな話題になりました。

今回、はやぶさ2の科学観測データが手元にあるわけですから、この発見の再現ができるはずです。
そこで、どの機器の観測データを使えば水の痕跡を確認できるのか、 ChatGPT に聞いてみました。

> ### ChatGPT の回答
>
> はやぶさ2が小惑星リュウグウの観測に使用した機器の中で、水の痕跡を発見するために特に重要な役割を果たしたのは、以下の機器です：
> 
> 1. **近赤外分光計 (Near-Infrared Spectrometer, NIRS3)**
>     - **用途**: リュウグウの表面で反射される赤外線を観測し、岩石の鉱物組成を調べる。
>     - **水の発見への貢献**:  
>         - 含水鉱物（OH基を含む鉱物）が存在する際に特徴的に吸収する赤外線の波長を捉える。
>         - 特定の波長（例: 2.7マイクロメートル付近）の赤外線吸収データを検出し、岩石内に取り込まれた水の存在を確認した。
>
> [...]
> 
> #### 推奨データの使用手順
> 1. **NIRS3データの確認**
>    - 吸収波長（2.7μmなど）で異常値が検出されている箇所を特定。
>    - そのデータを分析して含水鉱物が存在する可能性を評価。
>
> [...]

搭載機器のひとつ [NIRS3](https://www.isas.jaxa.jp/feature/hayabusa2/haya2_03.html) で計測した 2.7µm 付近の赤外線吸収率を調べることで、水の痕跡を見つけることができるようです。
さらに質問していくと、吸収強度の計算式も提示してくれました [^formula] 。

[^formula]: この式で果たして有益な分析ができるのか、正直なところ自信がないです。
調べたかぎり、[Kitazato et al. (2019)](https://www.science.org/doi/10.1126/science.aav7432) ではリュウグウの表面温度を推定して、温度が観測値に与える影響を除外する処理をしていますが、本記事ではそうした処理をせず、単純に2つの周波数における比を出しています。
論文中の画像 (Fig. 2) と本記事の結果画像を比較すると、ChatGPT 手法では表面温度の低い北半球で吸収強度が高く（色が薄く）なっていますが、論文中で示された正規化後の分布 (Fig. 2 D-F) によると、実際にはこうした差異は観察されていないようです。

> ```math
> \text{Absorption Depth} = 1 - \frac{\text{Reflectance at 2.7 µm}}{\text{Reflectance at Reference Wavelength}}
> ```
> 
> ここで、基準波長は吸収の影響を受けにくい波長を選択します（例：1.8 µm）。

### データ構造の把握

ここまでの ChatGPT との会話で「NIRS3 の観測データを使えば水の痕跡を確認できる」「そのためには 2.7µm と基準波長（1.8µm）の反射率の比をとる」という2つの情報を手に入れました。

一方、手元にある NIRS3 データの GeoTIFF ファイルには128バンド分の情報が入っていますが、どのバンドを使えばよいのか、という点は ChatGPT が教えてくれませんでした。
そこで、バンドと波長の対応情報は手探りで探ることにします。

幸いにも、[ISAS/JAXA のデータ公開 Web サイト](https://data.darts.isas.jaxa.jp/pub/pds4/data/hyb2/hyb2_nirs3/) で観測データに関する情報が公開されているので、今回はこのデータを参照します。
`collection_hyb2_nirs3_calibration.csv` というファイルを参照すると、1.8µm が 31ch, 2.7µm が 85ch 付近に対応していることがわかりました [^nirs3-dpsis] 。

[^nirs3-dpsis]: CSV ファイルの見かたは、[仕様定義書](https://data.darts.isas.jaxa.jp/pub/pds4/data/hyb2/hyb2_nirs3/document/hyb2_nirs3_dpsis.pdf) の "6.2.2. NIRS3 Calibration Data" に詳述されています。

### Spatial Analysis Agent で解析してみる

必要な情報が揃ったので、ここからは Spatial Analysis Agent を使って分析してみます。

まずは [README](https://github.com/Teakinboyewa/SpatialAnalysisAgent?tab=readme-ov-file#installation) に沿って、QGIS [^qgis-version] のプラグインマネージャ経由で "Spatial Analysis Agent" をインストールします。

[^qgis-version]: Python 3.11 以上が必須です。筆者環境（Windows 11）では、RC版の QGIS (3.40 "Bratislava", Python 3.12) ではプラグインが正しく動作した一方、LTS版 (3.34.13 "Prizren", Python 3.9) では動作しませんでした。

インストールすると、「プラグイン」メニューに "Autonomous GIS - Spatial Analysis Agent" が追加されます。

![menu_plugins_saa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58671/eced40a3-dc74-ada1-b367-c42a85c81603.png)


次に、分析したいデータをレイヤとして読み込みます。
LLM には表示されているレイヤの情報のみが渡され、非表示レイヤは解析対象にならないため、分析したいファイルだけを表示状態にします。

![hyb2_preflight.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58671/cde813b1-ff0e-3660-03f4-02750aa8e263.png)


プラグインウィンドウの "Write your request here..." と表示されている部分に、指示を記述します。

> `2018-07-11_ave_1.0d.tif` の31バンドに対する82バンドの吸収強度を計算してください

"Send Request" ボタンを押すと解析処理がはじまり、Python コードが書き出されていきます。
30秒くらい待つと結果が表示されました。

![実行結果（カラーランプ指定は手動）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58671/57c56a47-38c7-c702-6872-ba4f61764edd.png)


LLM が生成したコードを確認すると、QGIS の[ラスタ計算機能](https://docs.qgis.org/3.40/en/docs/user_manual/working_with_raster/raster_analysis.html#raster-calculator) を呼び出しているようです。
よく見ると、ChatGPT が提示した計算式とは異なっているのに気づきました。どうやら、31ch と 82ch の比を計算すべきところ、差分を計算してしまっているようです。

```python
# Define the raster calculation expression for absorption intensity (using band 31 subtracted by band 82)
expression = f'"InputRaster@31" - "InputRaster@82"'
```

計算式も含める形で再度指示を出し、分析をやり直させます。

> `2018-07-11_ave_1.0d.tif` の31バンドに対する82バンドの吸収強度（1-(82バンドの値)÷(31バンドの値)）を計算してください[^division-sign]

[^division-sign]: `/` 記号はパースに失敗するので `÷` 記号で代用しています。

再び30秒くらい待つと、結果が表示されました。

![リトライ後の分析結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58671/9322e198-9981-d165-96c2-08d0c8c843fe.png)


計算式も、教えたとおりに修正されています。

```python
# Define the expression for raster calculator
expression = f'1 - (\"Input Raster@82\" / \"Input Raster@31\")'
```

## Spatial Analysis Agent を使ってできること、できないこと

ここまで、Spatial Analysis Agent と ChatGPT を使いながら「はやぶさ2」のデータ解析を試みてきました。
上記のほかにもいくつかのタスクを実行した結果、このプラグインで"できること"と"できないこと"が見えてきたので、ご紹介したいと思います。

### できること

Spatial Analysis Agent の使いかたとして、下記2つのパターンがあるように感じました。

1. QGIS の機能を呼び出して解析作業を行う
    * QGIS の各機能には Python バインディングがありますが、LLM はこの API を経由してデータ処理を実行できます。  
    例えばラスタデータの場合、ラスタ計算ツールによる各種演算や等高線の作成などが可能です。
2. プラグインが存在しない作業を実装・実行する
    * Python の実行環境でできるタスクであれば、自動的にコードを書いて処理を実行してくれます。
    例えば主成分分析を行う QGIS プラグインは存在しないのですが、「このラスタ画像にPCAを適用してください。主成分の数は4つにすること」などと指示すると、`scikit-learn` などのライブラリを使ってコードを実装し、ファイルを書き出してくれます[^on-the-fly-export]。

[^on-the-fly-export]: ただし、実行してくれるのはファイルの書き出しまでで、レイヤの自動読み込みはしてくれないので、書き出されたファイルを QGIS にドラッグ＆ドロップして手動で再読み込みする必要があります。

### できないこと

もちろん、このプラグインに解析タスクをすべて丸投げできるわけではありません。
現時点で、下記のようなタスクは Spatial Analysis Agent が遂行できないため、人間が作業する必要があります。

1. データの取得や構造把握
    * Spatial Analysis Agent は「タスクを細分化」→「コードを実行」という2ステップでタスクを遂行しています。  
    このため、コードを実行してデータの内容を理解してから、次のステップを考える...ような探索的なアプローチはとれません。  
    また、インターネット上でデータを検索して自動で取ってくる、というのも現状ではできません。
2. LLMの手に余るような複雑なタスク
    * 1つのツールで完結するタスクは比較的得意ですが、たくさんのツールを組み合わせて分析するような複雑なタスクの場合、処理に失敗するケースが多くなります。  
    今回はバックエンドモデルとして GPT-4o を選択しましたが、ChatGPT 版の GPT-4o が失敗するレベルの難しいタスクは、このプラグインでも上手くいかない場合が多い印象を受けました。
3. 生成されたデータが合っているかどうかの検討
    * LLM が生成したコードが合っているとは限らず、今回の「はやぶさ2」データ解析でも意図したとおりにコードが生成されない例がみられました。  
      とくに科学研究など正確さが求められる業務では、専門知識をもった人間が処理内容を吟味することが重要だと思います。

### 機能と限界をふまえた活用方法

こうした限界点を踏まえつつ、LLM エージェントツールをどのように活用していけばよいでしょうか。

#### GIS に関する深い知識がない場合

QGIS は機能が豊富なぶん、初心者にとっては使いこなすのが難しい側面もあります。
しかし、こうしたプラグインの助けを借りれば、より簡単にQGISを使いこなせるようになるはずです。
特に、CS立体図や等高線の生成など、生成物が正しいかどうか一目でわかる場合、利活用がしやすいように思います。

#### QGIS に慣れているユーザの場合

QGIS に慣れているユーザの場合、本プラグインのような補助ツールに頼らなくても、各種ツールを自分で操作することで手早く作業を完結できることが多いと思います。
とはいえ、手間のかかる作業やツールとして存在しない処理を LLM プラグインに代行させられる、という利点はあるので、うまく使い分けることで作業効率を向上させることができると考えます。
バックエンドは GPT-4o なのだから ChatGPT を使えばよい、というのはその通りですが、QGIS を使う既存の作業フローを変えずに LLM を呼び出せるのは便利だと感じます。

## まとめ

今回は LLM を用いてコード生成する QGIS プラグインを使い、小惑星探査データの分析にチャレンジしました。
能力面の限界や課題はあるものの、うまく活用すればGISデータ活用者の拡大や、既存ユーザの作業効率化に役立ちそうです。

### 今後の技術発展の可能性

今回ご紹介した Spatial Analysis Agent は「GIS × LLM」の嚆矢というべきツールですが、今後の技術発展がどのように進むと考えられるか、方向性を探ってみたいと思います。

ツールを使ってみて、まず感じたのは「LLM がデータ取得や構造解析もできるようになればよいな」、という点です。
G空間情報センターや e-stat など、GIS データカタログの役割を果たすサービスはすでに存在しますが、これらの Web サイトからデータを検索・取得できるようになれば、オープンデータ利活用のチャンスがぐっと広がると思います。

LLM 自体の性能面では、o1 など推論能力を高めたモデルを用いることで、（API 利用料の増加と引き換えに）より高度な作業も行えるようになると期待できます。
逆に API コストの低減をめざすならば、バックエンドをローカル環境上のLLMサーバに差し替える、という方法が考えられます。

このほか、テキストと画像の両方を入力できるマルチモーダルモデルと組み合わせる、という方面での技術発展もあり得ます。
「この航空写真から太陽光パネルを抽出し、その総面積を求めてください」というような指示を実行できれば、幅広い応用が可能になるはずです。
画面上に表示されているデータを見て、結果の解釈もモデルがしてくれる...という将来が訪れるかもしれません。

今後も、GIS 分野における AI 技術の活用に注目していきたいと思います。