見出し画像

Google Earth Engineで期間検索をするときのend(期間末)の扱いについて


はじめに


こんにちは。

何度か取り上げているGoogle Earth Engineですが、サンプルコードを改めて読んでみて、検索期間を決める際のend(期間末)の指定の記述にブレがあったので、改めて検証してみました。
衛星観測は必ずしも毎日行われていませんし、雲量などで非抽出としてしまったりして、普段意識しづらいところですが、厳密に言ったら意外と大事だったりすると思います。

これまでもGoogle Earth Engineは紹介しているのでそちらの記事もご覧ください。

公式ドキュメントではどうなっているのか

Google Earth Engineの公式ドキュメントはどうなっているでしょうか?
一番使用頻度が高いと思われるee.ImageCollection.filterDateを読んでみましょう。

end(期間末)の説明ではThe end date (exclusive).とあります。他方検索期間のstartにはThe start date (inclusive).とあります。
inclusiveは含む、exclusiveは含まないの意味ですが、ちょっとわかりにくいですね。
サンプルコードを読んでみると次のようになっています。
filterDateの2つ目の引数と、その前のprint文をよく見てください。

# Filter the collection by date using date strings.
print('2020 images:', col.filterDate('2020', '2021').getInfo())
print('July images, 2020:', col.filterDate('2020-07', '2020-08').getInfo())
print('Early July images, 2020:',
      col.filterDate('2020-07-01', '2020-07-10').getInfo())

はじめの2つ、年のみ指定、年月指定 の2つでは、endで指定した年・月、つまり2021と2020-08は検索期間としては含んでいないことがprint文でわかります。
一方、Early July Images、2020日本語でいうと「7月上旬」ですが、そうなると7月1日~10日となって、endの日も含むことになってしまい、上記と矛盾します。日本語と英語のニュアンスの違いの可能性も高いですが、これはわかりにくい。
このサンプルコードでは、検索結果のリストを右側のConsoleで見られるので、回帰周期(1基なら10日おき、2基なら5日おき)から漏れがあるかどうかの判断はできますが、ちょっと面倒です。

※なおinclusiveとexclusiveについては、こんなページが有りました。契約では特に大事ですよね。

他のサンプルコードも読んでみる

場所検索と同じく期間検索はほぼ必ず行う処理なので、サンプルコードはそこかしこにでてくるのですが、どうも表現のブレが多いです。
例えば、Sentinel-2 MSI: MultiSpectral Instrument, Level-1Cの説明文(一部抜粋)。

// Map the function over one month of data and take the median.
// Load Sentinel-2 TOA reflectance data.
var dataset = ee.ImageCollection('COPERNICUS/S2')
                  .filterDate('2018-01-01', '2018-01-31')
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
                  .map(maskS2clouds);

多分2018年1月のデータを検索したいのだと思いますが、filterDateのendは'2018-01-31'と月末になっています。
このサンプル、期間のフィルターの直後に雲量でのフィルタリングを同時に行っており、実際、月末までの画像を対象に含めて検索したのか、していないのか、結果だけからはわからないので注意が必要です。

画像ではないですが、ベクトルデータ検索だとこういう書き方です。ee.Imageのドキュメントにあるサンプルコード(一部抜粋)ではこうなっています。

// Filter the observations in July 2021.
print('Field site observations collection in July 2021',
      fc.filter(ee.Filter.date('2021-07-01', '2021-08-01')));

こちらではendは'2018-08-01'になっています。次の月に送る指定になっています。ますますわかりにくい。
他にもいくつかサンプルコードを読んでみましたが、ほとんどのケースで、'2018-01-01', '2018-01-31'という書き方になっています。この方が感覚的には間違いない書き方だとは思いますが。
以下では、実際に自分で確かめてみようと思います。

コードを書いて確かめてみる

データはSentinel-2を対象にします。LANDSATだと観測頻度が16日と長く、サンプルが少なくなるためです。もっとも期間を微細に見ればいいので「関係ない」といえばないのですが。
場所は日本と、日本より東にある場所を選んでみます。
衛星の時間の基準としてはUTC(協定世界時)が使われます。日本の時間(JST)は+9時間になるわけですが、上空に衛星が飛来するのは現地の9-11時くらい(緯度による)なので、UTC時間でもその日のままなわけです。
上空に衛星が飛来する時間はどこでも同じですが、UTCからの時間差が有るので、もっと東になってしまうと、状況は変わります。
そこで、ニュージーランドの首都オークランド(UTC+12)、世界で最も早く1日の始まるキリバスのキリスィマスィ島(クリスマス島)(UTC+14)を選んでやってみます。

コードはこんな感じで書いてみました。

// 検索地点
var POI=ee.Geometry.Point(131.0815891,32.8824333);//阿蘇山
// 検索地点比較用(コメントアウト部分を都度付け替え)
// var POI=ee.Geometry.Point(174.748786,-36.8496721); //オークランド,ニュージーランド
// var POI=ee.Geometry.Point(-157.394358,1.882936); //キリスィマスィ島,キリバス 

// Sentinel-2画像をPOIの周りで検索
var Sentinel2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
.filterBounds(POI);

// さらに期間ごとに検索しリストをConsoleに表示する(画像は表示しない)
print('年指定', Sentinel2.filterDate('2021', '2022'));
print('年月指定, YYYY-MM', Sentinel2.filterDate('2021-05', '2021-06'));
print('年月日指定, YYYY-MM-DD', Sentinel2.filterDate('2021-05-01', '2021-06-01'));

// 検索期間の中で観測日時が最後のデータの観測日時を確認する
var Sentinel2LastDay=Sentinel2.filterDate('2021-05-01', '2021-06-01')
.sort('system:time_start',false)
.first();
print(Sentinel2LastDay);
print('観測日時',ee.Date(Sentinel2LastDay.get('system:time_start')));

POI(Point of Interest)のところは別々にしても良いのですが、コードが長くなるだけなので都度付け直します。
中心はprint('年指定')から下の3行になります。その後の部分は検索期間の中で観測日時が一番最後の1個だけデータを取り出して、その時間を見てみようというものです。

年指定での検索結果(部分)(endは2022)

ファイル名の先頭の文字でいつの撮影かがわかります。1/1から5日おきにデータがあるのかがわかります。多いので略してますが、年指定の最後の日は2021/12/27でした。以降は赤の5月分に注目してみます。

年月指定での検索結果(endは2021/6)

2021年5月のデータだけが、もれなくちゃんと選ばれてますね。

年月日指定での検索結果(endは2021/6/1)

結果は年月指定と同じです。

検索期間の中で観測日時が最後のデータの観測日時を確認

これは、最後の検索期間の中で観測日時が最後のデータの観測日時を確認したものですが、5/31になっていますね。観測時間はUTCなのでJSTだと11:08ということになります。

ではこれを次のように変えて実行してみます。コードは変えたところだけを表示しています。endの日付を5/31にしたわけですね。

print('年月日指定, YYYY-MM-DD', Sentinel2.filterDate('2021-05-01', '2021-05-31'));

// 検索期間の最終のデータのみ取り出す
var Sentinel2LastDay=Sentinel2.filterDate('2021-05-01', '2021-05-31')
年月日指定、最終日のみ指定での検索結果(endは2021/5/31)

データが1個ずつ減って、最終観測日時も5/26になっていることがわかります。気づかずにやっていたとしたら怖いですね。

// 観測日時が最後のデータを表示してみる
Map.centerObject(POI,9);
Map.addLayer(Sentinel2LastDay,{min:0,max:3000,bands:['B4','B3','B2']},'2021/5/31');

この2021/5/31は実はこんなきれいな画像の日だったわけです。
これを失うのは惜しいですよね。

2021/5/31の阿蘇を含むデータの画像

日付変更線近くの場所(ニュージーランドやキリバス)ではどうなのか?

