In Earth Engine gibt es mehrere Methoden zur Durchführung einer linearen Regression mit Reduzierern:
ee.Reducer.linearFit()
ee.Reducer.linearRegression()
ee.Reducer.robustLinearRegression()
ee.Reducer.ridgeRegression()
Die einfachste Methode zur linearen Regression ist linearFit()
, mit der die Schätzung der kleinsten Quadrate einer linearen Funktion einer Variablen mit einem konstanten Term berechnet wird. Für einen flexibleren Ansatz bei der linearen Modellierung können Sie einen der linearen Regressions-Reduzierungsmethoden verwenden, die eine variable Anzahl unabhängiger und abhängiger Variablen zulassen. linearRegression()
implementiert die Methode der gewöhnlichen kleinsten Quadrate(OLS). Bei robustLinearRegression()
wird eine Kostenfunktion basierend auf Regressionsresten verwendet, um Außreißer in den Daten iterativ zu entgewichten (O’Leary, 1990).
ridgeRegression()
führt eine lineare Regression mit L2-Regularisierung durch.
Die Regressionsanalyse mit diesen Methoden eignet sich zum Reduzieren von ee.ImageCollection
-, ee.Image
-, ee.FeatureCollection
- und ee.List
-Objekten.
Die folgenden Beispiele veranschaulichen jeweils eine Anwendung. linearRegression()
, robustLinearRegression()
und ridgeRegression()
haben dieselbe Eingabe- und Ausgabestruktur. linearFit()
erwartet jedoch eine zweibändige Eingabe (X gefolgt von Y) und ridgeRegression()
hat einen zusätzlichen Parameter (lambda
, optional) und eine Ausgabe (pValue
).
ee.ImageCollection
linearFit()
Die Daten sollten als zweibandiges Eingabebild eingerichtet werden, wobei der erste Band die unabhängige Variable und der zweite Band die abhängige Variable ist. Das folgende Beispiel zeigt die Schätzung des linearen Trends der zukünftigen Niederschläge (nach 2006 in den NEX-DCP30-Daten), die mithilfe von Klimamodellen prognostiziert wurden. Die abhängige Variable ist die prognostizierte Niederschlagsmenge und die unabhängige Variable ist die Zeit, die vor dem Aufruf von linearFit()
hinzugefügt wird:
// This function adds a time band to the image. var createTimeBand = function(image) { // Scale milliseconds by a large constant to avoid very small slopes // in the linear regression output. return image.addBands(image.metadata('system:time_start').divide(1e18)); }; // Load the input image collection: projected climate data. var collection = ee.ImageCollection('NASA/NEX-DCP30_ENSEMBLE_STATS') .filter(ee.Filter.eq('scenario', 'rcp85')) .filterDate(ee.Date('2006-01-01'), ee.Date('2050-01-01')) // Map the time band function over the collection. .map(createTimeBand); // Reduce the collection with the linear fit reducer. // Independent variable are followed by dependent variables. var linearFit = collection.select(['system:time_start', 'pr_mean']) .reduce(ee.Reducer.linearFit()); // Display the results. Map.setCenter(-100.11, 40.38, 5); Map.addLayer(linearFit, {min: 0, max: [-0.9, 8e-5, 1], bands: ['scale', 'offset', 'scale']}, 'fit');
Die Ausgabe enthält zwei Bereiche: „offset“ (Achsenabschnitt) und „scale“ (Maßstab). „Scale“ bezieht sich in diesem Zusammenhang auf die Steigung der Linie und darf nicht mit dem Skalierungsparameter verwechselt werden, der für viele Reducer verwendet wird und der räumlichen Maßstab darstellt. Das Ergebnis sollte in etwa so aussehen wie in Abbildung 1, wobei Bereiche mit steigendem Trend blau, Bereiche mit fallendem Trend rot und Bereiche ohne Trend grün dargestellt werden.
Abbildung 1. Die Ausgabe von linearFit()
, die auf projizierte Niederschläge angewendet wird. Gebiete mit voraussichtlich mehr Niederschlag sind blau und Gebiete mit voraussichtlich weniger Niederschlag rot dargestellt.
linearRegression()
Angenommen, es gibt zwei abhängige Variablen: Niederschlag und maximale Temperatur, sowie zwei unabhängige Variablen: eine Konstante und die Zeit. Die Sammlung ist mit dem vorherigen Beispiel identisch, aber der konstante Bereich muss vor der Reduzierung manuell hinzugefügt werden. Die ersten beiden Bänder der Eingabe sind die unabhängigen Variablen „X“ und die nächsten beiden Bänder sind die abhängigen Variablen „Y“. In diesem Beispiel werden zuerst die Regressionskoeffizienten abgerufen und dann das Array-Bild abgeflacht, um die gewünschten Bänder zu extrahieren:
// This function adds a time band to the image. var createTimeBand = function(image) { // Scale milliseconds by a large constant. return image.addBands(image.metadata('system:time_start').divide(1e18)); }; // This function adds a constant band to the image. var createConstantBand = function(image) { return ee.Image(1).addBands(image); }; // Load the input image collection: projected climate data. var collection = ee.ImageCollection('NASA/NEX-DCP30_ENSEMBLE_STATS') .filterDate(ee.Date('2006-01-01'), ee.Date('2099-01-01')) .filter(ee.Filter.eq('scenario', 'rcp85')) // Map the functions over the collection, to get constant and time bands. .map(createTimeBand) .map(createConstantBand) // Select the predictors and the responses. .select(['constant', 'system:time_start', 'pr_mean', 'tasmax_mean']); // Compute ordinary least squares regression coefficients. var linearRegression = collection.reduce( ee.Reducer.linearRegression({ numX: 2, numY: 2 })); // Compute robust linear regression coefficients. var robustLinearRegression = collection.reduce( ee.Reducer.robustLinearRegression({ numX: 2, numY: 2 })); // The results are array images that must be flattened for display. // These lists label the information along each axis of the arrays. var bandNames = [['constant', 'time'], // 0-axis variation. ['precip', 'temp']]; // 1-axis variation. // Flatten the array images to get multi-band images according to the labels. var lrImage = linearRegression.select(['coefficients']).arrayFlatten(bandNames); var rlrImage = robustLinearRegression.select(['coefficients']).arrayFlatten(bandNames); // Display the OLS results. Map.setCenter(-100.11, 40.38, 5); Map.addLayer(lrImage, {min: 0, max: [-0.9, 8e-5, 1], bands: ['time_precip', 'constant_precip', 'time_precip']}, 'OLS'); // Compare the results at a specific point: print('OLS estimates:', lrImage.reduceRegion({ reducer: ee.Reducer.first(), geometry: ee.Geometry.Point([-96.0, 41.0]), scale: 1000 })); print('Robust estimates:', rlrImage.reduceRegion({ reducer: ee.Reducer.first(), geometry: ee.Geometry.Point([-96.0, 41.0]), scale: 1000 }));
Die Ergebnisse zeigen, dass die Ausgabe von linearRegression()
den mit der linearFit()
-Reduktionsmethode geschätzten Koeffizienten entspricht. Die Ausgabe von linearRegression()
enthält jedoch auch Koeffizienten für die andere abhängige Variable tasmax_mean
. Die robusten Koeffizienten der linearen Regression unterscheiden sich von den OLS-Schätzungen. Im Beispiel werden die Koeffizienten der verschiedenen Regressionsmethoden zu einem bestimmten Punkt verglichen.
ee.Image
Im Kontext eines ee.Image
-Objekts können Regressionsminderer mit reduceRegion
oder reduceRegions
verwendet werden, um eine lineare Regression für die Pixel in den Regionen durchzuführen. In den folgenden Beispielen wird gezeigt, wie Regressionskoeffizienten zwischen Landsat-Bändern in einem beliebigen Polygon berechnet werden.
linearFit()
Im Abschnitt des Leitfadens zu Array-Datendiagrammen ist ein Streudiagramm der Korrelation zwischen den Landsat 8-SWIR1- und SWIR2-Bändern zu sehen. Hier werden die linearen Regressionskoeffizienten für diese Beziehung berechnet. Es wird ein Wörterbuch mit den Eigenschaften 'offset'
(y-Achsenabschnitt) und 'scale'
(Steigung) zurückgegeben.
// Define a rectangle geometry around San Francisco. var sanFrancisco = ee.Geometry.Rectangle([-122.45, 37.74, -122.4, 37.8]); // Import a Landsat 8 TOA image for this region. var img = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318'); // Subset the SWIR1 and SWIR2 bands. In the regression reducer, independent // variables come first followed by the dependent variables. In this case, // B5 (SWIR1) is the independent variable and B6 (SWIR2) is the dependent // variable. var imgRegress = img.select(['B5', 'B6']); // Calculate regression coefficients for the set of pixels intersecting the // above defined region using reduceRegion with ee.Reducer.linearFit(). var linearFit = imgRegress.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: sanFrancisco, scale: 30, }); // Inspect the results. print('OLS estimates:', linearFit); print('y-intercept:', linearFit.get('offset')); print('Slope:', linearFit.get('scale'));
linearRegression()
Hier wird dieselbe Analyse wie im vorherigen Abschnitt für linearFit
angewendet, nur dass diesmal die Funktion ee.Reducer.linearRegression
verwendet wird. Ein Regressionsbild wird aus drei separaten Bildern erstellt: einem konstanten Bild und Bildern, die die SWIR1- und SWIR2-Bänder aus demselben Landsat 8-Bild darstellen. Sie können beliebige Bänder kombinieren, um ein Eingabebild für die Regionsreduzierung um ee.Reducer.linearRegression
zu erstellen. Sie müssen nicht zum selben Quellbild gehören.
// Define a rectangle geometry around San Francisco. var sanFrancisco = ee.Geometry.Rectangle([-122.45, 37.74, -122.4, 37.8]); // Import a Landsat 8 TOA image for this region. var img = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044034_20140318'); // Create a new image that is the concatenation of three images: a constant, // the SWIR1 band, and the SWIR2 band. var constant = ee.Image(1); var xVar = img.select('B5'); var yVar = img.select('B6'); var imgRegress = ee.Image.cat(constant, xVar, yVar); // Calculate regression coefficients for the set of pixels intersecting the // above defined region using reduceRegion. The numX parameter is set as 2 // because the constant and the SWIR1 bands are independent variables and they // are the first two bands in the stack; numY is set as 1 because there is only // one dependent variable (SWIR2) and it follows as band three in the stack. var linearRegression = imgRegress.reduceRegion({ reducer: ee.Reducer.linearRegression({ numX: 2, numY: 1 }), geometry: sanFrancisco, scale: 30, }); // Convert the coefficients array to a list. var coefList = ee.Array(linearRegression.get('coefficients')).toList(); // Extract the y-intercept and slope. var b0 = ee.List(coefList.get(0)).get(0); // y-intercept var b1 = ee.List(coefList.get(1)).get(0); // slope // Extract the residuals. var residuals = ee.Array(linearRegression.get('residuals')).toList().get(0); // Inspect the results. print('OLS estimates', linearRegression); print('y-intercept:', b0); print('Slope:', b1); print('Residuals:', residuals);
Es wird ein Wörterbuch mit den Eigenschaften 'coefficients'
und 'residuals'
zurückgegeben. Das Attribut 'coefficients'
ist ein Array mit den Dimensionen (numX, numY). Jede Spalte enthält die Koeffizienten für die entsprechende abhängige Variable. In diesem Fall hat das Array zwei Zeilen und eine Spalte. Zeile 1, Spalte 1 ist der y-Achsenabschnitt und Zeile 2, Spalte 1 ist die Steigung. Die Property 'residuals'
ist der Vektor der Quadratwurzel der Residualsummenquadrate der Residuen jeder abhängigen Variablen. Extrahieren Sie die Koeffizienten, indem Sie das Ergebnis in ein Array umwandeln und dann die gewünschten Elemente herausschneiden oder das Array in eine Liste umwandeln und die Koeffizienten anhand der Indexposition auswählen.
ee.FeatureCollection
Angenommen, Sie möchten die lineare Beziehung zwischen der Reflexion von Sentinel-2 und Landsat 8 SWIR1 kennen. In diesem Beispiel wird eine zufällige Stichprobe von Pixeln, die als Punkt-Feature-Collection formatiert ist, verwendet, um die Beziehung zu berechnen. Es wird ein Streudiagramm der Pixelpaare mit der besten Anpassungslinie der kleinsten Quadrate generiert (Abbildung 2).
// Import a Sentinel-2 TOA image. var s2ImgSwir1 = ee.Image('COPERNICUS/S2/20191022T185429_20191022T185427_T10SEH'); // Import a Landsat 8 TOA image from 12 days earlier than the S2 image. var l8ImgSwir1 = ee.Image('LANDSAT/LC08/C02/T1_TOA/LC08_044033_20191010'); // Get the intersection between the two images - the area of interest (aoi). var aoi = s2ImgSwir1.geometry().intersection(l8ImgSwir1.geometry()); // Get a set of 1000 random points from within the aoi. A feature collection // is returned. var sample = ee.FeatureCollection.randomPoints({ region: aoi, points: 1000 }); // Combine the SWIR1 bands from each image into a single image. var swir1Bands = s2ImgSwir1.select('B11') .addBands(l8ImgSwir1.select('B6')) .rename(['s2_swir1', 'l8_swir1']); // Sample the SWIR1 bands using the sample point feature collection. var imgSamp = swir1Bands.sampleRegions({ collection: sample, scale: 30 }) // Add a constant property to each feature to be used as an independent variable. .map(function(feature) { return feature.set('constant', 1); }); // Compute linear regression coefficients. numX is 2 because // there are two independent variables: 'constant' and 's2_swir1'. numY is 1 // because there is a single dependent variable: 'l8_swir1'. Cast the resulting // object to an ee.Dictionary for easy access to the properties. var linearRegression = ee.Dictionary(imgSamp.reduceColumns({ reducer: ee.Reducer.linearRegression({ numX: 2, numY: 1 }), selectors: ['constant', 's2_swir1', 'l8_swir1'] })); // Convert the coefficients array to a list. var coefList = ee.Array(linearRegression.get('coefficients')).toList(); // Extract the y-intercept and slope. var yInt = ee.List(coefList.get(0)).get(0); // y-intercept var slope = ee.List(coefList.get(1)).get(0); // slope // Gather the SWIR1 values from the point sample into a list of lists. var props = ee.List(['s2_swir1', 'l8_swir1']); var regressionVarsList = ee.List(imgSamp.reduceColumns({ reducer: ee.Reducer.toList().repeat(props.size()), selectors: props }).get('list')); // Convert regression x and y variable lists to an array - used later as input // to ui.Chart.array.values for generating a scatter plot. var x = ee.Array(ee.List(regressionVarsList.get(0))); var y1 = ee.Array(ee.List(regressionVarsList.get(1))); // Apply the line function defined by the slope and y-intercept of the // regression to the x variable list to create an array that will represent // the regression line in the scatter plot. var y2 = ee.Array(ee.List(regressionVarsList.get(0)).map(function(x) { var y = ee.Number(x).multiply(slope).add(yInt); return y; })); // Concatenate the y variables (Landsat 8 SWIR1 and predicted y) into an array // for input to ui.Chart.array.values for plotting a scatter plot. var yArr = ee.Array.cat([y1, y2], 1); // Make a scatter plot of the two SWIR1 bands for the point sample and include // the least squares line of best fit through the data. print(ui.Chart.array.values({ array: yArr, axis: 0, xLabels: x}) .setChartType('ScatterChart') .setOptions({ legend: {position: 'none'}, hAxis: {'title': 'Sentinel-2 SWIR1'}, vAxis: {'title': 'Landsat 8 SWIR1'}, series: { 0: { pointSize: 0.2, dataOpacity: 0.5, }, 1: { pointSize: 0, lineWidth: 2, } } }) );
Abbildung 2. Streudiagramm und lineare Regressionslinie der kleinsten Quadrate für eine Stichprobe von Pixeln, die die TOA-Reflexion von Sentinel-2 und Landsat 8 SWIR1 repräsentieren.
ee.List
Spalten von zweidimensionalen ee.List
-Objekten können als Eingaben für Regressionsreduzierer verwendet werden. Die folgenden Beispiele liefern einfache Beweise: Die unabhängige Variable ist eine Kopie der abhängigen Variablen, die einen y-Achsenabschnitt von 0 und eine Steigung von 1 ergibt.
linearFit()
// Define a list of lists, where columns represent variables. The first column // is the independent variable and the second is the dependent variable. var listsVarColumns = ee.List([ [1, 1], [2, 2], [3, 3], [4, 4], [5, 5] ]); // Compute the least squares estimate of a linear function. Note that an // object is returned; cast it as an ee.Dictionary to make accessing the // coefficients easier. var linearFit = ee.Dictionary(listsVarColumns.reduce(ee.Reducer.linearFit())); // Inspect the result. print(linearFit); print('y-intercept:', linearFit.get('offset')); print('Slope:', linearFit.get('scale'));
Transponieren Sie die Liste, wenn Variablen durch Zeilen dargestellt werden. Konvertieren Sie sie dazu in eine ee.Array
, transponieren Sie sie und konvertieren Sie sie dann wieder in eine ee.List
.
// If variables in the list are arranged as rows, you'll need to transpose it. // Define a list of lists where rows represent variables. The first row is the // independent variable and the second is the dependent variable. var listsVarRows = ee.List([ [1, 2, 3, 4, 5], [1, 2, 3, 4, 5] ]); // Cast the ee.List as an ee.Array, transpose it, and cast back to ee.List. var listsVarColumns = ee.Array(listsVarRows).transpose().toList(); // Compute the least squares estimate of a linear function. Note that an // object is returned; cast it as an ee.Dictionary to make accessing the // coefficients easier. var linearFit = ee.Dictionary(listsVarColumns.reduce(ee.Reducer.linearFit())); // Inspect the result. print(linearFit); print('y-intercept:', linearFit.get('offset')); print('Slope:', linearFit.get('scale'));
linearRegression()
Die Anwendung von ee.Reducer.linearRegression()
ähnelt dem obigen Beispiel für linearFit(), mit der Ausnahme, dass eine konstante unabhängige Variable enthalten ist.
// Define a list of lists where columns represent variables. The first column // represents a constant term, the second an independent variable, and the third // a dependent variable. var listsVarColumns = ee.List([ [1, 1, 1], [1, 2, 2], [1, 3, 3], [1, 4, 4], [1, 5, 5] ]); // Compute ordinary least squares regression coefficients. numX is 2 because // there is one constant term and an additional independent variable. numY is 1 // because there is only a single dependent variable. Cast the resulting // object to an ee.Dictionary for easy access to the properties. var linearRegression = ee.Dictionary( listsVarColumns.reduce(ee.Reducer.linearRegression({ numX: 2, numY: 1 }))); // Convert the coefficients array to a list. var coefList = ee.Array(linearRegression.get('coefficients')).toList(); // Extract the y-intercept and slope. var b0 = ee.List(coefList.get(0)).get(0); // y-intercept var b1 = ee.List(coefList.get(1)).get(0); // slope // Extract the residuals. var residuals = ee.Array(linearRegression.get('residuals')).toList().get(0); // Inspect the results. print('OLS estimates', linearRegression); print('y-intercept:', b0); print('Slope:', b1); print('Residuals:', residuals);