使用python实现矩阵

这篇具有很好参考价值的文章主要介绍了使用python实现矩阵。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

矩阵

使用python构建一个类,模拟矩阵,可以进行各种矩阵的计算,与各种方便的用法

init

from array import array
class Matrix:
    def __init__(self, matrix: 'a list of one dimension', shape: 'a tuple of shape' = None, 
                 dtype: 'data type code' = 'd'):
        # matrix一个包含所有元素的列表,shape指定形状,默认为列向量,dtype是数据类型
        # 使用一个数组模拟矩阵,通过操作这个数组完成矩阵的运算
        self.shape = (len(matrix), 1)
        if shape:
            self.shape = shape
        self.array = array(dtype, matrix)

getitem

由于矩阵是一个二维数组,应当支持诸如matrix[1, 2],matrix[1:3, 2],matrix[1:3, 2:4]之类的取值
所以我们需要使用slice类的indice方法实现__getitem__,并支持切片

    def __getitem__(self, item: 'a index of two dimensions'):
        # 使用slice类的indices方法,实现二维切片
        rows, cols = item
        # 下面对传入的指针或者切片进行处理,使其可以统一处理
        if isinstance(rows, slice):
            rows = rows.indices(self.shape[0])
        else:
            rows = (rows, rows + 1)
        if isinstance(cols, slice):
            cols = cols.indices(self.shape[1])
        else:
            cols = (cols, cols + 1)
        res = []
        shape = (len(range(*rows)), len(range(*cols)))  # 新矩阵的形状
        # 通过遍历按照顺序将元素加入新的矩阵
        for row in range(*rows):
            for col in range(*cols):
                index = row * self.shape[1] + col
                res.append(self.array[index])
        if len(res) == 1:
        # 若是数则返回数
            return res[0]
        # 若是矩阵则返回矩阵
        return Matrix(res, shape)

由于要支持切片,所以需要在方法中新建一个矩阵用于返回值

setitem

由于没有序列协议的支持,我们需要自己实现__setitem__

    def __setitem__(self, key: 'a index or slice of two dimensions', value):
        # 使用slice类的indices方法,实现二维切片的广播赋值
        rows, cols = key
        if isinstance(rows, slice):
            rows = rows.indices(self.shape[0])
        else:
            rows = (rows, rows + 1)
        if isinstance(cols, slice):
            cols = cols.indices(self.shape[1])
        else:
            cols = (cols, cols + 1)
        if isinstance(value, Matrix):
            # 对于传入的值是矩阵,则需要判断形状
            if value.shape != (len(range(*rows)), len(range(*cols))):
                raise ShapeError
            # 使用x,y指针取出value中的值赋给矩阵
            x = -1
            for row in range(*rows):
                x += 1
                y = -1
                for col in range(*cols):
                    y += 1
                    index = row * self.shape[1] + col
                    self.array[index] = value[x, y]
        else:
            for row in range(*rows):
                for col in range(*cols):
                    index = row * self.shape[1] + col
                    self.array[index] = value

若传入的value是一个数,这里的逻辑基本与__getitem__相同,实现了广播。
而若传入的是一个矩阵,则需要判断形状,对对应的元素进行赋值,这是为了方便LU分解。

reshape

reshape用于改变形状,对于上面的实现方法,只需要改变matrix.shape就可以了
注意改变前后的总元素数应当一致

    def reshape(self, shape: 'a tuple of shape'):
        if self.shape[0] * self.shape[1] != shape[0] * shape[1]:
            raise ShapeError
        self.shape = shape

repr

实现__repr__方法,较为美观的打印矩阵

    def __repr__(self):
        shape = self.shape
        _array = self.array
        return "[" + ",\n".join(str(list(_array[i * shape[1]:(i + 1) * shape[1]])) for i in range(shape[0])) + "]"

add 与 mul

对于加法与乘法的支持,这里的乘法是元素的乘法,不是矩阵的乘法
同样的,实现广播

    def __add__(self, other):
        shape = self.shape
        res = zeros(shape)  # 创建一个新的零矩阵,用于返回
        if isinstance(other, Matrix):
            # 实现同样形状的矩阵元素之间的加法
            if self.shape != other.shape:
                # 如果矩阵的形状对不上,就返回错误
                raise ShapeError
            for i in range(shape[0]):
                for j in range(shape[1]):
                    res[i, j] = self[i, j] + other[i, j]
        else:
            # 实现广播
            for i in range(shape[0]):
                for j in range(shape[1]):
                    res[i, j] = self[i, j] + other
        return res

    def __mul__(self, other):
        shape = self.shape
        res = zeros(shape)  # 创建一个新的零矩阵,用于返回
        if isinstance(other, Matrix):
            # 实现同样形状的矩阵元素之间的乘法
            if self.shape != other.shape:
                # 如果矩阵的形状对不上,就返回错误
                raise ShapeError
            for i in range(shape[0]):
                for j in range(shape[1]):
                    res[i, j] = self[i, j] * other[i, j]
        else:
            # 实现广播
            for i in range(shape[0]):
                for j in range(shape[1]):
                    res[i, j] = self[i, j] * other
        return res

