通过python掌握线性代数

可以先看最后一个视频,了解内容情况。

本文比较长,是个人对视频内容的一些总结及理解,可供参考。

代码是在jupiterlab里运行的,因为比较整合。

目录

向量

用numpy实现

矩阵

矩阵变换

用numpy实现

消元

 p58 LU分解

p63 线性组合

生成空间

第九章

子空间

 零空间

 施密特正交​编辑

P93 QR分解

SVD分解


下图贯穿视频

通过python掌握线性代数_第1张图片

前面比较能理解,就记录了一下代码实现

向量

 

import math
# from ._globals import is_zero, is_equal
EPSILON = 1e-8


def is_zero(x):
    return abs(x) < EPSILON


def is_equal(a, b):
    return abs(a - b) < EPSILON


class Vector:

    def __init__(self, lst):
        self._values = list(lst)

    @classmethod
    def zero(cls, dim):
        """返回一个dim维的零向量"""
        return cls([0] * dim)

    def __add__(self, another):
        """向量加法,返回结果向量"""
        assert len(self) == len(another), \
            "Error in adding. Length of vectors must be same."

        return Vector([a + b for a, b in zip(self, another)])

    def __sub__(self, another):
        """向量减法,返回结果向量"""
        assert len(self) == len(another), \
            "Error in subtracting. Length of vectors must be same."

        return Vector([a - b for a, b in zip(self, another)])

    def norm(self):
        """返回向量的模"""
        return math.sqrt(sum(e**2 for e in self))

    def normalize(self):
        """返回向量的单位向量"""
        if is_zero(self.norm()):
            raise ZeroDivisionError("Normalize error! norm is zero.")
        return Vector(self._values) / self.norm()

    def dot(self, another):
        """向量点乘,返回结果标量"""
        assert len(self) == len(another), \
            "Error in dot product. Length of vectors must be same."

        return sum(a * b for a, b in zip(self, another))

    def underlying_list(self):
        """返回向量的底层列表"""
        return self._values[:]

    def __mul__(self, k):
        """返回数量乘法的结果向量:self * k"""
        return Vector([k * e for e in self])

    def __rmul__(self, k):
        """返回数量乘法的结果向量:k * self"""
        return self * k

    def __truediv__(self, k):
        """返回数量除法的结果向量:self / k"""
        return (1 / k) * self

    def __pos__(self):
        """返回向量取正的结果向量"""
        return 1 * self

    def __neg__(self):
        """返回向量取负的结果向量"""
        return -1 * self

    def __eq__(self, other):
        """返回向量是否相等"""
        other_list = other.underlying_list();
        if(len(other_list) != len(self._values)):
            return False
        return all(is_equal(x, y) for x, y in zip(self._values, other_list))

    def __neq__(self, other):
        """返回向量是否不等"""
        return not(self == other)

    def __iter__(self):
        """返回向量的迭代器"""
        return self._values.__iter__()

    def __getitem__(self, index):
        """取向量的第index个元素"""
        return self._values[index]

    def __len__(self):
        """返回向量长度(有多少个元素)"""
        return len(self._values)

    def __repr__(self):
        return "Vector({})".format(self._values)

    def __str__(self):
        return "({})".format(", ".join(str(e) for e in self._values))
# from playLA.Vector import Vector

if __name__ == "__main__":

    vec = Vector([5, 2])
    print(vec) #
    print("len(vec) = {}".format(len(vec)))
    print("vec[0] = {}, vec[1] = {}".format(vec[0], vec[1]))
    # (5, 2)
    # len(vec) = 2
    # vec[0] = 5, vec[1] = 2
    vec2 = Vector([3, 1])
    print("{} + {} = {}".format(vec, vec2, vec + vec2))
    print("{} - {} = {}".format(vec, vec2, vec - vec2))
    # (5, 2) + (3, 1) = (8, 3)
    # (5, 2) - (3, 1) = (2, 1)
    print("{} * {} = {}".format(vec, 3, vec * 3))
    print("{} * {} = {}".format(3, vec, 3 * vec))
    # (5, 2) * 3 = (15, 6)
    # 3 * (5, 2) = (15, 6)
    print("+{} = {}".format(vec, +vec))
    print("-{} = {}".format(vec, -vec))
    # +(5, 2) = (5, 2)
    # -(5, 2) = (-5, -2)
    zero2 = Vector.zero(2)
    print(zero2)
    print("{} + {} = {}".format(vec, zero2, vec + zero2))
    # (0, 0)
    # (5, 2) + (0, 0) = (5, 2)
    print("norm({}) = {}".format(vec, vec.norm()))
    print("norm({}) = {}".format(vec2, vec2.norm()))
    print("norm({}) = {}".format(zero2, zero2.norm()))
    # norm((5, 2)) = 5.385164807134504
    # norm((3, 1)) = 3.1622776601683795
    # norm((0, 0)) = 0.0
    print("normalize {} is {}".format(vec, vec.normalize()))
    print(vec.normalize().norm())
    # normalize(5, 2) is (0.9284766908852593, 0.3713906763541037)
    # 1.0
    print("normalize {} is {}".format(vec2, vec2.normalize()))
    print(vec2.normalize().norm())
    # normalize(3, 1) is (0.9486832980505138, 0.31622776601683794)
    # 0.9999999999999999
    try:
        zero2.normalize()
    except ZeroDivisionError:
        print("Cannot normalize zero vector {}.".format(zero2))
        #Cannot normalize zero vector (0, 0).

    print(vec.dot(vec2)) #17

    vec3 = Vector([0, 0])
    print("{} == {}? {}".format(zero2, vec3, vec3 == zero2))
    print("{} == {}? {}".format(vec2, vec3, vec3 == vec2))
    print("{} != {}? {}".format(vec2, vec3, vec3 != vec2))
    # (0, 0) == (0, 0)? True
    # (3, 1) == (0, 0)? False
    # (3, 1) != (0, 0)? True

用numpy实现

import numpy as np

