Смешивание numpy
и sympy
может быть сложным;Добавьте к этому потенциальную путаницу, вызванную np.mat
вместо базового типа массива, ndarray
.
В сумме
y_ = np.sum(np.dot(w,x)+b)
вычисляет выражение python / numpy на объектах sympy. Результатом является симпатичное выражение w*x+b
. Объекты sympy являются скалярами, так что это не кодирует никакого умножения матрицы или суммирования массива. Выражение multiply
вычисляется таким же образом.
Затем выражения lambdify
переводят один и тот же y_
в одну и ту же функцию Python. И эта оценка зависит от размеров и класса np.mat
аргументов.
детали
На данный момент игнорируется sympy
часть:
In [310]: w = np.mat([1,1,1,1,1])
...: x= np.mat([1,1,1,1,1]).T
...: b = np.mat([0,0,0,0,0]).T
...: y = np.mat([6,6,6,6,6]).T
In [311]: np.sum(np.dot(w,x)+b)
Out[311]: 25
In [312]: np.multiply(w,x)+b
Out[312]:
matrix([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
Потому что ониnp.mat
, оба w
и x
являются 2d:
In [316]: w.shape
Out[316]: (1, 5)
In [317]: x.shape
Out[317]: (5, 1)
np.dot
из (1,5) с (5,1) является результатом (1,1):
In [313]: np.dot(w,x)
Out[313]: matrix([[5]])
и для np.matrix
, *
определяется как dot
:
In [314]: w*x
Out[314]: matrix([[5]])
По элементам:
In [315]: np.multiply(w,x) # elementwise produces (5,5)
Out[315]:
matrix([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
np.sum(np.dot(w,x)+b)
делает dot
, затем добавляет b
и заканчивается sum
над всеми элементами.
np.multiply(w,x)+b
делает это умножение, добавляет b
. Нет sum
.
исправления
Использование w.T
, которое я пропустил в первый раз:
In [322]: np.multiply(w.T,x)
Out[322]:
matrix([[1],
[1],
[1],
[1],
[1]])
In [323]: w.T*x
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-323-11ad839cfa88> in <module>
----> 1 w.T*x
/usr/local/lib/python3.6/dist-packages/numpy/matrixlib/defmatrix.py in __mul__(self, other)
218 if isinstance(other, (N.ndarray, list, tuple)) :
219 # This promotes 1-D vectors to row vectors
--> 220 return N.dot(self, asmatrix(other))
221 if isscalar(other) or not hasattr(other, '__rmul__') :
222 return N.dot(self, other)
<__array_function__ internals> in dot(*args, **kwargs)
ValueError: shapes (5,1) and (5,1) not aligned: 1 (dim 1) != 5 (dim 0)
np.multiply
of (5,1) и(5,1) производит (5,1), поэлементное умножение
w.T*x
- матричное умножение для np.mat
, следовательно, ошибка np.dot
.
Использование np.mat
не рекомендуется (если формально не исключено). В numpy
добавление matmul/@
устраняет его нотационные преимущества. Жизнь проще в numpy
, если вы придерживаетесь базового класса массива, ndarray
. Я понимаю, что sympy
все еще использует концепцию 2d матрицы, с *
в качестве умножения матрицы.
с sympy
В сеансе isympy
я обнаружил, что мне нужно определить w,x,b
как символы:
y_ = np.sum(np.dot(w,x)+b)
Если w,x,b
- это просто символыэто скаляры, а не матрицы или массивы. Ваши np.sum(np.dot(1,2)+4)
, np.multiply(1,2)+4
и 1*2+4
все производят одно и то же. Только когда переменные являются массивами, или np.mat
, или, может быть, sympy.Matrix
, выражения отличаются.
Проблема не в lambdify
. В обоих случаях ему присваивается один и тот же y_
(как проверено print(y_)
. Вы получаете ошибку, поскольку аргументы np.mat
, а *
- умножение матриц.
С x,y,z
символы:
In [55]: f = lambdify((x,y,z),x*y+z, 'numpy')
Использование isympy
самоанализа:
In [56]: f??
Signature: f(x, y, z)
Docstring:
Created with lambdify. Signature:
func(x, y, z)
Expression:
x*y + z
Source code:
def _lambdifygenerated(x, y, z):
return (x*y + z)
Imported modules:
Source:
def _lambdifygenerated(x, y, z):
return (x*y + z)
File: ~/mypy/<lambdifygenerated-4>
Type: function
Ознакомьтесь с полной документацией по lambdify
. Обратите внимание, что это в основном лексическая замена
https://docs.sympy.org/latest/modules/utilities/lambdify.html
Эта документация предупреждает:
Как правило, функции NumPy не знают, как работать с выражениями SymPy, а функции SymPy не знают, как работатьдля массивов NumPy. Вот почему существует lambdify: для обеспечения моста между SymPy и NumPy.
sympify
https://docs.sympy.org/latest/modules/core.html#module-sympy.core.sympify
говорит, что используетeval
. С x,y,z
, определенным как символы:
In [66]: eval('np.dot(x,y)+z')
Out[66]: x⋅y + z
In [67]: eval('np.sum(np.dot(x,y)+z)')
Out[67]: x⋅y + z
In [68]: eval('np.multiply(x,y)+z')
Out[68]: x⋅y + z
Другими словами, он просто передает символы в функции (и / или операторы),
In [69]: np.dot(x,y)
Out[69]: x⋅y
dot
превращает свои входные данные в массивы:
In [70]: np.array(x)
Out[70]: array(x, dtype=object)
In [71]: np.dot(np.array(x), np.array(y))
Out[71]: x⋅y
Это работает, потому что для символов определены '*' и '+'.
sympy
документы предупреждают, что оценка numpy
ничего не "знает" о объектах sympy. Он обрабатывает их как массивы объектов типа d, которые могут работать или не работать:
In [72]: sin(x) # sympy sin
Out[72]: sin(x)
In [73]: np.sin(x) # numpy sin
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
AttributeError: 'Symbol' object has no attribute 'sin'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
<ipython-input-73-92f2c2d0df9d> in <module>
----> 1 np.sin(x)
TypeError: loop of ufunc does not support argument 0 of type Symbol which has no callable sin method
np.sin
делает np.sin(np.array(x))
, а затем делегирует действие методу sin
x
- который выполняетне существует.