2018/06/04

文系のための「GEEのデータ型」

Google Earth Engine(GEE) を使いこなすためには知っておくべきことが色々とある。
特に重要なものがEEオブジェクトとよばれるものである。
これはGEEが提供する概念的なデータの分類である。

この概念的なデータの分類は分類名属性操作の三つから成り、
そういった概念的な分類のことをクラスと呼び、
クラスという概念に基づく設計思想をオブジェクト指向とよぶ。

GEEが用意しているオブジェクトのことをEEオブジェクトと呼ぶ。
Earth Engineの略で「EE」。オブジェクトの名前としては小文字で「ee」である。
とにかく、「ee.」で始まるオブジェクトは全てGEEのオブジェクトである。

Code Editorを使ってプログラミングを行う際にはJavascriptを扱うが、
データ型については、少々、癖があるので注意しなくてはならない。
忘れてはならないこととして、GEEはサーバー上で実行される点である。

すなわち、GEEの場合にはサーバー側で扱う部分と、
クライアント側で扱う部分が分かれていて、
簡単には変数等を引き継ぐことができないことがある。

これは一般的なデータ型についてもいえる。

Javascriptにおいてもデータ型は存在しているが、
サーバー上で処理する場合にはGEEのデータ型を指定する必要がある。
私も以前にこの問題で躓いたことがある…。

まずは、文字列の場合で考えてみる。

var clientString = '文字列の定義';
print('クライアント・サイド', clientString);

var serverString = ee.String(clientString);
print('サーバー・サイド', serverString);

まず、var clientString で一般的な文字列変数を宣言し、
その下の行ではクライアント側で文字列変数を出力している。
何の変哲もない普通のプログラミングの例。

一方、下の二行では、最初にクライアント側で定義した文字列変数を
GEEのサーバーに引き渡して、サーバー上の文字列変数に格納している。
ちなみに、以下のようにすることもできる。

var serverString = ee.String('文字列の定義');
print('サーバー・サイド', serverString);

多くの人は気付いたと思うが、ee.String()を使うと表示に若干のタイムラグが生じる。

print()という関数はクライアント上で実行されるため、
一度、サーバーに格納された変数の中身を評価し、
その結果がクライアントに戻されて表示されるために通信時間が発生する。

確かに、この方法だと処理に時間がかかってしまいそうにみえるが、
これは通信時間とデータ量とのバランスの問題である。
データ量が大きくなると、サーバー上で処理を行い結果だけを返す方が遥かに早い

同様に、数値型についても試してみる。

数値型の場合には様々な数的な処理が入ってくるため、少々、厄介な問題が発生する。
以下では、最初に数値型を宣言し、初期値として10を代入したのちに、
さらに、10を足すという計算である。

まずは、クライアント・サイドの例。

var clientNumber = 10;
var clientNumber = clientNumber + 10;
print('クライアント・サイド', clientNumber);

次に、EEオブジェクトとしてサーバー上で処理する例。

var serverNumber = ee.Number(10);
var serverNumber = serverNumber.add(10);
print('サーバー・サイド', serverNumber);

クライアント・サイドで実行させる場合には通常の方法で計算できるが、
サーバーサイドでは「add()」という操作を通してしか値を足すことができない。
このように、EEオブジェクトとしてサーバー上で処理するには若干の癖がある。

プログラミングでよく使う配列の場合も検討してみる。
通常の配列の場合には一般的な書き方と変わらないが、
配列の場合には組み込み関数も用意されている。

まずは、クライアント・サイドの例。

var clientList = [0,1,2,3,4,5,6,7,8,9];
var clientValue = clientList[3];
print('クライアント・サイド', clientValue);

次に、EEオブジェクトとしてサーバー上で処理する例。

var serverList = ee.List([0,1,2,3,4,5,6,7,8,9]);
var serverValue = clientList[3];
print('サーバー・サイド', serverValue);

さらに、組み込み関数の「ee.List.sequence()」を使った場合。

var serveSequence = ee.List.sequence(0,9);
var serverValue = serveSequence.get(3);
print('サーバー・サイド', serverValue);

最後の「sequence()」は連続する整数の配列を作るための関数であるが、
この関数を使って配列を作った場合には「.get()」で取り出す必要がある。
また、この例では数値の配列であったが、取り出した値を使うときには…

var serverValue = ee.Number(serverValue).add(3)

EEオブジェクトの数値型(ee.Number)に変換しなければならない。

配列によく似た辞書型の場合は以下の通り。
プログラミングに慣れている人にとっては大したことはないだろう。
キーと値の間は「:(コロン)」で、ペアを加える場合には「,(カンマ)」で続ける。

var serverDict = ee.Dictionary({
  key_1: ee.Number(10),
  key_2: ee.Number(20),
  key_3: ee.Number(30)
});

print('キー1:', serverDict.get('key_1'));
print('キー2:', serverDict.get('key_2'));
print('キー3:', serverDict.get('key_3'));

print('全てのキー: ', serverDict.keys());

print('全ての値: ', serverDict.values());

ちなみに、辞書型に代入されているキーと値を配列順で呼び出すには…。

var n = 1;

print('n番目のキー: ', serverDict.keys().get(n));
print('n番目の値: ', serverDict.values().get(n));

最後は日付型について。ひょっとすると、これは後に役立つかもしれない。
GEEの日付型は1970年1月1日が基準となっている。
まずは、日付型のデータをインスタンス化する例について。

var date = ee.Date('2015-12-31');

print('日付型:', date);

これはいたって普通。GEEの場合には基準日からのミリ秒で表すことがある。
したがって、そような場合にはミリ秒で表された日付の変換が必要になる。
その方法はいたって簡単。

var today = 1528106762599;
print(ee.Date(today))

退屈な話が続いたが、結構、重要な内容が含まれている。
特に、サーバー・サイドの挙動とクライアント・サイドの挙動の違いについては、
少し、頭に置いておいた方が良いかもしれない。

0 件のコメント:

コメントを投稿