if __name__ == "__main__":

    print(np.__version__)

    # np.array 基础
    lst = [1, 2, 3]
    lst[0] = "Linear Algebra"
    print(lst)

    vec = np.array([1, 2, 3])
    print(vec)
    # vec[0] = "Linear Algebra"
    # vec[0] = 666
    # print(vec)

    # np.array的创建
    print(np.zeros(5))
    print(np.ones(5))
    print(np.full(5, 666))

    # np.array的基本属性
    print(vec)
    print("size =", vec.size)
    print("size =", len(vec))
    print(vec[0])
    print(vec[-1])
    print(vec[0: 2])
    print(type(vec[0: 2]))

    # np.array的基本运算
    vec2 = np.array([4, 5, 6])
    print("{} + {} = {}".format(vec, vec2, vec + vec2))
    print("{} - {} = {}".format(vec, vec2, vec - vec2))
    print("{} * {} = {}".format(2, vec, 2 * vec))
    print("{} * {} = {}".format(vec, vec2, vec * vec2))
    print("{}.dot({}) = {}".format(vec, vec2, vec.dot(vec2)))

    print(np.linalg.norm(vec))
    print(vec / np.linalg.norm(vec))
    print(np.linalg.norm(vec / np.linalg.norm(vec)))

    # zero3 = np.zeros(3)
    # print(zero3 / np.linalg.norm(zero3))

矩阵

# from .Vector import Vector


class Matrix:
    # __init__(self, list2d):初始化方法,接受一个二维列表或二维向量列表作为参数,将其转换为内部的矩阵表示self._values。
    # zero(cls, r, c):类方法,返回一个r行c列的零矩阵。
    # identity(cls, n):类方法,返回一个n行n列的单位矩阵。
    # T(self):返回矩阵的转置矩阵。
    # __add__(self, another):重载加法运算符,返回两个矩阵的加法结果。
    # __sub__(self, another):重载减法运算符,返回两个矩阵的减法结果。
    # dot(self, another):矩阵乘法,接受一个向量或矩阵作为参数,返回乘法结果。
    # __mul__(self, k):重载乘法运算符,返回矩阵与标量k的数量乘结果。
    # __rmul__(self, k):重载乘法运算符,返回标量k与矩阵的数量乘结果。
    # __truediv__(self, k):重载除法运算符,返回矩阵除以标量k的结果。
    # __pos__(self):重载正号运算符,返回矩阵取正的结果。
    # __neg__(self):重载负号运算符,返回矩阵取负的结果。
    # row_vector(self, index):返回矩阵的第index个行向量。
    # col_vector(self, index):返回矩阵的第index个列向量。
    # __getitem__(self, pos):重载索引运算符,返回矩阵中pos位置的元素。
    # size(self):返回矩阵的元素个数。
    # row_num(self):返回矩阵的行数。
    # col_num(self):返回矩阵的列数。
    # shape(self):返回矩阵的形状,即行数和列数。
    # __repr__(self)和__str__(self):返回矩阵的字符串表示。

    def __init__(self, list2d):
        if isinstance(list2d[0], list):
            self._values = [row[:] for row in list2d]
        elif isinstance(list2d[0], Vector):
            self._values = [row.underlying_list() for row in list2d]
        # 如果list2d的第一个元素是列表,则假设list2d是一个普通的二维列表,将其拷贝到self._values中。
        # 如果list2d的第一个元素是Vector类型的对象,则假设list2d是一个包含Vector对象的二维列表,并将其中每个Vector对象的底层列表提取出来,并存储到self._values中。

    @classmethod
    def zero(cls, r, c):
        """返回一个r行c列的零矩阵"""
        return cls([[0] * c for _ in range(r)])

    @classmethod
    def identity(cls, n):
        """返回一个n行n列的单位矩阵"""
        m = [[0]*n for _ in range(n)]
        for i in range(n):
            m[i][i] = 1;
        return cls(m)

    def T(self):
        """返回矩阵的转置矩阵"""
        return Matrix([[e for e in self.col_vector(i)]
                       for i in range(self.col_num())])

    def __add__(self, another):
        """返回两个矩阵的加法结果"""
        assert self.shape() == another.shape(), \
            "Error in adding. Shape of matrix must be same."
        # 确保两个矩阵具有相同的形状(行数和列数相同),如果形状不同,则会抛出一个错误提示.
        return Matrix([[a + b for a, b in zip(self.row_vector(i), another.row_vector(i))]
                       for i in range(self.row_num())])
        # 通过遍历两个矩阵的行向量,将对应位置的元素相加,生成一个新的矩阵作为加法的结果。
        # 在列表表达式中,循环遍历可迭代对象中的每个元素,并将表达式的结果添加到生成的列表中。
        # 例如,以下列表表达式将一个列表中的每个元素平方,并生成一个新的列表:
        # 例如numbers = [1, 2, 3, 4, 5]
        # squared_numbers = [x**2 for x in numbers]
        # print(squared_numbers)  # 输出: [1, 4, 9, 16, 25]


    def __sub__(self, another):
        """返回两个矩阵的减法结果"""
        assert self.shape() == another.shape(), \
            "Error in subtracting. Shape of matrix must be same."
        return Matrix([[a - b for a, b in zip(self.row_vector(i), another.row_vector(i))]
                       for i in range(self.row_num())])
        #迭代两个矩阵的对应行向量,并将对应位置的元素相减得到结果矩阵。

    def dot(self, another):
        """返回矩阵乘法的结果"""
        if isinstance(another, Vector):
            # 矩阵和向量的乘法
            assert self.col_num() == len(another), \
                "Error in Matrix-Vector Multiplication."
            return Vector([self.row_vector(i).dot(another) for i in range(self.row_num())])

        if isinstance(another, Matrix):
            # 矩阵和矩阵的乘法
            assert self.col_num() == another.row_num(), \
                "Error in Matrix-Matrix Multiplication."
            return Matrix([[self.row_vector(i).dot(another.col_vector(j)) for j in range(another.col_num())]
                           for i in range(self.row_num())])
        # 如果another是Vector类型的对象,则执行矩阵和向量的乘法。
        # 在这种情况下,首先断言当前矩阵的列数等于向量的长度,以确保乘法操作是有效的。
        # 然后,通过迭代矩阵的每一行,调用对应行向量的dot方法与向量进行点积运算,并将结果存储在一个列表中,最后将该列表作为结果返回。

        # 如果another是Matrix类型的对象,则执行矩阵和矩阵的乘法。
        # 在这种情况下,首先断言当前矩阵的列数等于another矩阵的行数,以确保乘法操作是有效的。
        # 然后,通过嵌套的列表推导式,迭代当前矩阵的每一行和another矩阵的每一列,并调用对应行向量和列向量的dot方法进行点积运算,得到乘法的结果矩阵。



    def __mul__(self, k):
        """返回矩阵的数量乘结果: self * k"""
        return Matrix([[e * k for e in self.row_vector(i)]
                       for i in range(self.row_num())])
    # 通过列表推导式迭代每个元素,将当前矩阵的每个元素乘以k,得到结果矩阵。

    def __rmul__(self, k):
        """返回矩阵的数量乘结果: k * self"""
        return self * k
        # 矩阵对象的右乘法,用于处理形如k * self的乘法运算。它直接调用了当前矩阵对象的__mul__方法,将k作为参数传递给它。

    def __truediv__(self, k):
        """返回数量除法的结果矩阵:self / k"""
        return (1 / k) * self
        # 将矩阵的每个元素除以k来得到结果矩阵。


    def __pos__(self):
        """返回矩阵取正的结果"""
        return 1 * self
        # 矩阵对象的取正运算,即返回矩阵本身。


    def __neg__(self):
        """返回矩阵取负的结果"""
        return -1 * self
        # 矩阵对象的取负运算,即将矩阵的每个元素取相反数得到结果矩阵。

    def row_vector(self, index):
        """返回矩阵的第index个行向量"""
        return Vector(self._values[index])

    def col_vector(self, index):
        """返回矩阵的第index个列向量"""
        return Vector([row[index] for row in self._values])

    def __getitem__(self, pos):
        """返回矩阵pos位置的元素 pos元组"""
        r, c = pos
        return self._values[r][c]

    def size(self):
        """返回矩阵的元素个数"""
        r, c = self.shape()
        return r * c

    def row_num(self):
        """返回矩阵的行数"""
        return self.shape()[0]

    __len__ = row_num

    def col_num(self):
        """返回矩阵的列数"""
        return self.shape()[1]

    def shape(self):
        """返回矩阵的形状: (行数, 列数)"""
        return len(self._values), len(self._values[0])

    def __repr__(self):
        return "Matrix({})".format(self._values)

    __str__ = __repr__
