【问题标题】:Double loop with map() function in Google Earth EngineGoogle 地球引擎中带有 map() 函数的双循环
【发布时间】:2017-12-03 02:14:32
【问题描述】:

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() 函数复制这样的双循环以达到服务器端方法?

【问题讨论】:

    标签: javascript loops dictionary for-loop google-earth-engine


    【解决方案1】:

    执行此操作的简单方法是在您关心的“几个月”内使用一张地图。

    // 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,因为它已经过优化。

    【讨论】:

    • 太好了……我去看看!
    【解决方案2】:

    假设你只是想了解 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。首先,逐项查看years 列表,然后逐项查看months 列表,然后,一旦有了年份和月份,过滤集合并将其添加到列表中(map 会自动执行此操作)。当您使用 2 个 map 函数时(一个超过几年,另一个超过几个月),您将获得一个列表列表,因此要获得一个 ImageCollection 列表,请使用 flatten() 函数。不知怎的,打印出来的物体有点不同,但我相信结果是一样的。

    【讨论】:

    • 优秀的答案!非常感谢你
    【解决方案3】:

    首先让我说我对 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 列表(使用字典)),但要点是相同的。

    【讨论】:

    • 谢谢,但是 GEE 的代码格式不同。目前不允许const
    • 哦,没问题,我编辑了答案以改用var
    猜你喜欢
    • 2022-10-21
    • 1970-01-01
    • 2017-10-07
    • 2019-09-28
    • 2017-06-18
    • 2019-05-21
    • 2018-08-24
    • 2018-10-17
    • 1970-01-01
    相关资源
    最近更新 更多