Remove Rearranged Arrays in Numpy - python

I have a numpy product generator (using meshgrid) which finds the product of two arrays (similar to itertools.product). The problem is that it generates arrays which contain the same elements, but rearranged (thus numpy.unique doesn't filter them).
For example, if I have an array like this:
[[0, 0]
[1, 0]
[0, 1]
[1, 1]]
I would need a result like this:
[[0, 0]
[1, 0]
[1, 1]]
Since [1, 0] and [0, 1] are the same for my purposes.

If you have numpy >= 1.13.0, you can use np.unique on previously sorted array:
>>> a = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
>>> a
[[0 0]
[1 0]
[0 1]
[1 1]]
>>> b = np.unique(np.sort(a, axis=1), axis=0)
>>> b
[[0 0]
[0 1]
[1 1]]

Related

Loop through rows of input matrices with vectorize

I have a 4x2 and a 2x2 matrices. I would like to loop each combination of rows (vectors of dimension 2) through a function foo using vectorize.
Here are the matrices:
X = np.array([[1, 0], [2, 0], [3, 0], [4,0]])
Y = np.array([[1, 0], [2, 0]])
Here's how I'm trying to run it:
def foo(x, y):
print("inputs:", x, y)
return x[0] * y[0]
bar = np.vectorize(foo, signature="???")
output = bar(X, Y)
print(output)
I'm looking for the following output. bar would return a 4x2 matrice:
inputs: [1,0] [1,0]
inputs: [1,0] [2,0]
inputs: [2,0] [1,0]
inputs: [2,0] [2,0]
inputs: [3,0] [1,0]
inputs: [3,0] [2,0]
inputs: [4,0] [1,0]
inputs: [4,0] [2,0]
[[1,2], [2,4], [3,6], [4,8]]
I've tried various combinations of signature, but I'm just not grokking how to use it given the output I'm looking for.
NB: I am aware vectorize just uses Python for loops under the hood and offers no performance benefit. I just want to understand how to use it.
The basic use of vectorize broadcasts the inputs against each other, and passes scalar tuples to your function. A (4,2) can't broadcast with a (2,2). signature is an addition that should make it possible to pass "rows" of your arrays. It's even slower, and I haven't see it used much (or recommended it).
In [536]: bar = np.vectorize(foo, signature="(n),(n)->()")
In [533]: bar(X,Y[0,:])
inputs: [1 0] [1 0]
inputs: [2 0] [1 0]
inputs: [3 0] [1 0]
inputs: [4 0] [1 0]
Out[533]: array([1, 2, 3, 4])
In [537]: bar(X[:,None],Y[None])
inputs: [1 0] [1 0]
inputs: [1 0] [2 0]
inputs: [2 0] [1 0]
inputs: [2 0] [2 0]
inputs: [3 0] [1 0]
inputs: [3 0] [2 0]
inputs: [4 0] [1 0]
inputs: [4 0] [2 0]
Out[537]:
array([[1, 2],
[2, 4],
[3, 6],
[4, 8]])
So this gives bar a (4,1,2) and (1,2,2); which broadcast as (4,2,2). Or with this signature it's broadcasting a (4,1) with 1,2) => (4,2). It's the signature that determines how the last dimensions match.
It may in some cases be convenient, but I wouldn't recommend devoting too much time to understanding vectorize.

Find all possible replacements for 1s and 0s in a list

Input:
table = [
[1, ''],
['', 0]
]
Desired output:
[[[1, 0], [0, 0]], [[1, 0], [1, 0]], [[1, 1], [0, 0]], [[1, 1], [1, 0]]]
Tried to do it with recursion like this:
def get_tables(tab, out_tab):
changes = 0
for row_i, row in enumerate(tab):
for val_i, val in enumerate(row):
if val == '':
changes = 1
tab[row_i][val_i] = 0
get_tables(tab, out_tab)
tab[row_i][val_i] = 1
get_tables(tab, out_tab)
if changes == 0:
out_tab.append(tab)
But it returns only 1s
Edit:
So the logic is: find '' in list and then create two lists, one with 1 instead of '' and one with 0 (like [1, ''] to [1, 0] and [1, 1]). Do the same operation with those two lists, and continue until there's no ''. Return all this lists in one.
Not the most efficient solution, but it works:
table = [
[1, ''],
['', 0]
]
import copy
# locations where element is ''
locs = [[idx_r, idx_c] for idx_r, row in enumerate(table) for idx_c, element in enumerate(row) if element == '']
len_locs = len(locs)
tables = []
for i in range(2 ** len_locs): # for n locations, we have 2**n permutations of 1 and 0
table_copy = copy.deepcopy(table)
permutation = list(map(int, f'{i:0{len_locs}b}')) # convert i to the binary to get current permutation
for it, (idx_r, idx_c) in enumerate(locs):
table_copy[idx_r][idx_c] = permutation[it]
tables.append(table_copy)
print(tables)
>>> [[[1, 0], [0, 0]], [[1, 0], [1, 0]], [[1, 1], [0, 0]], [[1, 1], [1, 0]]]

How do I create an nxn array of m-m arrays?

I want to create an array made of arrays in Python with numpy
I'm trying to calcule the inverse of a matrix made by some other matrix using numpy method linalg.inv() but it calculates one inverse for each submatrix instead of a general inverse
for example, lets say I have:
a = np.array([[1, 2],
[3, 4]])
b = np.array([[5, 6],
[7, 8]])
i = np.array([[1, 0],
[0, 1]])
what I've tried is:
c = np.array([[a, i],
[i, b]])
what I want is
>> [[1, 2, 1, 0]
[3, 4, 0, 1]
[1, 0, 5, 6]
[0, 1, 7, 8]]
what I get is
>> [[[[1 2]
[3 4]]
[[1 0]
[0 1]]]
[[[1 0]
[0 1]]
[[5 6]
[7 8]]]]
You can use the np.block function, which can be used to assemble a block of matrices. You can do something like this,
np.block([[a,i],[i,b]])

Numpy dot one matrix with an array of vectors and get a new array of vectors

Say we have an array of 2D vectors (describing a square shape), and a matrix (scale along y axis):
vecs = np.array([[1, 0],
[1, 1],
[0, 1],
[0, 0]])
mat = np.array([[1, 0],
[0, 2]])
I want to get a new array of vectors, where each vector from vecs is dot multiplied with mat. Now I do it like this:
new_vecs = vecs.copy()
for i, vec in enumerate(vecs):
new_vecs[i] = np.dot(mat, vec)
This produces the desired result:
>>> print(new_vecs)
[[1 0]
[1 2]
[0 2]
[0 0]]
What are better ways to do this?
The dot product np.dot will multiply matrices of any shape with each other, as long as their shapes line up: np.dot((a,b), (b,c)) -> (a,c). So if you invert the order, Numpy does this for you in one call:
In [3]: np.dot(vecs, mat)
Out[3]:
array([[1, 0],
[1, 2],
[0, 2],
[0, 0]])
You can use the following:
np.dot(mat , vecs.T).T

How to create a numpy array from itertools.combinations without looping

Is there a way to get this result without a loop? I've made a couple attempts at fancy indexing with W[range(W.shape[0]),... but have been so far unsuccessful.
import itertools
import numpy as np
n = 4
ct = 2
one_index_tuples = list(itertools.combinations(range(n), r=ct))
W = np.zeros((len(one_index_tuples), n), dtype='int')
for row_index, col_index in enumerate(one_index_tuples):
W[row_index, col_index] = 1
print(W)
Result:
[[1 1 0 0]
[1 0 1 0]
[1 0 0 1]
[0 1 1 0]
[0 1 0 1]
[0 0 1 1]]
You can use fancy indexing (advanced indexing) as follows:
# reshape the row index to 2d since your column index is also 2d so that the row index and
# column index will broadcast properly
W[np.arange(len(one_index_tuples))[:, None], one_index_tuples] = 1
W
#array([[1, 1, 0, 0],
# [1, 0, 1, 0],
# [1, 0, 0, 1],
# [0, 1, 1, 0],
# [0, 1, 0, 1],
# [0, 0, 1, 1]])
Try this:
[[ 1 if i in x else 0 for i in range(n) ] for x in itertools.combinations( range(n), ct )]

Categories