# from playLA.Vector import Vector
# from playLA.Matrix import Matrix


if __name__ == "__main__":

    matrix = Matrix([[1, 2], [3, 4]])
    print(matrix) #Matrix([[1, 2], [3, 4]])
    print("matrix.shape = {}".format(matrix.shape())) #matrix.shape = (2, 2)
    print("matrix.size = {}".format(matrix.size())) #matrix.size = 4
    print("len(matrix) = {}".format(len(matrix))) #len(matrix) = 2
    print("matrix[0][0] = {}".format(matrix[0, 0])) #matrix[0][0] = 1

    matrix2 = Matrix([[5, 6], [7, 8]])
    print(matrix2)
    print("add: {}".format(matrix + matrix2)) #add: Matrix([[6, 8], [10, 12]])
    print("subtract: {}".format(matrix - matrix2)) #subtract: Matrix([[-4, -4], [-4, -4]])
    print("scalar-mul: {}".format(2 * matrix)) #scalar-mul: Matrix([[2, 4], [6, 8]])
    print("scalar-mul: {}".format(matrix * 2)) #scalar-mul: Matrix([[2, 4], [6, 8]])
    print("zero_2_3: {}".format(Matrix.zero(2, 3))) #zero_2_3: Matrix([[0, 0, 0], [0, 0, 0]])

    T = Matrix([[1.5, 0], [0, 2]])
    p = Vector([5, 3])
    print("T.dot(p) = {}".format(T.dot(p))) #T.dot(p) = (7.5, 6)

    P = Matrix([[0, 4, 5], [0, 0, 3]])
    print("T.dot(P) = {}".format(T.dot(P))) #T.dot(P) = Matrix([[0.0, 6.0, 7.5], [0, 0, 6]])

    print("A.dot(B) = {}".format(matrix.dot(matrix2)))#A.dot(B) = Matrix([[19, 22], [43, 50]])
    print("B.dot(A) = {}".format(matrix2.dot(matrix)))#B.dot(A) = Matrix([[23, 34], [31, 46]])

    print("P.T = {}".format(P.T())) #P.T = Matrix([[0, 0], [4, 0], [5, 3]])

    I = Matrix.identity(2) #单位矩阵
    print(I)  #Matrix([[1, 0], [0, 1]])
    print("A.dot(I) = {}".format(matrix.dot(I)))  #A.dot(I) = Matrix([[1, 2], [3, 4]])
    print("I.dot(A) = {}".format(I.dot(matrix))) #I.dot(A) = Matrix([[1, 2], [3, 4]])

矩阵变换

import matplotlib.pyplot as plt
# from playLA.Matrix import Matrix
# from playLA.Vector import Vector
import math


