Расчет NDVI по регионам, месяцам и годам с помощью Google Earth Engine?

Я хочу рассчитать средний NDVI по регионам (уровень администратора 3, также называемый вореда), месяц и год. Итак, мой конечный результат будет выглядеть примерно так:

regions    year    month   NDVI   
---------------------------------
region_1     2010       1     0.5  
region_1     2010       2    -0.6  
region_1     2010       3     0.7  
region_1     2010       4    -0.3  
region_1     2010       5     0.4  
region_1     2010       6    -0.5  
region_1     2010       7     0.5  
region_1     2010       8    -0.7  
region_1     2010       9     0.8  
region_1     2010       10   -0.55  
region_1     2010       11   -0.3  
region_1     2010       12   -0.2  
region_2     2010       1     0.5  
region_2     2010       2    -0.6  
region_2     2010       3     0.7  
region_2     2010       4    -0.3  
region_2     2010       5     0.4  
region_2     2010       6    -0.5  
region_2     2010       7     0.5  
region_2     2010       8    -0.7  
region_2     2010       9     0.8  
region_2     2010       10   -0.55  
region_2     2010       11   -0.3  
region_2     2010       12   -0.2  
...          ...       ...    ...

Мой код в основном делает это для заранее определенного региона в var modisNDVI. Однако я хочу, чтобы мой код мог делать это с 2010 по 2015 год, за каждый месяц для каждого региона.

Как я могу сделать это, не написав больше циклов for (итерации по годам и месяцам)?

Должен ли я использовать reduceRegion или .map(), чтобы пропустить (все) циклы for?

Я попытался использовать reduceRegions, но не смог применить это к коллекции изображений.

// import data
var region = ee.FeatureCollection("ft:1zRUOJL1LYCPJj-mjP6ZRx8sxYKNH8EwDw3EPP66K"),
modisNDVI = ee.ImageCollection("MODIS/MCD43A4_006_NDVI");

// Get NDVI 
var modisNDVI = ee.ImageCollection(modisNDVI.filterDate('2015-01-01', '2015-06-01'));
var woredaNames = region.aggregate_array("HRpcode")

// do something so I can get monthly data for each year (2010-2015) for earch woreda (690)
// I don't want to write another for loop for the year and month what is a more optimized way?

// Processing all the 690 takes long, for this example I've used 10 woreda's
for (var woreda=0; woreda < 10 ;woreda++){

    // Focus on one region:
    var focusRegion = region.filter(ee.Filter.eq('system:index', String(woreda)));

    // Clip modis image on focused region:
    var focus_NDVI_clip = modisNDVI.mean().clip(focusRegion);

    // aggregate mean over geometry from focused region:
    var mean_dict = focus_NDVI_clip.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: focusRegion.geometry(),
    scale: 500,
    });

    // Append index to mean_dictionary and print it (eventually this should turn into a list):
    var woreda_code = ee.List(woredaNames).get(woreda);
    mean_dict = mean_dict.set('Woreda_code', ee.String(woreda_code));
    print(mean_dict);}

person Vindicare    schedule 13.11.2018    source источник
comment
Опубликовано как gis.stackexchange.com/q/301447/115   -  person PolyGeo    schedule 12.12.2018


Ответы (1)


Прежде всего, вам следует любой ценой избегать использования циклов for в Earth Engine, это только тормозит систему и не всем подходит (см. раздел Циклы на этом страница). Вы можете использовать вложенное сопоставление для циклического обхода функции. коллекция, а затем все периоды времени для извлечения необходимой информации:

// import data
var region = ee.FeatureCollection("ft:1zRUOJL1LYCPJj-mjP6ZRx8sxYKNH8EwDw3EPP66K"),
modisNDVI = ee.ImageCollection("MODIS/MCD43A4_006_NDVI");

var startDate = ee.Date('2010-01-01'); // set analysis start time
var endDate = ee.Date('2010-12-31'); // set analysis end time

// calculate the number of months to process
var nMonths = ee.Number(endDate.difference(startDate,'month')).round();

var result = region.map(function(feature){
  // map over each month
  var timeDict = ee.List.sequence(0,nMonths).map(function (n){
    // calculate the offset from startDate
    var ini = startDate.advance(n,'month');
    // advance just one month
    var end = ini.advance(1,'month');
    // filter and reduce
    var data = modisNDVI.filterDate(ini,end).mean().reduceRegion({
      reducer: ee.Reducer.mean(),
      geometry: feature.geometry(),
      scale: 1000
    });
    // return zonal mean with a time key
    return data.combine(ee.Dictionary({'time':ini}));
  });
  // return feature with a timeseries property and results
  return feature.set('timeseries',timeDict);
});

// print to see if it is doing what we expect...
print(result.select(["HRpcode",'timeseries']));

// Export the data to a table for further analysis
Export.table.toDrive({
  collection:result,
  description:"tester",
  fileFormat:"CSV",
  selectors:["HRpcode","timeseries"]
})

Ссылка на код: https://code.earthengine.google.com/abf5eeb5c203310c11bf45c6714ae731

Форматирование результатов может быть немного странным в этой реализации, в результате чего получается набор функций со словарями в качестве свойств, а не массив или таблица... но, надеюсь, это либо даст вам то, что вам нужно, либо даст вам средства для получения того, что вы необходимость.

person Kel Markert    schedule 05.12.2018
comment
Kel любые мысли о том, как преобразовать словарь в таблицу? - person mmann1123; 28.05.2019
comment
Да, посмотрите этот пример: code.earthengine.google.com/349615d7802d59f677181bef0badad9f. По сути, вместо того, чтобы возвращать словарь при сопоставлении периодов времени, вы просто получаете значения для каждого времени и создаете словарь с правильными датами и значениями, чтобы дать функцию. Надеюсь, это имеет смысл ... это дает временные ряды в виде столбцов, но вы, вероятно, можете просто перенести таблицу в свое любимое программное обеспечение для обработки таблиц, чтобы получить временные ряды в виде строк. - person Kel Markert; 31.05.2019