matmul

matmul矩阵乘法,运算符为@

    def __matmul__(self, other):
        # 实现矩阵的乘法
        if self.shape[1] != other.shape[0]:
            # 对形状进行判断
            raise ShapeError
        if self.shape[0] == 1 and other.shape[1] == 1:
            # 行向量与列向量的乘积,就是它们的数量积
            length = self.shape[1]
            return sum(self[0, i] * self[i, 0] for i in range(length))
        res = []
        shape = (self.shape[0], other.shape[1])
        for i in range(shape[0]):
            for j in range(shape[1]):
                # 将两个矩阵分别按行向量与列向量分块,然后相乘
                try:
                    # 由于切片返回的可能是数,而数不支持'@'运算符,所以使用异常处理语句
                    res.append(self[i, :] @ other[:, j])
                except TypeError:
                    res.append(self[i, :] * other[:, j])
        return Matrix(res, shape)

将矩阵分成向量进行矩阵乘法

LU分解

用属性self._lu,构建一个新的矩阵,作为LU分解表。self._lu并不会在初始化时创建,而是在需要用到LU分解表时计算。
同时,我们维护一个self.changed属性,用来判断在需要用到LU分解表时是否需要重新进行LU分解

    def __init__(self, matrix: 'a list of one dimension', shape: 'a tuple of shape' = None,
                 dtype: 'data type code' = "d"):
        # matrix一个包含所有元素的列表,shape指定形状默认为列向量,dtype是数据类型
        # 使用一个数组模拟矩阵,通过操作这个数组完成矩阵的运算
        self.shape = (len(matrix), 1)
        if shape:
            self.shape = shape
        self.array = array(dtype, matrix)

        self._changed = True
        self._primary = list(range(shape[0])) # 只进行行交换

显然,当我们修改了矩阵的元素后就需要重新进行LU分解,重写 setitem ,在开始时修改self.changed属性

    def __setitem__(self, key: 'a index or slice of two dimensions', value):
        # 使用slice类的indices方法,实现二维切片的广播赋值
        self._change = True
        ...

在lu分解中需要选择主元,用属性self._primary储存当前矩阵的主元表,因此我们要重写 getitemsetitem

...
row = self._primary[row]  # 通过主元表进行赋值,将行换为
index = row * self.shape[1] + col
...

下面,我们来实现LU分解

    def _primary_update(self, k):
        # 选择绝对值最大的数作为主元
        max_val = -777
        max_index = 0
        for i in range(k, self.shape[0]):
            x = abs(self[i, k])
            if x > max_val:
                max_val = x
                max_index = i
        self._primary[k], self._primary[max_index] = self._primary[max_index], self._primary[k]

    def _lu_factorization(self):
        self._lu = Matrix(self.array, self.shape) # 新建一个矩阵储存LU分解表
        rows, cols = self.shape
        _lu = self._lu
        step = min(rows, cols)
        for k in range(step):
            if _lu[k, k] == 0:
                # 如果当前对角元素为0,就需要更换主元
                _lu._primary_update(k)
            if _lu[k, k] == 0:
                # 如果更换主元之后仍然为0,就说明该列全为0,跳过
                break
            x = 1 / _lu[k, k]
            _lu[k + 1:, k] *= x
            for i in range(k + 1, rows):
                for j in range(k + 1, cols):
                    _lu[i, j] = _lu[i, j] - _lu[i, k] * _lu[k, j]

转置

用一个方法实现转置,而不是维护一个属性

    def trans(self):
        shape = self.shape[::-1]
        res = zeros(shape) # 创建一个零矩阵用于返回
        for i in range(shape[0]):
            for j in range(shape[1]):
                res[i, j] = self[j, i]
        return res

利用LU分解求行列式

原矩阵的行列式就是L与U的对角元素的乘积

    def det(self):
        if self.shape[0] != self.shape[1]:
            raise ShapeError
        if self._changed:
            self._lu_factorization()
            self._changed = False
        res = 1
        for i in range(self.shape[0]):
            res *= self[i, i]
        return res

利用LU分解解线性方程组