if __name__ == "__main__":

    points = [[0, 0], [0, 5], [3, 5], [3, 4], [1, 4], [1, 3], [2, 3], [2, 2], [1, 2], [1, 0]]
    x = [point[0] for point in points]
    y = [point[1] for point in points]

    plt.figure(figsize=(5, 5)) #窗口
    plt.xlim(-10, 10)
    plt.ylim(-10, 10)
    plt.plot(x, y)
    # plt.show()

    P = Matrix(points)

    # T = Matrix([[2, 0], [0, 1.5]])  #缩放
    # T = Matrix([[1, 0], [0, -1]]) #x翻转
    # T = Matrix([[-1, 0], [0, 1]]) #y翻转
    # T = Matrix([[-1, 0], [0, -1]]) #原点对称
    # T = Matrix([[1, 0.5], [0, 1]]) #x错切
    T = Matrix([[1, 0], [0.5, 1]]) #y错切

    # theta = math.pi / 3
    # T = Matrix([[math.cos(theta), math.sin(theta)], [-math.sin(theta), math.cos(theta)]])

    # 逆时针旋转90度
    # theta = math.pi / -2
    # T = Matrix([[math.cos(theta), math.sin(theta)], [-math.sin(theta), math.cos(theta)]])

    # 根据矩阵表示空间的法则,直接写出的逆时针旋转90度的变换矩阵
    # T = Matrix([[0, -1], [1, 0]])



    P2 = T.dot(P.T()) #转置
    plt.plot([P2.col_vector(i)[0] for i in range(P2.col_num())],
             [P2.col_vector(i)[1] for i in range(P2.col_num())])
    plt.show()

用numpy实现

import numpy as np

if __name__ == "__main__":

    # 矩阵的创建
    A = np.array([[1, 2], [3, 4]])
    print(A)
    # [[1 2]
    #  [3 4]]

    # 矩阵的属性
    print(A.shape) #(2, 2)
    print(A.T)
    # [[1 3]
    #  [2 4]]

    # 获取矩阵的元素
    print(A[1, 1]) #4
    print(A[0])
    print(A[:, 0])
    print(A[1, :])

    # 矩阵的基本运算
    B = np.array([[5, 6], [7, 8]])
    print(A + B)
    print(A - B)
    print(10 * A)
    print(A * 10)
    print(A * B)
    print(A.dot(B))

    p = np.array([10, 100])
    print(A + p)
    print(A + 1)

    print(A.dot(p))

    # 单位矩阵
    I = np.identity(2)
    print(I)
    print(A.dot(I))
    print(I.dot(A))

    # 逆矩阵
    invA = np.linalg.inv(A)
    print(invA)
    # [[-2.   1.]
    #  [1.5 - 0.5]]
    print(invA.dot(A))
    # [[1.0000000e+00 4.4408921e-16]
    #  [0.0000000e+00 1.0000000e+00]]
    print(A.dot(invA))
    # [[1.00000000e+00 1.11022302e-16]
    #  [0.00000000e+00 1.00000000e+00]]

    # 只有方针才可逆
    # C = np.array([[1, 2, 3], [4, 5, 6]])
    # np.linalg.inv(C)

消元

# from .Matrix import Matrix
# from .Vector import Vector
# from ._globals import is_zero


class LinearSystem:

    def __init__(self, A, b = None):

        assert b is None or A.row_num() == len(b), "row number of A must be equal to the length of b"
        self._m = A.row_num()#行
        self._n = A.col_num()#列

        if b is None:
            self.Ab = [A.row_vector(i) for i in range(self._m)]
        if isinstance(b, Vector):
            self.Ab = [Vector(A.row_vector(i).underlying_list() + [b[i]])
                        for i in range(self._m)]
        if isinstance(b, Matrix):
            self.Ab = [Vector(A.row_vector(i).underlying_list() + b.row_vector(i).underlying_list())
                       for i in range(self._m)]
        self.pivots = []  # 记录了pivots列表,用于存储主元的列索引。
    # 初始化线性方程组对象。
    # A是一个矩阵对象,表示线性方程组的系数矩阵;
    # b是一个向量或矩阵对象,表示线性方程组的常数项(可选).
    # 根据A和b的类型,将其转换为增广矩阵Ab,其中每个行向量是 A的行向量和b的对应行向量的连接。


    def _max_row(self, index_i, index_j, n):

        best, ret = abs(self.Ab[index_i][index_j]), index_i
        for i in range(index_i + 1, n):
            if abs(self.Ab[i][index_j]) > best:
                best, ret = abs(self.Ab[i][index_j]), i
        return ret

    # 在指定范围内查找具有最大绝对值的元素的行索引。
    # index_i 是起始行索引,index_j是列索引,n是结束行索引。返回具有最大绝对值元素的行索引。

    def _forward(self):

        i, k = 0, 0
        while i < self._m and k < self._n:
            # 看Ab[i][k]位置是否可以是主元
            max_row = self._max_row(i, k, self._m)
            self.Ab[i], self.Ab[max_row] = self.Ab[max_row], self.Ab[i]#交换

            if is_zero(self.Ab[i][k]):
                k += 1#下一列
            else:
                # 将主元归为一
                self.Ab[i] = self.Ab[i] / self.Ab[i][k]
                for j in range(i + 1, self._m):
                    self.Ab[j] = self.Ab[j] - self.Ab[j][k] * self.Ab[i]
                self.pivots.append(k)
                i += 1
    # 使用高斯消元法进行前向消元,将增广矩阵Ab转化为行最简形式。在过程中将主元归一化,并进行消元操作

    def _backward(self):

        n = len(self.pivots)
        for i in range(n - 1, -1, -1):
            k = self.pivots[i]
            # Ab[i][k]为主元
            for j in range(i - 1, -1, -1):
                self.Ab[j] = self.Ab[j] - self.Ab[j][k] * self.Ab[i]
    # 使用高斯约当消元法进行后向消元,进一步将增广矩阵 Ab 转化为行最简形式。

    def gauss_jordan_elimination(self):
        """如果有解,返回True;如果没有解,返回False"""
        self._forward()
        self._backward()

        for i in range(len(self.pivots), self._m):
            if not is_zero(self.Ab[i][-1]):
                return False
        return True
    # 调用 _forward 和  _backward  方法进行高斯约当消元,求解线性方程组。
    # 如果方程组有解,返回  True;如果方程组无解,返回 False。

    def fancy_print(self):
        for i in range(self._m):
            print(" ".join(str(self.Ab[i][j]) for j in range(self._n)), end=" ")
            print("|", self.Ab[i][-1])
            # 以更漂亮的格式打印增广矩阵  Ab,方便观察结果。