最初のコードでコメントアウトしていた、ニュージーランドのオークランド(UTC+12)、キリバスのキリスィマスィ島(UTC+14)でも見てみます。
データ観測の都合上、オークランドの検索期間は2021年8月、キリスィマスィ島は7月とします。
検索期間はfilterDate('2021-08-01', '2021-09-01')、filterDate('2021-07
-01', '2021-08-01')、のようにします。

オークランドでの年月日指定、最終日のみ指定での検索結果(期間は2021/8/1から2021/9/1)

月末の観測日時は2021/8/31の22:26:18(UTC)なので、実は現地では9/1の10:26:18なわけですが、こういうこともありえます。こういう場所ではstartの日も気にしないといけません。

キリスィマスィ島での年月日指定、最終日のみ指定での検索結果(期間は2021/7/1から2021/8/1)

月末の観測日時は2021/7/31の21:04:54(UTC)なので、これも現地では8/1の11:04:54になります。多分、現地の方はこの辺のことは頭にある(Google Earth Engineを使うかどうかはわかりませんが・・・)ので問題ないと思いますが、我々は注意がいります。
こと光学衛星の観測時刻と時差問題については、日本はUTC+9時間という絶妙な場所にあるので影響を考えなくても済み、ラッキーでした(?)。
なおここで説明はしていませんが、12/31を検索に含む場合は当然翌年の1/1を指定する必要があります。

観測時間も指定して検索してみる

あまり行うことはないと思いますが(実際、筆者は一度もない)、観測時間も指定して検索してみます。場所は阿蘇に戻します。
同じものが3つ並んでいるようですが、endを22秒から1秒ずつ変えています。
先の阿蘇の結果では2021/5/31 02:08:23(UTC)(11:08:23 JST)ですが、実際の時間はミリ秒単位であり。正確には02:08:23+22ミリ秒のためです。
ここでミリ秒はいわゆるUNIX時間です。

print('年月日時刻指定22',Sentinel2.filterDate('2021-05-31T00:00:00', '2021-05-31T02:08:22'));
print('年月日時刻指定23',Sentinel2.filterDate('2021-05-31T00:00:00', '2021-05-31T02:08:23'));
print('年月日時刻指定24',Sentinel2.filterDate('2021-05-31T00:00:00', '2021-05-31T02:08:24'));
年月日時間指定での検索結果(endを1秒づつずらしたもの)

結果ですが、最後の24秒にしたときだけ検索結果に引っかかっています。23秒ではまだシステム的には観測してないことになるわけですね。
実際は衛星は北から南に連続して動いているのでピンポイントで「観測してない」とは言いづらいのですが。

まとめ

今回はGoogle Earth Engineの利用で頻出の期間検索を行う際のendの指定について掘り下げてみました。
endの年月日は含まないというのは、経験的に知ってはいたものの、ここまで細かく見たことはなかったので、興味深い結果になりました。特に日付変更線に近いあたりで。
光学衛星を利用する場合は、画像検索は雲量検索とセットなわけですが、Google Earth Engineの特徴としてデータを群として扱えるということが有るので、ちょっと問題ですね。

英語ドキュメントそのものの記載がぶれているので、関連紹介ページも記載がぶれているようです。
サービス内容的に欧米(のUTC帯)だけでなく、全世界にユーザーが居るはずなので、ドキュメントだけでも何とかして欲しいところなのですが、全然直す気配がないので、もうそのままなのかもしれません。

最後に

ここまでご覧いただき、ありがとうございました。

普段は北海道に本拠地を置くNPOに所属し、環境保全を主な題材としてGISやリモセンに関する仕事をしています。

コンサベーションGISコンソーシアムジャパン の活動もその1つです。
ご相談、ご質問、お仕事のご依頼などがございましたら、コンサベーションGISコンソーシアムジャパンWEBサイト掲載のメールアドレスまでメールをお寄せください。

コンサベーションGISコンソーシアムジャパンの活動及びこのnoteでの活動はボランティアで行っているのですが、何分資金が不足しています。
もしサポートしてもいいなという方がいらっしゃいましたら、そちらもよろしくお願いします。

noteの中の人は都内に居るので、お仕事などお声がけいただければと思います。

この記事が気に入ったらサポートをしてみませんか?