import numpy as np
import netCDF4 as nc4
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.util import add_cyclic_point
x = np.array([1, 2, -3, 4])
y = x * 2
X = np.array([x, y]).transpose()
m, n = X.shape
print(m, n)
4 2
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(X[:, 0], X[:, 1])
<matplotlib.collections.PathCollection at 0x1123035c0>
X = (X - X.mean(axis=0)) / X.std(axis=0)
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(X[:, 0], X[:, 1])
<matplotlib.collections.PathCollection at 0x1123a9048>
print(X.mean(), X.std())
0.0 1.0
U, s, V = np.linalg.svd(X)
U
array([[ 0. , -0.19611614, 0.78446454, -0.58834841], [-0.19611614, 0.96153846, 0.15384615, -0.11538462], [ 0.78446454, 0.15384615, 0.38461538, 0.46153846], [-0.58834841, -0.11538462, 0.46153846, 0.65384615]])
U @ U.transpose()
array([[ 1.00000000e+00, 8.32667268e-17, -1.45716772e-16, 5.89805982e-17], [ 8.32667268e-17, 1.00000000e+00, -3.46944695e-17, -1.38777878e-17], [-1.45716772e-16, -3.46944695e-17, 1.00000000e+00, 1.11022302e-16], [ 5.89805982e-17, -1.38777878e-17, 1.11022302e-16, 1.00000000e+00]])
V
array([[-0.70710678, -0.70710678], [-0.70710678, 0.70710678]])
V @ V.transpose()
array([[1., 0.], [0., 1.]])
s * s / n
array([4., 0.])
元に戻るかX=UΣVTを計算
smat = np.zeros((m, n))
smat[:n, :n] = np.diag(s)
np.allclose(X, U @ (smat @ V))
True
V = V.transpose()
X = X @ V
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(X[:, 0], X[:, 1])
<matplotlib.collections.PathCollection at 0x1124110b8>
m = 100
x = np.random.randn(m)
y = x + np.random.rand(m)
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x, y)
ax.set_aspect('equal')
正規化乱数だがサンプル数が多くないので,正規化は必要。
X = np.array([x, y]).transpose()
X = (X - X.mean()) / X.std()
x = X[:,0]
y = X[:,1]
X.shape
(100, 2)
SVD解析を実行する。
U, s, V = np.linalg.svd(X)
V = V.transpose()
V
array([[ 0.66550926, 0.74638959], [ 0.74638959, -0.66550926]])
散布図に主成分を描いてみよう。
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(x, y, color='gray')
ax.quiver(V[0,0], V[0,1], units='xy', angles='xy', scale=1, color='r')
ax.quiver(-V[1,0], -V[1,1], units='xy', angles='xy', scale=1, color='b')
ax.set_aspect('equal')
回転してデータの圧縮を確認。
X = X @ V
fig, ax = plt.subplots(figsize=(5, 5))
ax.scatter(X[:, 0], X[:, 1])
ax.set_aspect('equal')
月平均の海面気圧(slp)から1月のみを切り出したファイル( https://github.com/tenomoto/dsss2018/blob/master/slp_jan_mean.nc )をダウンロードする。
座標軸を読む。
f = nc4.Dataset('slp_jan_mean.nc')
list(f.dimensions)
['time', 'lon', 'lat']
変数を読む。
list(f.variables)
['time', 'lon', 'lat', 'slp']
lon = f.variables['lon'][:]
lat = f.variables['lat'][:]
time = f.variables['time'][:]
気圧を読む。
slp = f.variables['slp']
print(slp)
<class 'netCDF4._netCDF4.Variable'> float32 slp(time, lat, lon) long_name: Sea Level Pressure units: millibars _FillValue: -9.96921e+36 missing_value: -9.96921e+36 precision: 1 least_significant_digit: 1 var_desc: Sea Level Pressure level_desc: Sea Level statistic: Mean parent_stat: Other dataset: NCEP Reanalysis Derived Products actual_range: [ 955.56085 1082.5582 ] unlimited dimensions: time current shape = (71, 73, 144) filling off
描画関数を作っておこう。
def plot_nps(lon, lat, data):
datac, lonc = add_cyclic_point(data, coord=lon)
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.NorthPolarStereo())
p = ax.contourf(lonc, lat, datac, transform=ccrs.PlateCarree())
ax.set_extent([0, 359.999, 20, 90], ccrs.PlateCarree())
fig.colorbar(p)
ax.coastlines()
最初の年を描画して確認。警告は無視してよい。
plot_nps(lon, lat, slp[0])
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)
気候値(時間平均)
slp_clim = np.mean(slp, axis=0)
slp_clim.shape
(73, 144)
plot_nps(lon, lat, slp_clim)
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)
北太平洋にアリューシャン低気圧,北大西洋にアイスランド低気圧,ユーラシア大陸にシベリア高気圧が現れた。
標準偏差
slp_stddev = np.std(slp, axis=0)
slp_stddev.shape
(73, 144)
plot_nps(lon, lat, slp_stddev)
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)
アリューシャン低気圧とアイスランド低気圧の変動が大きい。
極に近づくほど東西格子間隔が狭まることを考慮して,緯度の重み√cosϕを掛ける。
wgt = np.sqrt(np.abs(np.cos(np.deg2rad(lat))))
Thompson and Wallace (1998)に基づき,北緯20度以北の海面気圧を用いる。
dslp = (slp - slp_clim) / slp_stddev
X = dslp * wgt[None, :, None]
X = X[:,np.where(lat > 20),:].reshape(time.size,-1).transpose()
m, n = X.shape
print(m, n)
4032 71
U, s, V = np.linalg.svd(X)
寄与率
contrib = (s * s) / (s @ s) * 100
fig, ax = plt.subplots(figsize=(5,5))
ax.plot(contrib[0:10])
ax.plot(contrib[0:10],'bo')
ax.set_title("contribution rate %", fontsize=14)
ax.grid()
回帰
D = (dslp.transpose() @ V.transpose()).transpose()
D.shape
(71, 73, 144)
plot_nps(lon, lat, D[0])
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)
plot_nps(lon, lat, D[1])
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)
plot_nps(lon, lat, D[2])
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)
共分散行列の固有値分解でも同じになるか確認しよう。
cov = (X.transpose() @ X) / n
W, V_eig = np.linalg.eig(cov)
W.shape; V_eig.shape
(71, 71)
D_eig = (dslp.transpose() @ V_eig).transpose()
D_eig.shape
(71, 73, 144)
plot_nps(lon, lat, D_eig[0])
/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/cartopy/util.py:102: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result. new_data = ma.concatenate((data, data[slicer]), axis=axis)