def inv(A):

    if A.row_num() != A.col_num():
        return None

    n = A.row_num()
    ls = LinearSystem(A, Matrix.identity(n))
    if not ls.gauss_jordan_elimination():
        return None

    invA = [[row[i] for i in range(n, 2*n)] for row in ls.Ab]
    return Matrix(invA)
    # 计算矩阵 A 的逆矩阵。
    # 首先检查 A 是否为方阵,如果不是,则返回 None。
    # 创建一个线性方程组对象 ls,以 A 和单位矩阵作为参数,使用高斯约当消元法求解.
    # 如果方程组无解,则返回 None.
    # 从线性方程组对象的增广矩阵 Ab 中提取逆矩阵的部分,并返回一个新的矩阵对象 invA.

def rank(A):

    ls = LinearSystem(A)
    ls.gauss_jordan_elimination()

    zero = Vector.zero(A.col_num())
    return sum([row != zero for row in ls.Ab])
    # 计算矩阵 A 的秩。
    # 创建一个线性方程组对象 ls,以 A 作为参数,使用高斯约当消元法求解。
    # 在消元过程中,统计非零行向量的数量,并返回该数量作为矩阵 A 的秩.
# from playLA.Matrix import Matrix
# from playLA.Vector import Vector
# from playLA.LinearSystem import LinearSystem
# from playLA.LinearSystem import inv, rank


if __name__ == "__main__":

    A = Matrix([[1, 2, 4], [3, 7, 2], [2, 3, 3]])
    b = Vector([7, -11, 1])
    ls = LinearSystem(A, b)
    ls.gauss_jordan_elimination()
    ls.fancy_print()
    print()
    # [-1, -2, 3]

    A2 = Matrix([[1, -3, 5], [2, -1, -3], [3, 1, 4]])
    b2 = Vector([-9, 19, -13])
    ls2 = LinearSystem(A2, b2)
    ls2.gauss_jordan_elimination()
    ls2.fancy_print()
    print()
    # [2, -3, -4]

    A3 = Matrix([[1, 2, -2], [2, -3, 1], [3, -1, 3]])
    b3 = Vector([6, -10, -16])
    ls3 = LinearSystem(A3, b3)
    ls3.gauss_jordan_elimination()
    ls3.fancy_print()
    print()
    # [-2, 1, -3]

    A4 = Matrix([[3, 1, -2], [5, -3, 10], [7, 4, 16]])
    b4 = Vector([4, 32, 13])
    ls4 = LinearSystem(A4, b4)
    ls4.gauss_jordan_elimination()
    ls4.fancy_print()
    print()
    # [3, -4, 0.5]

    A5 = Matrix([[6, -3, 2], [5, 1, 12], [8, 5, 1]])
    b5 = Vector([31, 36, 11])
    ls5 = LinearSystem(A5, b5)
    ls5.gauss_jordan_elimination()
    ls5.fancy_print()
    print()
    # [3, -3, 2]


    A6 = Matrix([[1, 1, 1], [1, -1, -1], [2, 1, 5]])
    b6 = Vector([3, -1, 8])
    ls6 = LinearSystem(A6, b6)
    ls6.gauss_jordan_elimination()
    ls6.fancy_print()
    print()
    # [1, 1, 1]


    print("--------------------------------------------------------------")
    A7 = Matrix([[1, -1, 2, 0, 3],
                 [-1, 1, 0, 2, -5],
                 [1, -1, 4, 2, 4],
                 [-2, 2, -5, -1, -3]])
    b7 = Vector([1, 5, 13, -1])
    ls7 = LinearSystem(A7, b7)
    ls7.gauss_jordan_elimination()
    ls7.fancy_print()
    print()
    # 1.0 -1.0 0.0 -2.0 0.0 | -15.0
    # 0.0  0.0 1.0  1.0 0.0 | 5.0
    # 0.0  0.0 0.0  0.0 1.0 | 2.0
    # 0.0  0.0 0.0  0.0 0.0 | 2.220446049250313e-16

    A8 = Matrix([[2, 2],
                 [2, 1],
                 [1, 2]])
    b8 = Vector([3, 2.5, 7])
    ls8 = LinearSystem(A8, b8)
    if not ls8.gauss_jordan_elimination():
        print("No Solution!")
    ls8.fancy_print()
    print()
    # No Solution!
    # 1.0  0.0 | 1.0
    # -0.0 1.0 | 0.5
    # 0.0  0.0 | 5.0

    A = Matrix([[1, 2], [3, 4]])
    invA = inv(A)
    print(invA)
    #-2 1
    # 1 -0.5
    print(A.dot(invA))
    # 1 0
    # 0 1
    print(invA.dot(A))
    # 1 0
    # 0 1
    print()

    print("rank A8 = {}".format(rank(A8))) #rank A8 = 2
    print("rank A7 = {}".format(rank(A7))) #rank A7 = 3
    print("rank A6 = {}".format(rank(A6))) #rank A6 = 3

强烈推荐5-9 总结:看待矩阵的四个重要视角_哔哩哔哩_bilibili

数据 系统 变换 空间(真的很透彻)

强烈推荐6-6 直观理解线性方程组解的结构(1)_哔哩哔哩_bilibili

视频里所有的直观理解都很好

下面是从p58开始的一些我不大熟悉的地方

 p58 LU分解

通过python掌握线性代数_第2张图片

通过python掌握线性代数_第3张图片

通过python掌握线性代数_第4张图片

 通过python掌握线性代数_第5张图片

 LU分解目的是提高效率

代码

#from .Matrix import Matrix
#from .Vector import Vector
#from ._globals import is_zero


