Earth Engine hỗ trợ các phép biến đổi mảng như chuyển đổi, nghịch đảo và giả nghịch đảo. Ví dụ: hãy xem xét một hồi quy bình phương tối thiểu thông thường (OLS) của một chuỗi thời gian hình ảnh. Trong ví dụ sau, một hình ảnh có các dải cho các giá trị dự đoán và một phản hồi được chuyển đổi thành hình ảnh mảng, sau đó được "giải" để lấy các giá trị ước tính hệ số bình phương nhỏ nhất theo ba cách. Trước tiên, hãy tập hợp dữ liệu hình ảnh và chuyển đổi thành mảng:
Trình soạn thảo mã (JavaScript)
// Scales and masks Landsat 8 surface reflectance images. function prepSrL8(image) { // Develop masks for unwanted pixels (fill, cloud, cloud shadow). var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0); var saturationMask = image.select('QA_RADSAT').eq(0); // Apply the scaling factors to the appropriate bands. var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2); var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0); // Replace the original bands with the scaled ones and apply the masks. return image.addBands(opticalBands, null, true) .addBands(thermalBands, null, true) .updateMask(qaMask) .updateMask(saturationMask); } // Load a Landsat 8 surface reflectance image collection. var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') // Filter to get only two years of data. .filterDate('2019-04-01', '2021-04-01') // Filter to get only imagery at a point of interest. .filterBounds(ee.Geometry.Point(-122.08709, 36.9732)) // Prepare images by mapping the prepSrL8 function over the collection. .map(prepSrL8) // Select NIR and red bands only. .select(['SR_B5', 'SR_B4']) // Sort the collection in chronological order. .sort('system:time_start', true); // This function computes the predictors and the response from the input. var makeVariables = function(image) { // Compute time of the image in fractional years relative to the Epoch. var year = ee.Image(image.date().difference(ee.Date('1970-01-01'), 'year')); // Compute the season in radians, one cycle per year. var season = year.multiply(2 * Math.PI); // Return an image of the predictors followed by the response. return image.select() .addBands(ee.Image(1)) // 0. constant .addBands(year.rename('t')) // 1. linear trend .addBands(season.sin().rename('sin')) // 2. seasonal .addBands(season.cos().rename('cos')) // 3. seasonal .addBands(image.normalizedDifference().rename('NDVI')) // 4. response .toFloat(); }; // Define the axes of variation in the collection array. var imageAxis = 0; var bandAxis = 1; // Convert the collection to an array. var array = collection.map(makeVariables).toArray(); // Check the length of the image axis (number of images). var arrayLength = array.arrayLength(imageAxis); // Update the mask to ensure that the number of images is greater than or // equal to the number of predictors (the linear model is solvable). array = array.updateMask(arrayLength.gt(4)); // Get slices of the array according to positions along the band axis. var predictors = array.arraySlice(bandAxis, 0, 4); var response = array.arraySlice(bandAxis, 4);
import ee import geemap.core as geemap
Colab (Python)
import math # Scales and masks Landsat 8 surface reflectance images. def prep_sr_l8(image): # Develop masks for unwanted pixels (fill, cloud, cloud shadow). qa_mask = image.select('QA_PIXEL').bitwiseAnd(int('11111', 2)).eq(0) saturation_mask = image.select('QA_RADSAT').eq(0) # Apply the scaling factors to the appropriate bands. optical_bands = image.select('SR_B.').multiply(0.0000275).add(-0.2) thermal_bands = image.select('ST_B.*').multiply(0.00341802).add(149.0) # Replace the original bands with the scaled ones and apply the masks. return ( image.addBands(optical_bands, None, True) .addBands(thermal_bands, None, True) .updateMask(qa_mask) .updateMask(saturation_mask) ) # Load a Landsat 8 surface reflectance image collection. collection = ( ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') # Filter to get only two years of data. .filterDate('2019-04-01', '2021-04-01') # Filter to get only imagery at a point of interest. .filterBounds(ee.Geometry.Point(-122.08709, 36.9732)) # Prepare images by mapping the prep_sr_l8 function over the collection. .map(prep_sr_l8) # Select NIR and red bands only. .select(['SR_B5', 'SR_B4']) # Sort the collection in chronological order. .sort('system:time_start', True) ) # This function computes the predictors and the response from the input. def make_variables(image): # Compute time of the image in fractional years relative to the Epoch. year = ee.Image(image.date().difference(ee.Date('1970-01-01'), 'year')) # Compute the season in radians, one cycle per year. season = year.multiply(2 * math.pi) # Return an image of the predictors followed by the response. return ( image.select() .addBands(ee.Image(1)) # 0. constant .addBands(year.rename('t')) # 1. linear trend .addBands(season.sin().rename('sin')) # 2. seasonal .addBands(season.cos().rename('cos')) # 3. seasonal .addBands(image.normalizedDifference().rename('NDVI')) # 4. response .toFloat() ) # Define the axes of variation in the collection array. image_axis = 0 band_axis = 1 # Convert the collection to an array. array = collection.map(make_variables).toArray() # Check the length of the image axis (number of images). array_length = array.arrayLength(image_axis) # Update the mask to ensure that the number of images is greater than or # equal to the number of predictors (the linear model is solvable). array = array.updateMask(array_length.gt(4)) # Get slices of the array according to positions along the band axis. predictors = array.arraySlice(band_axis, 0, 4) response = array.arraySlice(band_axis, 4)
Xin lưu ý rằng arraySlice()
trả về tất cả hình ảnh trong chuỗi thời gian cho phạm vi chỉ mục được chỉ định dọc theo bandAxis
(trục 1). Tại thời điểm này, bạn có thể sử dụng đại số ma trận để giải phương trình cho các hệ số OLS:
Trình soạn thảo mã (JavaScript)
// Compute coefficients the hard way. var coefficients1 = predictors.arrayTranspose().matrixMultiply(predictors) .matrixInverse().matrixMultiply(predictors.arrayTranspose()) .matrixMultiply(response);
import ee import geemap.core as geemap
Colab (Python)
# Compute coefficients the hard way. coefficients_1 = ( predictors.arrayTranspose() .matrixMultiply(predictors) .matrixInverse() .matrixMultiply(predictors.arrayTranspose()) .matrixMultiply(response) )
Mặc dù phương thức này hoạt động, nhưng không hiệu quả và khiến mã khó đọc. Bạn nên sử dụng phương thức pseudoInverse()
(matrixPseudoInverse()
cho hình ảnh mảng):
Trình soạn thảo mã (JavaScript)
// Compute coefficients the easy way. var coefficients2 = predictors.matrixPseudoInverse() .matrixMultiply(response);
import ee import geemap.core as geemap
Colab (Python)
# Compute coefficients the easy way. coefficients_2 = predictors.matrixPseudoInverse().matrixMultiply(response)
Từ góc độ dễ đọc và hiệu quả tính toán, cách tốt nhất để lấy hệ số OLS là solve()
(matrixSolve()
đối với hình ảnh mảng). Hàm solve()
xác định cách giải hệ thống tốt nhất từ các đặc điểm của dữ liệu đầu vào, sử dụng phép nghịch đảo giả cho các hệ thống quá xác định, phép nghịch đảo cho các ma trận vuông và các kỹ thuật đặc biệt cho các ma trận gần như đơn nhất:
Trình soạn thảo mã (JavaScript)
// Compute coefficients the easiest way. var coefficients3 = predictors.matrixSolve(response);
import ee import geemap.core as geemap
Colab (Python)
# Compute coefficients the easiest way. coefficients_3 = predictors.matrixSolve(response)
Để có hình ảnh nhiều băng tần, hãy chiếu hình ảnh mảng vào không gian có kích thước thấp hơn, sau đó làm phẳng hình ảnh đó:
Trình soạn thảo mã (JavaScript)
// Turn the results into a multi-band image. var coefficientsImage = coefficients3 // Get rid of the extra dimensions. .arrayProject([0]) .arrayFlatten([ ['constant', 'trend', 'sin', 'cos'] ]);
import ee import geemap.core as geemap
Colab (Python)
# Turn the results into a multi-band image. coefficients_image = ( coefficients_3 # Get rid of the extra dimensions. .arrayProject([0]).arrayFlatten([['constant', 'trend', 'sin', 'cos']]) )
Kiểm tra kết quả của ba phương thức và quan sát thấy rằng ma trận kết quả của các hệ số là giống nhau bất kể phương thức giải. solve()
linh hoạt và hiệu quả nên là lựa chọn phù hợp cho việc lập mô hình tuyến tính cho mục đích chung.