利用LU分解可以快速地解出线性方程组文章来源地址https://www.toymoban.com/news/detail-446639.html

    def linear_equation(self, y):
        # 利用LU分解表解方程
        if not self.det():
            # 不考虑扁平化的情况,即使可能有解
            raise DetError
        lu = self._lu
        length = self.shape[1]
        z = [0]*length # 先解 L @ z = y
        for i in range(length):
            z_i = y[i, 0]
            for j in range(i):
                z_i -= z[j] * lu[i, j]
            z[i] = z_i
        x = [0]*length # 再解 U @ x = z
        for i in range(length - 1, -1, -1):
            x_i = z[i]
            for j in range(length - 1, i, -1):
                x_i -= x[j] * lu[i, j]
            x[i] = x_i / lu[i, i]
        return Matrix(x, (length, 1))

到了这里,关于使用python实现矩阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 矩阵乘法,python简易实现

    1.首先,先了解下矩阵乘法最基本的工作原理,可简易得理解成 C矩阵(i, j)的值是 由A矩阵 i 行依次与B矩阵 j 列相乘的求和,即:  2.demo实现 3、基于矩阵结果是行和列的对应相乘的累和迭代,所以选择依次增加,核心算法:      其中,选取 i、j、k进行循环与迭代,k作为中

    2024年02月11日
    浏览(40)
  • 矩阵加法python实现

    加法即对应元素相加,要求两个矩阵的形状⼀样: C = A + B, Ci,j = Ai,j + Bi,j 数乘即一个标量与矩阵每个元素相乘: D = a · B + c, Di,j = a · Bi,j + c 有时我们允许矩阵和向量相加的,得到⼀个矩阵,把 b 加到了 A 的每⼀⾏上,本质上是构造了⼀个将 b 按⾏复制的⼀个新矩阵,这种机

    2024年02月15日
    浏览(15)
  • 转换矩阵、平移矩阵、旋转矩阵关系以及python实现旋转矩阵、四元数、欧拉角之间转换

    由于在平时总是或多或少的遇到平移旋转的问题,每次都是现查资料,然后查了忘,忘了继续查,这次弄明白之后干脆写一篇文章,给人方便同时于己方便,后续如有扩充或变动也方便添加。 假设有两个向量 a 1 = ( x 1 , y 1 , z 1 ) a_1 = (x_1, y_1, z_1) a 1 ​ = ( x 1 ​ , y 1 ​ , z 1 ​

    2024年02月03日
    浏览(79)
  • python实现混淆矩阵(numpy)

    假设有A、B、C、D、E五个类别 step1:将pred和label进行一对一组合 Step2:遍历list_pred_label,将其中的类别转为混淆矩阵索引(A:0,B:1,C:2,D:3,E:4) step3:对混淆矩阵进行赋值

    2024年02月12日
    浏览(38)
  • 如何保存矩阵?python代码实现

    机器学习中的参数矩阵如何保存??当脱离了dl的框架后,菜鸟表示啥都不会。。 可以借用scipy包的savemat函数保存,loadmat函数读取; 首先要确保有scipy这个包,没有就安装一下 pip install scipy ,我这里的版本是1.7; Talk is cheap ,show me the code~ 第二种实现方式: #利用pickle实现,代

    2024年02月12日
    浏览(33)
  • 用Python实现矩阵运算【学习笔记】

    Pandas:Python中一个强大的分析结构化数据的工具集,可用于快速实现数据的导入/导出,索引。 Matplotlib:Python基础绘图库,几行代码即可生成绘图,直方图、条形图、散点图等。 NumPy:使用Python进行科学计算的基础软件包。核心:基于N维数组对象ndarray的数组运算。 现有矩阵

    2024年02月11日
    浏览(47)
  • python实现邻接矩阵转邻接表

    2024年02月01日
    浏览(37)
  • 【Python】矩阵乘法3种实现方案

    结论: 1、@ 符在numpy里就是矩阵乘法的意思,也是dot()的意思。 2、用这个 @ 运算符可以不用再使用matmult方法 3、一般来说,@ 比.dot()方法要慢一点点。dot是numpy里的函数,主要用于求向量相乘,矩阵乘法,矩阵与向量乘法。   内积,点积,乘法, 点积 对于元素相乘并相加,

    2024年02月12日
    浏览(50)
  • 如何使用Python从零开始构建游戏

    作者:禅与计算机程序设计艺术 游戏开发是一个庞大的领域,其涉及到许多领域如数学、计算机图形学、音视频等等,本文只讨论游戏编程,不涉及到其他相关领域知识。 游戏编程可以分成以下几步: 游戏逻辑 渲染 物理引擎 AI 用户交互 游戏中可能会用到不同的技术或框架

    2024年02月08日
    浏览(43)
  • 逆透视变换——变换矩阵的Python实现

    透视变换原理和变换矩阵的python实现 个人理解,可能有误,欢迎讨论。 进行透视变换,需要选择四个点,这些点定义了一个长方形,但是在原始图像中由于照相角度等问题,它并没有呈现出是一个长方形,为了变换视角,我们需要进行透视变换。 透视变换本质上是将图片从

    2024年02月02日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包