def lu(matrix):
    assert matrix.row_num() == matrix.col_num(), "matrix must be a square matrix"
    # 检查matrix是否为方阵,如果不是,则抛出断言错误
    n = matrix.row_num()
    A = [matrix.row_vector(i) for i in range(n)]
    # 创建一个与 matrix 大小相同的矩阵A,其中每个行向量都是matrix的行向量。
    L = [[1.0 if i == j else 0.0 for i in range(n)] for j in range(n)]
    # 创建一个与matrix大小相同的单位下三角矩阵 L,其中主对角线上的元素为1,其他元素为0。

    for i in range(n):
        # 看A[i][i]位置是否可以是主元.对于每个对角线上的元素 A[i][i],检查是否为零。如果为零,表示主元为零,无法进行LU分解,返回 None(上三角为空,下三角为空)。
        if is_zero(A[i][i]):
            return None, None
        else:
            for j in range(i + 1, n):
                p = A[j][i] / A[i][i]
                A[j] = A[j] - p * A[i]
                L[j][i] = p
    # 否则,对于当前行i的下方的每一行j,计算倍数p,使得A[j][i] = p * A[i][i],并将其存储在矩阵L的相应位置
    # 然后,通过从第i行中减去倍数p乘以第 i行,将矩阵 A进行消元操作。
    return Matrix(L), Matrix([A[i].underlying_list() for i in range(n)])
    # 返回矩阵 L 和经过消元后的矩阵 A

#from playLA.Matrix import Matrix
#from playLA.LU import lu


if __name__ == "__main__":
    A1 = Matrix([[1, 2, 3], [4, 5, 6], [3, -3, 5]])
    L1, U1 = lu(A1)
    print(L1) #Matrix([[1.0, 0.0, 0.0], [4.0, 1.0, 0.0], [3.0, 3.0, 1.0]])
    print(U1) #上三角up Matrix([[1, 2, 3], [0.0, -3.0, -6.0], [0.0, 0.0, 14.0]])
    print(L1.dot(U1)) #验证 Matrix([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [3.0, -3.0, 5.0]])
    print()

    A2 = Matrix([[1, 4, 5, 3], [5, 22, 27, 11], [6, 19, 27, 31], [5, 28, 35, -8]])
    L2, U2 = lu(A2)
    print(L2)
    print(U2)
    print(L2.dot(U2))

    print()

    A3 = Matrix([[1, 2, 3], [3, 7, 14], [4, 13, 38]])
    L3, U3 = lu(A3)
    print(L3)
    print(U3)
    print(L3.dot(U3))

    print()

通过python掌握线性代数_第6张图片

 通过python掌握线性代数_第7张图片

 PLU分解,更多

p63 线性组合

通过python掌握线性代数_第8张图片

 通过python掌握线性代数_第9张图片

 通过python掌握线性代数_第10张图片

 通过python掌握线性代数_第11张图片

 通过python掌握线性代数_第12张图片

 通过python掌握线性代数_第13张图片

 通过python掌握线性代数_第14张图片

通过python掌握线性代数_第15张图片

通过python掌握线性代数_第16张图片

 通过python掌握线性代数_第17张图片

 

 p65直观理解(推荐)

通过python掌握线性代数_第18张图片

 

通过python掌握线性代数_第19张图片

 

生成空间

通过python掌握线性代数_第20张图片

 

 通过python掌握线性代数_第21张图片

 通过python掌握线性代数_第22张图片

 通过python掌握线性代数_第23张图片

 通过python掌握线性代数_第24张图片

 通过python掌握线性代数_第25张图片

 

 通过python掌握线性代数_第26张图片

 

通过python掌握线性代数_第27张图片

 通过python掌握线性代数_第28张图片

第八章总结8-8 本章小结:形成自己的知识图谱_哔哩哔哩_bilibili

 

 

第九章

通过python掌握线性代数_第29张图片

 通过python掌握线性代数_第30张图片

 通过python掌握线性代数_第31张图片

 

子空间

通过python掌握线性代数_第32张图片

 通过python掌握线性代数_第33张图片

 通过python掌握线性代数_第34张图片

 通过python掌握线性代数_第35张图片

 通过python掌握线性代数_第36张图片x

 

 通过python掌握线性代数_第37张图片

 

 通过python掌握线性代数_第38张图片

 

通过python掌握线性代数_第39张图片

 

通过python掌握线性代数_第40张图片

 

通过python掌握线性代数_第41张图片

 通过python掌握线性代数_第42张图片

 通过python掌握线性代数_第43张图片

 

 通过python掌握线性代数_第44张图片

 

通过python掌握线性代数_第45张图片

 

 

 零空间

通过python掌握线性代数_第46张图片

 

通过python掌握线性代数_第47张图片

 通过python掌握线性代数_第48张图片

 

通过python掌握线性代数_第49张图片

 通过python掌握线性代数_第50张图片

 

通过python掌握线性代数_第51张图片

 

通过python掌握线性代数_第52张图片

 

通过python掌握线性代数_第53张图片

 通过python掌握线性代数_第54张图片

 通过python掌握线性代数_第55张图片

 通过python掌握线性代数_第56张图片

 

通过python掌握线性代数_第57张图片

 

通过python掌握线性代数_第58张图片

 

通过python掌握线性代数_第59张图片

通过python掌握线性代数_第60张图片

 

 通过python掌握线性代数_第61张图片

 

 通过python掌握线性代数_第62张图片

 通过python掌握线性代数_第63张图片

 

通过python掌握线性代数_第64张图片

 ​​​​​​​通过python掌握线性代数_第65张图片

 

 施密特正交通过python掌握线性代数_第66张图片

 

# from .Matrix import Matrix
# from .LinearSystem import rank


def gram_schmidt_process(basis):#对给定的向量组 basis 进行Gram-Schmidt正交化过程

    matrix = Matrix(basis)#将向量组转换为矩阵
    assert rank(matrix) == len(basis)
    # 检查矩阵的秩是否等于向量组的长度,如果不相等,则抛出断言错误,表示向量组线性相关,无法进行正交化。
    res = [basis[0]]#存储正交化后的向量。第一个向量作为初始向量 p,将其添加到 res 中
    for i in range(1, len(basis)):
        p = basis[i]
        for r in res:
            p = p - basis[i].dot(r) / r.dot(r) * r
        #将其与已经正交化的向量进行投影,然后将投影后的部分从 basis[i] 中减去
        res.append(p) #将正交化后的向量 p 添加到 res 中。
    return res;


