I've done this function, changesOfSign
, which takes as argument a matrix and returns the matrix whose rows are all possible combinations of the original rows with the +
or -
sign associated to the entries:
import itertools
import numpy as np
def expandgrid(*itrs): # https://stackoverflow.com/a/12131385/1100107
product = list(itertools.product(*itrs))
return [[x[i] for x in product] for i in range(len(itrs))]
def changesOfSign(mat):
maps = np.apply_along_axis(
lambda r: map(lambda x: [0] if x==0 else [-x,x], r),
1, mat
)
lists = [list(m) for m in maps]
mats = [np.transpose(expandgrid(*lists[i])) for i in range(len(lists))]
return np.vstack(tuple(mats))
arr = np.array([
[1, 0, 3],
[5, 2, 4]
])
For example:
changesOfSign(arr)
Out[22]:
array([[-1, 0, -3],
[-1, 0, 3],
[ 1, 0, -3],
[ 1, 0, 3],
[-5, -2, -4],
[-5, -2, 4],
[-5, 2, -4],
[-5, 2, 4],
[ 5, -2, -4],
[ 5, -2, 4],
[ 5, 2, -4],
[ 5, 2, 4]])
Now I want to generalize this function to have the possibility to choose for which columns I want the changes of sign. I've done:
cols = [0, 1] # columns for which changes of sign are desired
lists = np.apply_along_axis(
lambda r: [[x] if (x==0 or i not in cols) else [-x,x] for i,x in enumerate(r)],
1, arr
)
mats = [np.transpose(expandgrid(*lists[i])) for i in range(len(lists))]
np.vstack(tuple(mats))
It works:
array([[-1, 0, 3],
[ 1, 0, 3],
[-5, -2, 4],
[-5, 2, 4],
[ 5, -2, 4],
[ 5, 2, 4]])
but I have this warning when I run np.apply_along_axis
:
VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
I don't know where I can put dtype=object
. Any idea?
EDIT
I have a solution:
def f(cols):
return lambda r: [[x] if (x==0 or i not in cols) else [-x,x] for i,x in enumerate(r)]
lists = [f(cols)(r) for r in arr]
mats = [np.transpose(expandgrid(*lists[i])) for i in range(len(lists))]
np.vstack(tuple(mats))