Unpack `np.unravel_index()` in for loop [duplicate] - python

This question already has answers here:
python matrix transpose and zip
(7 answers)
Closed 1 year ago.
I'm trying to directly unpack the tuple returned from np.unravel_index() in a for loop definition, but I'm running into the following issue:
for i,j in np.unravel_index(range(len(10)), (2, 5)):
print(i,j)
returns:
ValueError: too many values to unpack (expected 2)
I can solve the issue by doing:
idx = np.unravel_index(range(len(10)), (2, 5))
for i, j in zip(idx[0], idx[1]):
print(i, j)
but I really feel I should be able to do it all in the for loop assignment.
I have looked through StackOverflow and found nothing that could help me with my specific question.
Solution:
As the accepted solution I think that this does exactly what I want i.e., unpack directly in the for loop assignment and without previous knowledge of the dimensions of idx:
for i, j in zip(*np.unravel_index(range(len(10)), (2, 5)):
print(i, j)

Your idx is a tuple of arrays:
In [559]: idx = np.unravel_index(np.arange(5),(2,5))
In [560]: idx
Out[560]: (array([0, 0, 0, 0, 0]), array([0, 1, 2, 3, 4]))
The tuple works great for indexing, e.g. data[idx]. In fact that's its intended purpose.
Your zip turns that into a list/iteration on 2 element tuples:
In [561]: list(zip(*idx))
Out[561]: [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]
np.transpose can also turn it into a (n,2) array:
In [562]: np.transpose(idx)
Out[562]:
array([[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4]])
Iteration on [562] will be just as slow as the iteration on the zip, possibly slower. But if you don't need to iterate, [562] may be better.
Notice I used zip(*idx) above, so your expression could written as:
for i, j in zip(*np.unravel_index(range(len(neuron_sample)), (2, 5))):
print(i, j)

Related

Is there a pattern to itertools.permutations

When i am iterating over an itertools.permutations, I would like to know at what indexes specific combinations of numbers would show up, without slowly iterating over the whole thing.
For example:
When I have a list, foo, which equals list(itertools.permutations(range(10))), I would like to know at which indexes the first character will be a zero, and the seventeenth a three. A simple way to do this would be to check every combination and see whether it fits my requirement.
n = 10
foo = list(itertools.permutations(range(n)))
solutions = []
for i, permutation in foo:
if permutation[0] == 0 and permutation[16] == 3:
solutions.append(i)
However, as n gets larger, this becomes incredibly slow, and very memory inefficient.
Is there some pattern that I could use so that instead of creating a long list I could simply say that if (a*i+b)%c == 0 then I know that it will fit my pattern.
EDIT: in reality I will be having many conditions some of which also involve more than 2 positions, therefore I hope that by combining those conditions I can limit the amount of possibilities to the point where this becomes doable. Also, the 100 might have been a big bit, I am expecting n to not get larger than 20.
You need to do a mapping between permutations of not fixed elements and corresponding permutations with fixed cells enrolled. For example, if you count permutations over list [0, 1, 2, 3, 4] and require a value 1, for zero cell and a value 2 for third cell, permutation (0, 4, 3) will be mapped to (1, 0, 4, 2, 3). I know, tuples are not friendly for this case because they are immutable but lists has insert method which is pretty useful here. That's why I convert them to lists and then back to tuples.
import itertools
def item_padding(item, cells):
#returns padding of item, e.g. (0, 4, 3) -> (1, 0, 4, 2, 3)
listed_item = list(item)
for idx in sorted(cells):
listed_item.insert(idx, cells[idx])
return tuple(listed_item)
array = range(5)
cells = {0:1, 3:2} #indexes and their fixed values
remaining_items = set(list(array)) - set(list(cells.values()))
print(list(map(lambda x: item_padding(x, cells), itertools.permutations(remaining_items))))
Output:
[(1, 0, 3, 2, 4), (1, 0, 4, 2, 3), (1, 3, 0, 2, 4), (1, 3, 4, 2, 0), (1, 4, 0, 2, 3), (1, 4, 3, 2, 0)]
To sum up, list conversions are quite slow as well as iterations. Despite that, I think this algorithm is a conceptually good example that reveals what can be done here. Use numpy instead if you really need to optimise it.
Update:
It works 6 seconds on my laptop if array is range(12) (with 3628800 permutations). It's three times more than returning not padded tuples.

How to change values of a numpy array between two positions

I have a numpy array full of 0's such as this
[0,0,0,0,0,0,0,0,0,0,0,0]
And a list of positions such as this
[2-4,6-10]
So what I want to do is iterate through the list of positions and then change the 0's in the numpy array to 1's within the according positions so that I should have a numpy array such as.
[0,1,1,1,0,1,1,1,1,1,0,0,0]
Hope this is clear enough, if not just let me know.
Thanks.
Here's one approach by generating those indices as a concatenated array with np.r_ and then indexing and assigning 1s -
In [64]: a = np.array([0,0,0,0,0,0,0,0,0,0,0,0])
In [65]: pos = np.r_[1:4,5:10]
In [66]: a[pos] = 1
In [67]: a
Out[67]: array([0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0])
You could use a list of pairs to hold the positions;
l = [(2, 4), (6, 10)]
nl = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
Secondly, use a loop;
for a in l:
for c, n in enumerate(nl)
if (a[0] >= c || a[1] <= c):
nl[c] = 1
This is by far not the fastest way to do this but it is simple and readable.
As suggested by this user you could use this instead, which is a lot better in my opinion;
nl[a[0]:[a[1]]=[1]*(a[1]-a[0])

Python list of combinations of positions

I'm trying to generate a list of all possible 1-dimensional positions for an arbitrary number of identical objects. I want it formatted so each coordinate is the distance from the previous object, so for 3 objects (0,5,2) would mean one object is at position 0, another is at position 5 and another is at position 7.
So the main restraint is that the sum of the coordinates is <=D. Nested for loops works well for this. For example, with 3 objects with maximum coordinate D:
def positions(D):
output=[]
for i in range(D+1):
for j in range(D+1-i):
for k in range(D+1-i-j):
output.append((i,j,k))
return(output)
What's the best way to extend this to an arbitrary number of objects? I can't find a good way without explicitly writing a specific number of for loops.
I think you can combine itertools.combinations, which will give you the locations, with taking the difference, which should give you your "distance from the previous object" behaviour. For example, using
def diff(loc):
return [y-x for x,y in zip((0,) + loc, loc)]
we have
In [114]: list(itertools.combinations(range(4), 3))
Out[114]: [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
for the possible positions, and then
In [115]: [diff(x) for x in itertools.combinations(range(4), 3)]
Out[115]: [[0, 1, 1], [0, 1, 2], [0, 2, 1], [1, 1, 1]]
for your relative-distance version.

Numpy array subset - unexpected behaviour

I'm trying to copy a subset of a numpy array (to do image background subtraction - but that's by the by). I don't understand what's wrong with the following - I've demonstrated it interactively because you really don't want to wade through all my code...
>>> from numpy import zeros
>>> a = zeros((5,5,3), 'uint8')
>>> print a.shape
(5, 5, 3)
>>> b = a[1:2][1:2][:].copy()
>>> print b.shape
(0, 5, 3)
>>> print a[1:2][1:2][:].shape
(0, 5, 3)
>>> print a.shape
(5, 5, 3)
>>>
What I'd like is for b.shape to return (2,2,3) - and behave that way in the subsequent operations I need to do with it. I'm sure I've done something really obvious wrong, but I can't work out what. Any suggestions gratefully received!
I believe you meant a[1:3, 1:3, :] instead of a[1:2][1:2][:].
Also, a[1:3, 1:3, ...] would work too (... means "as many : as necessary"). NumPy seems to also allow a[1:3, 1:3].
There are two parts to the explanations:
slicing in Python is left-inclusive and right-exclusive
comma-indexing is necessary here, a[1:3] gives you a shape (2,5,3) and another [1:3] will slice through the first dimension again.
For simple indexing a[1][2][3] is same as a[1,2,3] because each consecutive indexing removes one dimension. That doesn't hold for slicing, though - you need to use commas.
There are two different problems with what you're doing. The primary one is how you're handling indexing in numpy. Numpy matrices have their own syntax that is much more clear than the list of lists syntax that you're using... Use commas instead of separate indices in brackets:
>>> from numpy import zeros
>>> a = zeros((5,5,3), 'uint8')
>>> print a[1:2,1:2,:].shape
(1, 1, 3)
What you're doing instead is failing because a[1:2] still returns a list of lists, so your next index is an index on the outer list (which only has one element), not the inner list that you want:
>>> a[1:2]
array([[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]], dtype=uint8)
>>> a[1:2][1:2]
array([], shape=(0, 5, 3), dtype=uint8)
(You wouldn't have this problem if you were using simple indices instead of slices, but you should still use the comma syntax because it's much clearer.
Second, you're using slices wrong. The first value of the slice is the index of the first value of the array that you want--and the indices start at 0. The second value is one MORE than the index of the array that you want. This is so that a[first_index:second_index] returns second_index-first_index points. So, you want something like this:
>>> b = a[0:2,0:2,:]
>>> b
array([[[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0]]], dtype=uint8)
Your index of [1:2] will only return one element... the second one in the list.
Also, as a side note, .copy() is redundant here because taking slices from a numpy array already creates a new object.

clean way to accomplish -- if x in [(0, 1, 2), (2, 0, 1), (1, 2, 0)]:?

If not, then a canonical name for a function? 'Cycle' makes sense to me, but that's taken.
The example in the header is written for clarity and brevity. Real cases I'm working with have a lot of repetition.
(e.g., I want [1, 1, 0, 0, 0, 2, 1] to "match" [0, 0, 2, 1, 1, 1, 0])
This type of thing is obscuring my algorithm and filling my code with otherwise useless repetition.
You can get the cycles of the list with:
def cycles(a):
return [ a[i:] + a[:i] for i in range(len(a)) ]
You can then check if b is a cycle of a with:
b in cycles(a)
If the length of the list is long, or if want to make multiple comparison to the same cycles, it may be beneficial (performance wise) to embed the results in a set.
set_cycles = set(cycles(a))
b in set_cycles
You can prevent necessarily constructing all the cycles by embedding the equality check in the list and using any:
any( b == a[i:]+a[:i] for i in range(len(a)))
You could also achieve this effect by turning the cycles function into a generator.
Misunderstood your question earlier. If you want to check if any cycle of a list l1 matches a list l2 the best (cleanest/most pythonic) method is probably any(l1 == l2[i:] + l2[:i] for i in xrange(len(l2))). There is also a rotate method in collections.deque that you might find useful.
You could use cycle from itertools, together with islice to cut it up. This basically puts this answer in a list comprehension so the list is shifted once for every element.
>>> from itertools import islice, cycle
>>> l = [0,1,2]
>>> [tuple(islice(cycle(t),i,i+len(t))) for i,_ in enumerate(l)]
[(0, 1, 2), (1, 2, 0), (2, 0, 1)]

Categories