简体   繁体   English

Google Earth Engine中具有map()函数的双循环

[英]Double loop with map() function in Google Earth Engine

In Google Earth Engine Developer's Guide , there is a recommendation to avoid for() loops. 在《 Google Earth Engine开发人员指南》中 ,建议避免使用for()循环。 They recommend to use map() function as this example: 他们建议使用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);

I'm trying to select MODIS scenes from each month/year prior to compute VCI. 我试图从每个月/每年选择MODIS场景,然后再计算VCI。 So, the approach I'd take is with a double loop: 因此,我采用的方法是使用双循环:

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);

Is there a way to replicate a double loop like this with map() function to reach a server-side approach? 有没有办法用map()函数复制这样的双循环以达到服务器端的目的?

Assuming that you are just trying to understand GEE's map() function, and how would be the equivalent of a normal js for loop , the code would be: 假设您只是想了解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()

This code replicates a normal for loop . 这段代码复制了普通的for loop First, it goes item by item of the years list , and then item by item of the months list , and then, once you have year and month, filter the collection and add it to a list ( map does that automatically). 首先,它按年列表的逐项排列 ,然后按月列表的逐项排列 ,然后,一旦有了年和月,就过滤集合并将其添加到列表中( map会自动执行此操作)。 As you use 2 map functions (one over years and the other over months), you get a list of lists, so to get a list of ImageCollection use the flatten() function. 当您使用2个map函数时(一个数年,另一个数月),您将获得一个列表列表,因此,要使用flatten()函数来获取ImageCollection的列表。 Somehow the printed objects are a bit different, but I am sure the result is the same. 某种程度上来说,打印对象有所不同,但是我确信结果是相同的。

The easy way to do this is with a single map over the "months" you care about. 实现此目的的简单方法是使用一张您关注的“月”上的地图。

// 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))

This will return a list of ImageCollections. 这将返回ImageCollections的列表。 Most months will have only 1 image, since MYD13A1 contains 16-day images, but some will have two. 由于MYD13A1包含16天的图像,因此大多数月份将只有1张图像,但有些月份将有2天。 Month 95 is Jan of 2008 and has two. 第95个月是2008年1月,有两个月。

Alternatively, you could join the collection with a collection of dates, but this is simpler. 或者,您可以将集合与日期集合一起加入,但这比较简单。

And you should prefer filterDate over calendarRange when possible, as it's optimized. 而且,由于它已经过优化,因此应尽可能选择filterDate而不是calendarRange。

Let me start by saying I know nothing about Google Earth Engine and my info is from functional programming knowledge. 首先,我说我对Google Earth Engine一无所知,而我的信息来自功能编程知识。


map is unique in that it doesn't generate the things it loops over. map的独特之处在于它不会生成循环的东西。 You start with a list and map iterates over each item in that list and transforms it. 您从列表开始,然后对列表中的每个项目进行map并进行转换。 If you don't have that list then map isn't a great fit. 如果您没有该列表,则地图不太适合。

It looks like you are creating a list with each month/year combo represented. 您似乎正在创建一个表示每个月/年组合的列表。 I would break this into a few steps. 我将其分为几个步骤。 Build the month and year lists, build the list that represents cartesian product of the 2 lists then transform to the ee objects. 构建月和年列表,构建代表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)

There are likely better ways(like not iterating throught the whole list of modis each time we want a single month object (use a dictionary)) but the gist is the same. 可能有更好的方法(例如,每次我们想要一个月的对象(使用字典)时,不遍历整个modis列表),但要旨是相同的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM