每个网格单元跨时间的线性回归

Chr*_*007 5 python machine-learning linear-regression python-3.x python-xarray

我是 xarray 和机器学习方面的新手。

所以我的 xarray 数据集如下:

<xarray.Dataset>
Dimensions:    (latitude: 721, longitude: 1440, time: 72)
Coordinates:
  * time       (time) datetime64[ns] 1950-01-01 1951-01-01 ... 2021-01-01
  * longitude  (longitude) float32 0.0 0.25 0.5 0.75 ... 359.25 359.5 359.75
  * latitude   (latitude) float32 90.0 89.75 89.5 89.25 ... -89.5 -89.75 -90.0
Data variables:
    z          (time, latitude, longitude) float32 49654.793 49654.793 ... 49654.793
Run Code Online (Sandbox Code Playgroud)

现在我想在跨时间维度的每个网格上应用线性回归,然后我想从原始值中删除回归值以删除趋势。下面是一个示例网格的示例。

y = np.array(jan.z[:, 700, 700]) #single grid with all time
x = (np.arange(1950, len(y)+1949)).reshape(-1, 1) #72 time for x axis which will remain same for all grid

reg = LinearRegression().fit(x, y)

pred = reg.predict(x)
y = (y - (pred - y))
Run Code Online (Sandbox Code Playgroud)

现在这仅适用于一个网格,我有这样的721*14000网格,因此 for 循环不会是最优化的方法,是否有更优化的方法或一些直接函数可以在 xarray 中执行此操作?我尝试寻找类似的东西,但我找不到哪个可以解决我的问题。

Mic*_*ado 4

xarray 现在有一个 polyfit 方法(请参阅xr.DataArray.polyfitxr.Dataset.polyfit)。它与 dask 集成良好,即使对于大型阵列也能表现良好。

例子

In [2]: # generate a large random dask array
   ...: arr = dda.random.random((100, 1000, 1000), chunks=(-1, 100, 100)).astype('float32')

In [3]: da = xr.DataArray(arr, dims=['time', 'y', 'x'], coords=[pd.date_range('1950-01-01', freq='Y', periods=100), np.a
  ...: range(1000), np.arange(1000)])

In [4]: da
Out[4]:
<xarray.DataArray 'astype-5e6d16cb0909caa0098a5c92f0770801' (time: 100,
                                                             y: 1000, x: 1000)>
dask.array<astype, shape=(100, 1000, 1000), dtype=float32, chunksize=(100, 100, 100), chunktype=numpy.ndarray>
Coordinates:
  * time     (time) datetime64[ns] 1950-12-31 1951-12-31 ... 2049-12-31
  * y        (y) int64 0 1 2 3 4 5 6 7 8 ... 991 992 993 994 995 996 997 998 999
  * x        (x) int64 0 1 2 3 4 5 6 7 8 ... 991 992 993 994 995 996 997 998 999
Run Code Online (Sandbox Code Playgroud)

沿维度调用 polyfittimedeg=1进行线性最小二乘回归:


In [5]: da.polyfit('time', deg=1)
Out[5]:
<xarray.Dataset>
Dimensions:               (degree: 2, y: 1000, x: 1000)
Coordinates:
  * degree                (degree) int64 1 0
  * y                     (y) int64 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
  * x                     (x) int64 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
Data variables:
    polyfit_coefficients  (degree, y, x) float64 dask.array<chunksize=(2, 10, 1000), meta=np.ndarray>
Run Code Online (Sandbox Code Playgroud)

完整的工作流程

首先,将年份值指定为数组上的坐标,并使用swap_dims替换'time'为年度值(以便正确缩放系数)。

In [13]: year = np.arange(1950, 2050)

In [14]: da.coords['year'] = ('time', ), year

In [15]: da = da.swap_dims({'time': 'year'})
Run Code Online (Sandbox Code Playgroud)

现在您可以调用 polyfit 来获取 的趋势[units/year]

In [16]: coeffs = da.polyfit('year', deg=1)
Run Code Online (Sandbox Code Playgroud)

xr.polyval可用于使用所得系数来预测值:

In [17]: pred = xr.polyval(da.year, coeffs.chunk({'x': 100, 'y': 100}))

In [18]: pred
Out[18]:
<xarray.Dataset>
Dimensions:               (y: 1000, x: 1000, year: 100)
Coordinates:
  * y                     (y) int64 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
  * x                     (x) int64 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
  * year                  (year) int64 1950 1951 1952 1953 ... 2047 2048 2049
Data variables:
    polyfit_coefficients  (year, y, x) float64 dask.array<chunksize=(100, 100, 100), meta=np.ndarray>
Run Code Online (Sandbox Code Playgroud)

结果可用于计算无法解释的变异:

In [19]: unexplained = da - pred

In [20]: unexplained
Out[20]:
<xarray.Dataset>
Dimensions:               (y: 1000, x: 1000, year: 100)
Coordinates:
  * y                     (y) int64 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
  * x                     (x) int64 0 1 2 3 4 5 6 ... 994 995 996 997 998 999
  * year                  (year) int64 1950 1951 1952 1953 ... 2047 2048 2049
    time                  (year) datetime64[ns] 1950-12-31 ... 2049-12-31
Data variables:
    polyfit_coefficients  (year, y, x) float64 dask.array<chunksize=(100, 100, 100), meta=np.ndarray>
Run Code Online (Sandbox Code Playgroud)