def qr(A):#计算矩阵 A 的QR分解

    assert A.row_num() == A.col_num(), "A must be square"
    #首先检查 A 是否为方阵,如果不是,则抛出断言错误。
    basis = [A.col_vector(i) for i in range(A.col_num())];
    #列表 basis,其中每个元素为 A 的列向量
    P = gram_schmidt_process(basis)#得到正交化后的向量组 P。
    Q = Matrix([v / v.norm() for v in P]).T()
    #将向量组 P 中的每个向量除以其自身的范数,得到单位向量组 Q。
    R = Q.T().dot(A)
    #将 Q 转置后与 A 进行矩阵乘法,得到上三角矩阵 R。
    return Q, R # Q 是正交矩阵,R 是上三角矩阵。
# from playLA.Vector import Vector
# from playLA.GramSchmidtProcess import gram_schmidt_process
# from itertools import product


if __name__ == "__main__":

    basis1 = [Vector([2, 1]), Vector([1, 1])]
    res1 = gram_schmidt_process(basis1)
    for row in res1:
        print(row)
    #(2, 1)
    # (-0.19999999999999996, 0.4)

    # 标准正交基
    res1 = [row / row.norm() for row in res1]
    for row in res1:
        print(row)
        #(0.8944271909999159, 0.4472135954999579)
        #(-0.44721359549995787, 0.894427190999916)
    print(res1[0].dot(res1[1])) #1.1102230246251565e-16(0)
    print()


    basis2 = [Vector([2, 3]), Vector([4, 5])]
    res2 = gram_schmidt_process(basis2)
    res2 = [row / row.norm() for row in res2]
    for row in res2:
        print(row)
    print(res2[0].dot(res2[1]))
    print()
    #(0.5547001962252291, 0.8320502943378437)
    # (0.8320502943378439, -0.5547001962252287)
    # 4.996003610813204e-16

    basis3 = [Vector([1, 0, 1]), Vector([3, 1, 1]), Vector([-1, -1, -1])]
    res3 = gram_schmidt_process(basis3)
    res3 = [row / row.norm() for row in res3]
    for row in res3:
        print(row)
    print(sum(res3[i].dot(res3[j]) for i, j in product(range(3), repeat=2) if i != j))
    print()
    #(0.7071067811865475, 0.0, 0.7071067811865475)
    # (0.5773502691896258, 0.5773502691896258, -0.5773502691896258)
    # (0.40824829046386296, -0.816496580927726, -0.40824829046386296)
    # -1.1102230246251565e-16

    basis4 = [Vector([1, 1, 5, 2]), Vector([-3, 3, 4, -2]), Vector([-1, -2, 2, 5])]
    res4 = gram_schmidt_process(basis4)
    res4 = [row / row.norm() for row in res4]
    for row in res4:
        print(row)
    print(sum(res4[i].dot(res4[j]) for i, j in product(range(3), repeat=2) if i != j))
    print()
    #(0.1796053020267749, 0.1796053020267749, 0.8980265101338746, 0.3592106040535498)
    # (-0.6447334317039531, 0.4554538921211412, 0.2602593669263664, -0.5560086475245101)
    # (-0.7426488253165523, -0.32682633521100585, -0.019776923309897908, 0.584179888538524 )
    # 5.551115123125783e-17

    basis5 = [Vector([1, 2, 3, 4]), Vector([2, 1, 1, 0]), Vector([3, 0, -1, 3])]
    res5 = gram_schmidt_process(basis5)
    res5 = [row / row.norm() for row in res5]
    for row in res5:
        print(row)
    print(sum(res5[i].dot(res5[j]) for i, j in product(range(3), repeat=2) if i != j))
    print()
    # (0.18257418583505536, 0.3651483716701107, 0.5477225575051661, 0.7302967433402214)
    # (0.8454337760700726, 0.2552252908890785, 0.1435642261251067, -0.44664425905588745)
    # (0.4725854085508103, -0.2953658803442565, -0.6498049367573643, 0.5168902906024487)
    # -2.7755575615628914e-16

P93 QR分解

通过python掌握线性代数_第67张图片

 

通过python掌握线性代数_第68张图片

 通过python掌握线性代数_第69张图片

 通过python掌握线性代数_第70张图片

 通过python掌握线性代数_第71张图片

 通过python掌握线性代数_第72张图片

 

# from playLA.Matrix import Matrix
# from playLA.GramSchmidtProcess import qr


if __name__ == "__main__":

    A1 = Matrix([[1, 1, 2],
                [1, 1, 0],
                [1, 0, 0]])
    Q1, R1 = qr(A1)
    print(Q1)
    print(R1)
    print(Q1.dot(R1))
    print()
    # Matrix([[0.5773502691896258, 0.408248290463863, 0.7071067811865475],
    #         [0.5773502691896258, 0.408248290463863, -0.7071067811865475],
    #         [0.5773502691896258, -0.8164965809277259, 0.0]])
    # Matrix([[1.7320508075688776, 1.1547005383792517, 1.1547005383792517],
    #         [1.1102230246251565e-16, 0.816496580927726, 0.816496580927726], [0.0, 0.0, 1.414213562373095]])
    # Matrix(
    #     [[1.0000000000000002, 1.0000000000000002, 2.0],
    #     [1.0000000000000002, 1.0000000000000002, 4.440892098500626e-16],
    #      [1.0000000000000002, 2.220446049250313e-16, 2.220446049250313e-16]])

    A2 = Matrix([[2, -1, -1],
                 [2, 0, 2],
                 [2, -1, 3]])
    Q2, R2 = qr(A2)
    print(Q2)
    print(R2)
    print(Q2.dot(R2))
    # Matrix([[0.5773502691896258, -0.408248290463863, -0.7071067811865475], [0.5773502691896258, 0.8164965809277259, 1.1775693440128314e-16], [0.5773502691896258, -0.408248290463863, 0.7071067811865476]])
    # Matrix([[3.4641016151377553, -1.1547005383792517, 2.3094010767585034], [-2.220446049250313e-16, 0.816496580927726, 0.8164965809277258], [4.440892098500626e-16, -1.1102230246251565e-16, 2.8284271247461907]])
    # Matrix([[2.0, -1.0000000000000002, -1.0], [2.0000000000000004, -2.220446049250313e-16, 2.0000000000000004], [2.000000000000001, -1.0000000000000002, 3.000000000000001]])

