【问题标题】:numpy - Inverse of a matrix/array filled with Fractions - Errornumpy - 用分数填充的矩阵/数组的逆 - 错误
【发布时间】:2021-09-18 23:12:24
【问题描述】:

我正在尝试使用 numpy 对表示为 numpy 数组的矩阵执行操作。
我将分数作为这些矩阵中的元素。

似乎一切正常,直到我尝试找到逆向。

这给出了一个错误。

这是 numpy 中的错误吗?

我的意思是,如果 numpy 允许我们将这样的分数填充矩阵相乘,那么它应该也可以让我们找到逆矩阵,对吧?

import numpy as np
from fractions import Fraction as F

c = np.array([[F(2),F(-1), F(-1)],[F(3),F(4), F(-2)],[F(3),F(-2), F(4)]])

c @ c

np.dot(c, c)

np.linalg.inv(c)

错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-45-5ed58b2836e1> in <module>
----> 1 np.linalg.inv(c)

<__array_function__ internals> in inv(*args, **kwargs)

C:\Programs\Anaconda3\lib\site-packages\numpy\linalg\linalg.py in inv(a)
    544     signature = 'D->D' if isComplexType(t) else 'd->d'
    545     extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
--> 546     ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
    547     return wrap(ainv.astype(result_t, copy=False))
    548 

TypeError: No loop matching the specified signature and casting was found for ufunc inv

我的 numpy 版本是

1.19.2

【问题讨论】:

  • inv 需要 float dtype 数组,而不是 object dtype。 dot@ 已推广到与 object dtype 一起使用,前提是对象具有必要的 * 和 + 操作。但是inv 还没有被推广。还要注意 dot 与 object dtype 很慢。

标签: python numpy linear-algebra matrix-inverse


【解决方案1】:

我同意另一个答案。 Numpy 用于数字,这意味着使用浮点数进行不完美的计算。如果你想做精确的又名符号计算。您应该改用 sympy 。例如。试试:

import sympy
from fractions import Fraction as F

c = sympy.Matrix([[F(2),F(-1), F(-1)],[F(3),F(4), F(-2)],[F(3),F(-2), F(4)]])
c.inv()

【讨论】:

    【解决方案2】:

    不确定您是否可以将其称为错误,但似乎正在按预期工作。 Numpy 的 linalg 模块是 Scipy 的 linalg 模块的轻量版; Numpy 仅支持浮点数或复杂浮点数(编辑:除非您使用 Numpy 内部调用的“精确类型”,如 int;那些是强制转换的)。甚至 Scipy 也不支持分数。来自Scipy's linalg (emphasis mine)的源码:

    许多 SciPy 线性代数函数确实支持任意数组 输入参数。常见不支持输入的示例包括 包含 inf/nan、稀疏矩阵表示、和 具有复杂元素的矩阵

    阅读源码,Numpy 限制性更强; Scipy 接受任何调用np.array(A) 确实 生成具有dtype object 的数组。这是否有意义是主观的;似乎有一些非平凡的兼容性(与现有的 C 算法)或性能权衡以允许数组中的一般对象。

    【讨论】:

    • 对象 dtype 数组上的数学是偶然的,而且永远不会很快。它以列表理解的速度运行,并将操作委托给元素自己的方法。因此np.exp 总是会失败,因为没有人有exp 方法。由于scipy 的大部分内容是专门的数学库的前端,因此对对象 dtype 的支持就更加少了。
    【解决方案3】:
    In [291]: import fractions
    In [292]: F = fractions.Fraction
    In [293]: c = np.array([[F(2),F(-1), F(-1)],[F(3),F(4), F(-2)],[F(3),F(-2), F(4)]])
         ...: 
    In [294]: c
    Out[294]: 
    array([[Fraction(2, 1), Fraction(-1, 1), Fraction(-1, 1)],
           [Fraction(3, 1), Fraction(4, 1), Fraction(-2, 1)],
           [Fraction(3, 1), Fraction(-2, 1), Fraction(4, 1)]], dtype=object)
    In [295]: c@c
    Out[295]: 
    array([[Fraction(-2, 1), Fraction(-4, 1), Fraction(-4, 1)],
           [Fraction(12, 1), Fraction(17, 1), Fraction(-19, 1)],
           [Fraction(12, 1), Fraction(-19, 1), Fraction(17, 1)]], dtype=object)
    

    这是因为c 的元素支持简单的乘法和加法。

    In [298]: c[0,0]*c[1,1]
    Out[298]: Fraction(8, 1)
    

    比较这个对象dtype矩阵乘法的时间:

    In [300]: timeit c@c
    123 µs ± 523 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    float dtype 乘法的时间:

    In [301]: c1=c.astype(float)
    In [302]: c1
    Out[302]: 
    array([[ 2., -1., -1.],
           [ 3.,  4., -2.],
           [ 3., -2.,  4.]])
    In [303]: timeit c1@c1
    4.19 µs ± 28.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    

    使用数字 dtype,@/dot 将任务传递给快速编译的库。对于 object dtype,它必须执行较慢的 python 级计算。

    inv 有快速数值模式,但没有实现慢速对象版本。

    使用 object dtype 输入完整的错误消息是:

    UFuncTypeError: Cannot cast ufunc 'inv' input from dtype('O') to dtype('float64') with casting rule 'same_kind
    

    使用浮点数据类型:

    In [304]: np.linalg.inv(c1)
    Out[304]: 
    array([[ 0.2       ,  0.1       ,  0.1       ],
           [-0.3       ,  0.18333333,  0.01666667],
           [-0.3       ,  0.01666667,  0.18333333]])
    In [305]: timeit np.linalg.inv(c1)
    16.4 µs ± 339 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    

    将其与https://stackoverflow.com/a/69239281/901925 提供的sympy 版本进行比较

    In [308]: import sympy
    In [309]: from fractions import Fraction as F
         ...: 
         ...: c = sympy.Matrix([[F(2),F(-1), F(-1)],[F(3),F(4), F(-2)],[F(3),F(-2), F(4)]])
    In [310]: c
    Out[310]: 
    Matrix([
    [2, -1, -1],
    [3,  4, -2],
    [3, -2,  4]])
    In [311]: c.inv()
    Out[311]: 
    Matrix([
    [  1/5,  1/10,  1/10],
    [-3/10, 11/60,  1/60],
    [-3/10,  1/60, 11/60]])
    In [312]: timeit c.inv()
    801 µs ± 23.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    scipy 更明确

    In [315]: from scipy import linalg
    In [316]: linalg.inv(c)
    Traceback (most recent call last):
      File "<ipython-input-316-48147545516b>", line 1, in <module>
        linalg.inv(c)
      File "/usr/local/lib/python3.8/dist-packages/scipy/linalg/basic.py", line 939, in inv
        a1 = _asarray_validated(a, check_finite=check_finite)
      File "/usr/local/lib/python3.8/dist-packages/scipy/_lib/_util.py", line 296, in _asarray_validated
        raise ValueError('object arrays are not supported')
    ValueError: object arrays are not supported
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-20
      • 1970-01-01
      • 2023-04-06
      • 2014-03-05
      • 2010-12-14
      • 2019-04-17
      • 2013-12-07
      • 1970-01-01
      相关资源
      最近更新 更多