2015-10-05 2 views
2

numpy.square, кажется, дает неправильный вывод, когда scipy.sparse матрицы передаются ему:numpy.square возвращает неправильный результат для разреженных матриц

import numpy as np 
import scipy.sparse as S 
a = np.array([np.arange(5), np.arange(5), np.arange(5), np.arange(5), np.arange(5)]) 

a 
# array([[0, 1, 2, 3, 4], 
#  [0, 1, 2, 3, 4], 
#  [0, 1, 2, 3, 4], 
#  [0, 1, 2, 3, 4], 
#  [0, 1, 2, 3, 4]]) 

np.square(a) 
# array([[ 0, 1, 4, 9, 16], 
#  [ 0, 1, 4, 9, 16], 
#  [ 0, 1, 4, 9, 16], 
#  [ 0, 1, 4, 9, 16], 
#  [ 0, 1, 4, 9, 16]]) 

b = S.lil_matrix(a) 
c = np.square(b) 
c 
# <5x5 sparse matrix of type '<class 'numpy.int64'>' 
# with 20 stored elements in Compressed Sparse Row format> 

c[2,2] 
# 20 
# Expected output is 4, as in np.square(a) output above. 

Является ли это ошибка?

ответ

2

В общем, передавая в scipy.sparse матрицы в numpy функции, которые принимают в качестве входных данных массивы ("array_like"), приводят к неопределенному/непреднамеренному поведению.

Нет автоматических sparse -> dense отливок.

Nump ничего не знает о разреженных матрицах Scipy.

Редкие матрицы не являются «массивными» в смысле, понятном Numpy. То, что выполняют функции numpy, - это обрабатывать разреженные матрицы как только некоторые объекты Python неизвестного типа - в общем, в результате они помещаются в 1-элементные массивы объектов и работают оттуда. Для возврата скалярных результатов временный массив объектов отбрасывается, и возвращается только объект, содержащийся внутри него, поэтому легко пропустить то, что на самом деле было сделано что-то странное.

Объектные массивы имеют некоторые резервные копии для выполнения операций арифметики и т. Д. На своих элементах (неизвестные объекты Python), включая вызов operator.mul элемента, если необходимо выполнить * и т. Д. Это затем сочетается с приведенными выше результатами с поведением, которое вы видите.

2

Обновление: Как указывалось в hpaulj, причина, вероятно, немного более сложная. np.square способен обнаруживать np.matrix и способен квадратировать элементы. Однако он колеблется на sp.sparse.*matrix.


Это не ошибка; это тонкая разница между тем, как numpy и scipy используют оператор __mul__. По умолчанию, * для numpy.ndarray выполняет поэлементное умножение, тогда как для numpy.matrix (и, следовательно, для scipy.sparse.*matrix), он выполняет матричное умножение (от PEP 465):

numpy предоставляет два различных типов с различными __mul__ методами. Для numpy.ndarray объектов, * выполняет умножение по методу и умножение матрицы должно использовать вызов функции (numpy.dot). Для объектов numpy.matrix объектов * выполняет умножение матриц и для умножения по элементу требуется синтаксис функции.

Внутри numpy.square использует метод __mul__ прилагаемого аргумента, который отличается для ndarray с и matrix х годов.

+1

Документация 'np.square' говорит, что она выполняет элементное умножение. Он делает это для объектов 'np.matrix'. По какой-то сообразительной причине, с «разреженными» матричными объектами, он выполняет матричное умножение. Вызывающий стек, я думаю, представляет собой сочетание кода C и Python, которое сложно выполнить. – hpaulj

Смежные вопросы