P94总结10-8 本章小结和更多和投影相关的话题_哔哩哔哩_bilibili

通过python掌握线性代数_第73张图片

最小二乘法

通过python掌握线性代数_第74张图片

 

通过python掌握线性代数_第75张图片

 通过python掌握线性代数_第76张图片

 

通过python掌握线性代数_第77张图片

  ​​​​​​​通过python掌握线性代数_第78张图片

 

 

通过python掌握线性代数_第79张图片

 通过python掌握线性代数_第80张图片

 

 

 

通过python掌握线性代数_第81张图片

 通过python掌握线性代数_第82张图片

 

通过python掌握线性代数_第83张图片

 通过python掌握线性代数_第84张图片

通过python掌握线性代数_第85张图片

 通过python掌握线性代数_第86张图片

通过python掌握线性代数_第87张图片

通过python掌握线性代数_第88张图片

图形学+计算机视觉

通过python掌握线性代数_第89张图片

通过python掌握线性代数_第90张图片

 

 行列式(按行排列)

通过python掌握线性代数_第91张图片

 通过python掌握线性代数_第92张图片

 

 

 通过python掌握线性代数_第93张图片

import numpy as np
from numpy.linalg import eig


if __name__ == "__main__":

    A1 = np.array([[4, -2],
                   [1, 1]]);
    eigenvalues1, eigenvectors1 = eig(A1);
    print(eigenvalues1)
    print(eigenvectors1)
    print()
    #[3. 2.]
    # [[0.89442719 0.70710678]
    #  [0.4472136  0.70710678]]


    # 关于y=x翻转
    A2 = np.array([[0, 1],
                   [1, 0]]);
    eigenvalues2, eigenvectors2 = eig(A2);
    print(eigenvalues2)
    print(eigenvectors2)
    print()
    # [1. - 1.]
    # [[0.70710678 - 0.70710678]
    #  [0.70710678  0.70710678]]


    # 旋转90度
    A3 = np.array([[0, -1],
                   [1, 0]]);
    eigenvalues3, eigenvectors3 = eig(A3);
    print(eigenvalues3)
    print(eigenvectors3)
    print()
    # [0. + 1.j 0. - 1.j]
    # [[0.70710678 + 0.j     0.70710678 - 0.j]
    #  [0. - 0.70710678j     0. + 0.70710678j]]

    # 单位矩阵
    A4 = np.array([[1, 0],
                   [0, 1]]);
    eigenvalues4, eigenvectors4 = eig(A4);
    print(eigenvalues4)
    print(eigenvectors4)
    print()
    # [1. 1.]
    # [[1. 0.]
    #  [0. 1.]]

    # 几何重数为1
    A5 = np.array([[3, 1],
                   [0, 3]]);
    eigenvalues5, eigenvectors5 = eig(A5);
    print(eigenvalues5)
    print(eigenvectors5)
    print()
    # [3. 3.]
    # [[1.00000000e+00 - 1.00000000e+00]
    #  [0.00000000e+00  6.66133815e-16]]


 通过python掌握线性代数_第94张图片

 

通过python掌握线性代数_第95张图片

 

import numpy as np
from numpy.linalg import eig, inv
# from playLA.LinearSystem import rank
# from playLA.Matrix import Matrix


def diagonalize(A):

    assert A.ndim == 2 #二维
    assert A.shape[0] == A.shape[1] #长宽相等

    eigenvalues, eigenvectors = eig(A)  #特征值和特征向量

    P = eigenvectors
    if rank(Matrix(P.tolist())) != A.shape[0]:
        print("Matrix can not be diagonalized!")
        return None, None, None
    #rank函数来检查特征向量矩阵P的秩是否等于矩阵A的维度。
    # 如果不相等,说明矩阵A不可对角化,打印出相应的提示信息并返回None。

    D = np.diag(eigenvalues)
    #对角矩阵D,其中对角线上的元素为特征值数组eigenvalues的值。
    Pinv = inv(P) #P的逆矩阵,保存在变量Pinv中.

    return P, D, Pinv


if __name__ == "__main__":

    A1 = np.array([[4, -2],
                   [1, 1]])
    P1, D1, Pinv1 = diagonalize(A1)
    print(P1)
    #[[0.89442719 0.70710678]
    # [0.4472136  0.70710678]]
    print(D1)
    #[[3. 0.]
    #[0. 2.]]
    print(Pinv1)
    #[[ 2.23606798 -2.23606798]
    #[-1.41421356  2.82842712]]
    print(P1.dot(D1).dot(Pinv1))
    #[[ 4. -2.]
    #[ 1.  1.]]
    print()


    A2 = np.array([[3, 1],
                   [0, 3]])
    P2, D2, Pinv2 = diagonalize(A2)
    print(P2)
    print(D2)
    print(Pinv2)
    print()
    #Matrix can not be diagonalized!
    # None
    # None
    # None

SVD分解

import numpy as np
from scipy.linalg import svd


if __name__ == "__main__":

    A = np.array([[1, 2],
                  [3, 4],
                  [5, 6]])
    U, s, VT = svd(A)
    print(U)
     #[[-0.2298477   0.88346102  0.40824829]
     # [-0.52474482  0.24078249 -0.81649658]
     # [-0.81964194 -0.40189603  0.40824829]]
    print(s)
    #[9.52551809 0.51430058]
    print(VT)
    #[[-0.61962948 -0.78489445]
    # [-0.78489445  0.61962948]]
    print()


    Sigma = np.zeros(A.shape) #0
    for i in range(len(s)):
        Sigma[i][i] = s[i]  #对角线
    print(Sigma)
    #[[9.52551809 0.        ]
     # [0.         0.51430058]
     # [0.         0.        ]]
    print(U.dot(Sigma).dot(VT))
    #[[1. 2.]
     # [3. 4.]
     # [5. 6.]]

 

你可能感兴趣的:(python,开发语言,线性代数)