GEE遥感利器:主成分分析(PCA)原理与实战,一键实现降维处理!

GEE遥感利器:主成分分析(PCA)原理与实战,一键实现降维处理!

主成分分析(PCA)是遥感影像处理的经典方法,通过降维去除冗余信息,提取关键特征。今天我们将深入探讨PCA的数学原理,并在GEE中实现这一强大工具。


一、主成分分析:从原理到本质

核心目标:将多波段数据转换为少数几个互不相关的综合波段(主成分),最大限度保留原始信息。

核心思想

  1. 数据线性变换,寻找新坐标轴(主成分方向)
  2. 第一主成分承载最大方差,后续成分依次递减
  3. 各主成分之间互不相关(协方差为0)

二、PCA数学推导:步步深入

步骤0:准备原始数据
var scale = 1000;
var roi = ee.Geometry.Polygon(
        [[[98.76874122458284, 27.476046782884104],
          [98.76874122458284, 26.36424630156598],
          [100.16400489645784, 26.36424630156598],
          [100.16400489645784, 27.476046782884104]]], null, false);
Map.centerObject(roi, 8);
var hAxis = {'title': 'NDVI','viewWindow': {min: -0.8, max: 0.8}};
var vAxis = {'title': 'EVI', 'viewWindow': {min: -0.5, max: 0.5}};
var imageCol =ee.ImageCollection('MODIS/061/MOD13A1')
                       .select(['NDVI', 'EVI'])
                       .filterBounds(roi)
                       .filterDate("2020-01-01","2020-12-31")
                      .map(function (image){
                        return image.addBands(image.divide(10000), null, true);
                      });
var image = imageCol.median();
var NDVI_EVI = image.reduceRegion({
  reducer: ee.Reducer.toList(), 
  geometry: roi, 
  scale: 1000
});
var n = 100;
var x_origin = ee.Array(NDVI_EVI.get('NDVI')).slice(0, 0, n);
var y_origin = ee.Array(NDVI_EVI.get('EVI')).slice(0, 0, n);
var chart = ui.Chart.array.values(y_origin, 0, x_origin)
    .setSeriesNames(['原始数据'])
    .setOptions({
      title: '原始数据',
      hAxis: hAxis,
      vAxis: vAxis,
      pointSize: 5,
});
print(chart);

在这里插入图片描述

步骤1:数据标准化

对每个波段 XkX_kXk 进行中心化处理:
Zk=Xk−μk,   μk=1n∑i=1nxi Z_k = X_k - \mu_k,\ \ \ \mu_k = \frac{1}{n}\sum_{i=1}^{n}x_i Zk=Xkμk,   μk=n1i=1nxi

var x_mean = x_origin.reduce(ee.Reducer.mean(), [0]);
var y_mean = y_origin.reduce(ee.Reducer.mean(), [0]);
var x_centered = x_origin.subtract(x_mean.repeat(0, n));
var y_centered = y_origin.subtract(y_mean.repeat(0, n));
var chart = ui.Chart.array.values(y_centered, 0, x_centered)
    .setSeriesNames(['中心化数据'])
    .setOptions({
      title: '中心化数据',
      hAxis: hAxis,
      vAxis: vAxis,
      pointSize: 5,
});
print(chart);

在这里插入图片描述

步骤2:计算协方差矩阵

设标准化数据矩阵为 ZZZ(m个像元 × n个波段),协方差矩阵为:
C=1m−1ZTZ C = \frac{1}{m-1} Z^T Z C=m11ZTZ

var D = ee.Array.cat([x_centered, y_centered], 1).transpose();
var covar = D.matrixMultiply(D.transpose()).divide(n-1);
print('covar',covar);

在这里插入图片描述

步骤3:特征值分解

解协方差矩阵的特征方程:
Cvi=λivi C \mathbf{v}_i = \lambda_i \mathbf{v}_i Cvi=λivi
其中:

  • λi\lambda_iλi:特征值(主成分方差)
  • vi\mathbf{v}_ivi:特征向量(主成分方向)
var eigens = covar.eigen();
// 获取特征值
var eigenValues = eigens.slice(1, 0, 1);
print('eigenValues',eigenValues);
// 获取特征向量
var eigenVectors = eigens.slice(1, 1);
print('eigenVectors',eigenVectors);

在这里插入图片描述
在这里插入图片描述

步骤4:生成主成分

第k主成分计算公式:
PCk=Z⋅vk PC_k = Z \cdot v_k PCk=Zvk

// 计算主成分
var principalComponents = eigenVectors.matrixMultiply(D);
print('principalComponents',principalComponents);
var x = principalComponents.slice(0, 0, 1).project([1]);
var y = principalComponents.slice(0, 1, 2).project([1]);
var chart = ui.Chart.array.values(y, 0, x)
    .setSeriesNames(['principalComponents'])
    .setOptions({
      title: 'principalComponents',
     hAxis: hAxis,
      vAxis: vAxis,
      // lineWidth: 1,
      pointSize: 5,
});
print(chart);

在这里插入图片描述

关键点:特征值大小反映主成分的信息量占比。


三、为什么必须用协方差矩阵?

PCA的数学本质

