3.scipy Linalg


title: "3.scipy-linalg" date: 2026-05-24T14:11:09Z

1import pylab as pl
2import numpy as np
3from scipy import linalg
1import matplotlib as mpl
2mpl.rcParams['font.sans-serif'] = ['SimHei']

线性代数-linalg

解线性方程组

 1import numpy as np
 2from scipy import linalg
 3
 4m, n = 500, 50
 5A = np.random.rand(m, m)
 6B = np.random.rand(m, n)
 7X1 = linalg.solve(A, B)
 8X2 = np.dot(linalg.inv(A), B)
 9print (np.allclose(X1, X2))
10%timeit linalg.solve(A, B)
11%timeit np.dot(linalg.inv(A), B)
True
5.38 ms ± 120 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
8.14 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1luf = linalg.lu_factor(A)
2X3 = linalg.lu_solve(luf, B)
3np.allclose(X1, X3)
True
 1M, N = 1000, 100
 2np.random.seed(0)
 3A = np.random.rand(M, M)
 4B = np.random.rand(M, N)
 5Ai = linalg.inv(A)
 6luf = linalg.lu_factor(A)   
 7%timeit linalg.inv(A)
 8%timeit np.dot(Ai, B)
 9%timeit linalg.lu_factor(A)    
10%timeit linalg.lu_solve(luf, B) 
50.6 ms ± 1.94 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
3.49 ms ± 306 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
20.1 ms ± 1.42 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
4.49 ms ± 65 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

最小二乘解

 1from numpy.lib.stride_tricks import as_strided
 2
 3
 4def make_data(m, n, noise_scale):  #❶
 5    np.random.seed(42)
 6    x = np.random.standard_normal(m)
 7    h = np.random.standard_normal(n)
 8    y = np.convolve(x, h)
 9    yn = y + np.random.standard_normal(len(y)) * noise_scale * np.max(y)
10    return x, yn, h
11
12
13def solve_h(x, y, n):  #❷
14    X = as_strided(
15        x, shape=(len(x) - n + 1, n), strides=(x.itemsize, x.itemsize))  #❸
16    Y = y[n - 1:len(x)]  #❹
17    h = linalg.lstsq(X, Y)  #❺
18    return h[0][::-1]  #❻
1x, yn, h = make_data(1000, 100, 0.4)
2H1 = solve_h(x, yn, 120)
3H2 = solve_h(x, yn, 80)
4
5print("Average error of H1:", np.mean(np.abs(h[:100] - h)))
6print("Average error of H2:", np.mean(np.abs(h[:80] - H2)))
Average error of H1: 0.0
Average error of H2: 0.2958422158342371
 1#%figonly=实际的系统参数与最小二乘解的比较
 2fig, (ax1, ax2) = pl.subplots(2, 1, figsize=(6, 4))
 3ax1.plot(h, linewidth=2, label=u"实际的系统参数")
 4ax1.plot(H1, linewidth=2, label=u"最小二乘解H1", alpha=0.7)
 5ax1.legend(loc="best", ncol=2)
 6ax1.set_xlim(0, len(H1))
 7
 8ax2.plot(h, linewidth=2, label=u"实际的系统参数")
 9ax2.plot(H2, linewidth=2, label=u"最小二乘解H2", alpha=0.7)
10ax2.legend(loc="best", ncol=2)
11ax2.set_xlim(0, len(H1));

png

特征值和特征向量

