2

Google Earth Engine Developer's Guide中,有一个避免for()循环的建议。他们建议使用map()函数作为这个例子:

// to avoid
var clientList = [];
for(var i = 0; i < 8; i++) {
  clientList.push(i + 1);
}
print(clientList);

// to use
var serverList = ee.List.sequence(0, 7);
serverList = serverList.map(function(n) {
  return ee.Number(n).add(1);
});
print(serverList);

我试图在计算 VCI 之前从每个月/年中选择 MODIS 场景。所以,我采取的方法是双循环:

modis = ee.ImageCollection("MODIS/MYD13A1");

var modis_list = [];
for(var i = 1; i <13; i++) {
  for(var j = 2000; j <2018; j++){
    modis_list.push(modis.filter(ee.Filter.calendarRange(i, i, 'month'))
                          .filter(ee.Filter.calendarRange(j, j, 'year')));
  }
}
print(modis_list);

有没有一种方法可以复制这样的双循环,并map()具有达到服务器端方法的功能?

4

3 回答 3

8

做到这一点的简单方法是在您关心的“几个月”内使用一张地图。

// Collect images for each month, starting from 2000-01-01.
var months = ee.List.sequence(0, 18*12).map(function(n) {
  var start = ee.Date('2000-01-01').advance(n, 'month')
  var end = start.advance(1, 'month')
  return ee.ImageCollection("MODIS/MYD13A1").filterDate(start, end)
})
print(months.get(95))

这将返回一个 ImageCollections 列表。大多数月份只有 1 张图像,因为 MYD13A1 包含 16 天的图像,但有些月份会有两张。第 95 个月是 2008 年 1 月,有两个。

或者,您可以使用日期集合加入集合,但这更简单。

如果可能,您应该更喜欢 filterDate 而不是 calendarRange,因为它已经过优化。

于 2017-12-02T18:14:32.110 回答
5

假设您只是想了解 GEE 的map()功能,以及如何等同于普通 js for loop,代码将是:

var map_m = function(i) {
  i = ee.Number(i)
  var years = ee.List.sequence(2000, 2017)
  var filtered_col = years.map(function(j) {
    var filtered = modis.filter(ee.Filter.calendarRange(i, i, 'month'))
                        .filter(ee.Filter.calendarRange(j, j, 'year'))
    return filtered
  })
  return filtered_col
}

var months = ee.List.sequence(1, 12)
var modis_list2 = months.map(map_m).flatten()

此代码复制了一个正常的for loop. 首先,逐项逐项逐年逐项处理,然后逐项逐项逐项处理月份列表然后,一旦有了年份和月份,过滤集合并将其添加到列表中(自动执行此操作)。当您使用 2 个函数(一个超过几年,另一个超过几个月)时,您会获得一个列表列表,因此要获得一个使用该函数的列表。不知何故,打印的对象有点不同,但我相信结果是一样的。mapmapImageCollectionflatten()

于 2017-11-04T04:24:51.057 回答
0

首先让我说我对 Google 地球引擎一无所知,我的信息来自函数式编程知识。


map它的独特之处在于它不会生成它循环的东西。您从一个列表开始,map遍历该列表中的每个项目并对其进行转换。如果您没有该列表,则地图不是一个很好的选择。

看起来您正在创建一个包含每个月/年组合的列表。我会把它分成几个步骤。构建月份和年份列表,构建表示 2 个列表的笛卡尔积的列表,然后转换为ee对象。

var range = (from, to) => new Array(end-start+1).fill(0).map((_,i)=>i+from)
var cartesianProduct = (a, b) => // not gonna do this here but it returns pairs [ [ a[1], b[1] ], ... ]
var getEE = ([month, year]) => modis
    .filter(ee.Filter.calendarRange(month, month, 'month'))
    .filter(ee.Filter.calendarRange(year, year, 'year'));

var months = range(1,12);
var years = range(2000, 2017);
var data = cartesianProduct(months, years)
    .map(getEE)

modis可能有更好的方法(比如每次我们想要一个单月对象时不遍历整个列表(使用字典)),但要点是相同的。

于 2017-11-03T19:36:52.340 回答