PCA的首要目标是找到使标准化数据ZZZ投影方差最大化的方向
假设这个方向为单位向量wwwwTw=1w^T w=1wTw=1),那么每个数据在这个方向下的坐标值为:wTZw^T ZwTZ,于是有方差:
D(x)=1m−1∑i=1m(wTxi)2=1m−1(wTZ)(wTZ)T=1m−1wTZZTw=wT(1m−1ZZT)w=wTCw \begin{array}{c} D(x) = \frac{1}{m-1} \sum_{i = 1}^{m}\left(w^{T} x_{i}\right)^{2} \\ = \frac{1}{m-1} \left(w^{T} Z\right)\left(w^{T} Z\right)^{T} \\ = \frac{1}{m-1} w^{T} Z Z^{T} w \\ = w^{T}\left(\frac{1}{m-1} Z Z^{T}\right) w \\ = w^{T} C w \end{array} D(x)=m11i=1m(wTxi)2=m11(wTZ)(wTZ)T=m11wTZZTw=wT(m11ZZT)w=wTCw
在约束条件 wTw=1w^T w = 1wTw=1 下求极值,构造拉格朗日函数:
L(w,λ)=wTCw−λ(wTw−1) \mathcal{L}(w, \lambda) = w^T C w - \lambda (w^T w - 1) L(w,λ)=wTCwλ(wTw1)
www 求导并令导数为0:
∂L∂w=2Cw−2λw=0 \frac{\partial \mathcal{L}}{\partial w} = 2C w - 2\lambda w = 0 wL=2Cw2λw=0
得到关键方程:
Cw=λw \boxed{C w = \lambda w} Cw=λw
这正是协方差矩阵 CCC 的特征值方程!
代入方差D(x)D(x)D(x)中:
D(x)=wTCw=wTλw=λ D(x)= w^{T} C w = w^{T} \lambda w = \lambda D(x)=wTCw=wTλw=λ
因此所求方差D(x)D(x)D(x)最大值就是协方差矩阵CCC的最大特征值λ\lambdaλ,而此时的方向就是最大特征值所对应的特征向量www,那么次大方向自然就是第二大特征值对应的特征向量,依此类推,直到我们找出了n个,以这n个特征向量作为新的坐标系,然后将原始数据投影到这个坐标系下即可得到降维后的数据。

三、GEE实战:将PCA应用到影像

完整代码示例
var scale = 1000;
var roi = ee.Geometry.Polygon(
        [[[98.76874122458284, 27.476046782884104],
          [98.76874122458284, 26.36424630156598],
          [100.16400489645784, 26.36424630156598],
          [100.16400489645784, 27.476046782884104]]], null, false);
Map.centerObject(roi, 8);
var visualization = {
  min: 0,
  max: 0.9,
  palette: [
    'ffffff', 'ce7e45', 'df923d', 'f1b555', 'fcd163', '99b718', '74a901',
    '66a000', '529400', '3e8601', '207401', '056201', '004c00', '023b01',
    '012e01', '011d01', '011301'
  ],
};
var imageCol =ee.ImageCollection('MODIS/061/MOD13A1')
                       .select(['NDVI', 'EVI'])
                       .filterBounds(roi)
                       .filterDate("2020-01-01","2020-12-31")
                      .map(function (image){
                        return image.addBands(image.divide(10000), null, true);
                      });
var image = imageCol.median().clip(roi);
var bandNames = image.bandNames();
Map.addLayer(image.select('NDVI'), visualization, 'NDVI');   
Map.addLayer(image.select('EVI'), visualization, 'EVI');   
// 计算均值
var meanDict = image.reduceRegion({
    reducer: ee.Reducer.mean(),
    geometry: roi,
    scale: scale,
    maxPixels: 1e13
});
// 中心化
var means = ee.Image.constant(meanDict.values(bandNames));
var centered = image.subtract(means);

// 转换为数组
var arrays = centered.toArray();
// 计算协方差矩阵
var covar = arrays.reduceRegion({
    reducer: ee.Reducer.centeredCovariance(),
    geometry: roi,
    scale: scale,
    maxPixels: 1e13
});
// 特征值分解
var covarArray = ee.Array(covar.get('array'));
print('covarArray', covarArray);
var eigens = covarArray.eigen();
print('eigens', eigens);
var eigenValues = eigens.slice(1, 0, 1);
print('eigenValues', eigenValues);
var eigenValuesList = eigenValues.toList().flatten();
var total = eigenValuesList.reduce(ee.Reducer.sum());
var percentageVariance = eigenValuesList.map(function(item) {
  return ee.Number(item).divide(total).multiply(100).format("%.2f");
});
print('信息量占比', percentageVariance);   
// 获取特征向量
var eigenVectors = eigens.slice(1, 1);
print('eigenVectors', eigenVectors);
// 计算主成分
var arrayImage = arrays.toArray(1);

var principalComponents = ee.Image(eigenVectors).matrixMultiply(arrayImage).arrayProject([0]).arrayFlatten([['PC1', 'PC2']]);
Map.addLayer(principalComponents.select('PC1'), {min:-1,max:1}, 'PC1');  
Map.addLayer(principalComponents.select('PC2'), {min:-1,max:1}, 'PC2'); 
关键函数解析

ee.Reducer.centeredCovariance()

  • 计算协方差矩阵

eigen()

  • 执行矩阵的特征分解
输出结果:

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值