1A = np.array([[1, -0.3], [-0.1, 0.9]])
2evalues, evectors = linalg.eig(A)
3
4print(evalues)
5print(evectors)
[1.13027756+0.j 0.76972244+0.j]
[[ 0.91724574  0.79325185]
 [-0.3983218   0.60889368]]
 1#%figonly=线性变换将蓝色箭头变换为红色箭头
 2points = np.array([[0, 1.0], [1.0, 0], [1, 1]])
 3
 4def draw_arrows(points, **kw):
 5    props = dict(color="blue", arrowstyle="->")
 6    props.update(kw)
 7    for x, y in points:
 8        pl.annotate("",
 9                    xy=(x, y), xycoords='data',
10                    xytext=(0, 0), textcoords='data',
11                    arrowprops=props)
12
13draw_arrows(points)
14draw_arrows(np.dot(A, points.T).T, color="red")    
15draw_arrows(evectors.T, alpha=0.7, linewidth=2)
16draw_arrows(np.dot(A, evectors).T, color="red", alpha=0.7, linewidth=2)    
17
18ax = pl.gca()
19ax.set_aspect("equal")
20ax.set_xlim(-0.5, 1.1)
21ax.set_ylim(-0.5, 1.1);

png

 1np.random.seed(42)
 2t = np.random.uniform(0, 2*np.pi, 60)
 3
 4alpha = 0.4
 5a = 0.5
 6b = 1.0
 7x = 1.0 + a*np.cos(t)*np.cos(alpha) - b*np.sin(t)*np.sin(alpha)
 8y = 1.0 + a*np.cos(t)*np.sin(alpha) - b*np.sin(t)*np.cos(alpha)
 9x += np.random.normal(0, 0.05, size=len(x))
10y += np.random.normal(0, 0.05, size=len(y))
1D = np.c_[x**2, x*y, y**2, x, y, np.ones_like(x)]
2A = np.dot(D.T, D)
3C = np.zeros((6, 6))
4C[[0, 1, 2], [2, 1, 0]] = 2, -1, 2
5evalues, evectors = linalg.eig(A, C)     #❶
6evectors = np.real(evectors)
7err = np.mean(np.dot(D, evectors)**2, 0) #❷
8p = evectors[:, np.argmin(err) ]         #❸
9print (p)
[-0.55214278  0.5580915  -0.23809922  0.54584559 -0.08350449 -0.14852803]
1#%figonly=用广义特征向量计算的拟合椭圆
2def ellipse(p, x, y):
3    a, b, c, d, e, f = p
4    return a*x**2 + b*x*y + c*y**2 + d*x + e*y + f
5
6X, Y = np.mgrid[0:2:100j, 0:2:100j]
7Z = ellipse(p, X, Y)
8pl.plot(x, y, "ro", alpha=0.5)
9pl.contour(X, Y, Z, levels=[0]);

png

奇异值分解-SVD

1r, g, b = np.rollaxis(pl.imread("vinci_target.png"), 2).astype(float)
2img = 0.2989 * r + 0.5870 * g + 0.1140 * b
3img.shape
(505, 375)
1U, s, Vh = linalg.svd(img)
2print(U.shape)
3print(s.shape) 
4print(Vh.shape)
(505, 505)
(375,)
(375, 375)
1#%fig=按从大到小排列的奇异值
2pl.semilogy(s, lw=3);
C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\mathtext.py:854: MathTextWarning: Font 'default' does not have a glyph for '-' [U+2212]
  MathTextWarning)
C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\mathtext.py:855: MathTextWarning: Substituting with a dummy symbol.
  warn("Substituting with a dummy symbol.", MathTextWarning)

png

1def composite(U, s, Vh, n):
2    return np.dot(U[:, :n], s[:n, np.newaxis] * Vh[:n, :])
3
4print (np.allclose(img, composite(U, s, Vh, len(s))))
True
1#%fig=原始图像、使用10、20、50个向量合成的图像(从左到右)
2img10 = composite(U, s, Vh, 10)
3img20 = composite(U, s, Vh, 20)
4img50 = composite(U, s, Vh, 50)
1%array_image img; img10; img20; img50
UsageError: Line magic function `%array_image` not found.
1pl.imshow(img)
<matplotlib.image.AxesImage at 0x16bf1557b00>

png

1pl.imshow(img10)
<matplotlib.image.AxesImage at 0x16bf186fc88>

png

1pl.imshow(img20)
<matplotlib.image.AxesImage at 0x16bf1d99cc0>

png

1pl.imshow(img50)
<matplotlib.image.AxesImage at 0x16bf1de9da0>

png