np.mgrid accepts tuple of slices, like np.mgrid[1:3, 4:8] or np.mgrid[np.s_[1:3, 4:8]].
But is there a way to mix both slices and arrays of indexes in a tuple argument to mgrid? E.g.:
extended_mgrid(np.s_[1:3, 4:8] + (np.array([1,2,3]), np.array([7,8])))
should give same results as
np.mgrid[1:3, 4:8, 1:4, 7:9]
But in general an array of indexes inside a tuple may not be representable as a slice.
Solving this task is needed to be able to create N-D tuple of indexes provided a mix of slicing + indexing using np.mgrid like in this my answer for another question.
Task solved with help of #hpaulj using np.meshgrid.
Try it online!
import numpy as np
def extended_mgrid(i):
res = np.meshgrid(*[(
np.arange(e.start or 0, e.stop, e.step or 1)
if type(e) is slice else e
) for e in {slice: (i,), np.ndarray: (i,), tuple: i}[type(i)]
], indexing = 'ij')
return np.stack(res, 0) if type(i) is tuple else res[0]
# Tests
a = np.mgrid[1:3]
b = extended_mgrid(np.s_[1:3])
assert np.array_equal(a, b), (a, b)
a = np.mgrid[(np.s_[1:3],)]
b = extended_mgrid((np.s_[1:3],))
assert np.array_equal(a, b), (a, b)
a = np.array([[[1,1],[2,2]],[[3,4],[3,4]]])
b = extended_mgrid((np.array([1,2]), np.array([3,4])))
assert np.array_equal(a, b), (a, b)
a = np.mgrid[1:3, 4:8, 1:4, 7:9]
b = extended_mgrid(np.s_[1:3, 4:8] + (np.array([1,2,3]), np.array([7,8])))
assert np.array_equal(a, b), (a, b)
Related
The problem is: swapping the second element between two tuples meeting all the following criteria: consisting of two ints, each in range(5), elements in same positions aren't equal
If they are two lists I can simply use variable swapping with indexing but tuples are immutable so I unpacked the two tuples into a single list and unpacked that list into four variables and reordered the variables...
Example Code
(See the initial values the variables are declared with, the printed values are the intended result.)
a, b = [1,2], [3,4]
a[1], b[1] = b[1], a[1]
print(a)
print(b)
l1, l2 = (1,2), (3,4)
a, b, c, d = [*l1, *l2]
print((a, d))
print((c, b))
In [161]: a, b = [1,2], [3,4]
...: a[1], b[1] = b[1], a[1]
...: print(a)
...: print(b)
...:
...: l1, l2 = (1,2), (3,4)
...: a, b, c, d = [*l1, *l2]
...: print((a, d))
...: print((c, b))
[1, 4]
[3, 2]
(1, 4)
(3, 2)
I don't want to cast the tuples into lists, I wonder if there is a better way to swap the second element between the two tuples?
You're right that the tuples are immutable, and you won't be able to get around creating new tuples. If you just want to do this without using unpacking notation, you could do something like
l1, l2 = (1,2), (3,4)
a = (l1[0],l2[1])
b = (l2[0],l1[1])
If speed is a concern here, running this with pypy will be very efficient.
Try this:
t = (1, 2)
swapped = t[::-1]
# true
assert type(swapped) == tuple
assert swapped == (2, 1)
I have a list of numpy arrays, say,
a = [np.random.rand(3, 3), np.random.rand(3, 3), np.random.rand(3, 3)]
and I have a test array, say
b = np.random.rand(3, 3)
I want to check whether a contains b or not. However
b in a
throws the following error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
What is the proper way for what I want?
You can just make one array of shape (3, 3, 3) out of a:
a = np.asarray(a)
And then compare it with b (we're comparing floats here, so we should use isclose())
np.all(np.isclose(a, b), axis=(1, 2))
For example:
a = [np.random.rand(3,3),np.random.rand(3,3),np.random.rand(3,3)]
a = np.asarray(a)
b = a[1, ...] # set b to some value we know will yield True
np.all(np.isclose(a, b), axis=(1, 2))
# array([False, True, False])
As highlighted by #jotasi the truth value is ambiguous due to element-wise comparison within the array.
There was a previous answer to this question here. Overall your task can be done in various ways:
list-to-array:
You can use the "in" operator by converting the list to a (3,3,3)-shaped array as follows:
>>> a = [np.random.rand(3, 3), np.random.rand(3, 3), np.random.rand(3, 3)]
>>> a= np.asarray(a)
>>> b= a[1].copy()
>>> b in a
True
np.all:
>>> any(np.all((b==a),axis=(1,2)))
True
list-comperhension:
This done by iterating over each array:
>>> any([(b == a_s).all() for a_s in a])
True
Below is a speed comparison of the three approaches above:
Speed Comparison
import numpy as np
import perfplot
perfplot.show(
setup=lambda n: np.asarray([np.random.rand(3*3).reshape(3,3) for i in range(n)]),
kernels=[
lambda a: a[-1] in a,
lambda a: any(np.all((a[-1]==a),axis=(1,2))),
lambda a: any([(a[-1] == a_s).all() for a_s in a])
],
labels=[
'in', 'np.all', 'list_comperhension'
],
n_range=[2**k for k in range(1,20)],
xlabel='Array size',
logx=True,
logy=True,
)
Ok so in doesn't work because it's effectively doing
def in_(obj, iterable):
for elem in iterable:
if obj == elem:
return True
return False
Now, the problem is that for two ndarrays a and b, a == b is an array (try it), not a boolean, so if a == b fails. The solution is do define a new function
def array_in(arr, list_of_arr):
for elem in list_of_arr:
if (arr == elem).all():
return True
return False
a = [np.arange(5)] * 3
b = np.ones(5)
array_in(b, a) # --> False
This error is because if a and b are numpy arrays then a == b doesn't return True or False, but array of boolean values after comparing a and b element-wise.
You can try something like this:
np.any([np.all(a_s == b) for a_s in a])
[np.all(a_s == b) for a_s in a] Here you are creating list of boolean values, iterating through elements of a and checking if all elements in b and particular element of a are the same.
With np.any you can check if any element in your array is True
As pointed out in this answer, the documentation states that:
For container types such as list, tuple, set, frozenset, dict, or collections.deque, the expression x in y is equivalent to any(x is e or x == e for e in y).
a[0]==b is an array, though, containing an element-wise comparison of a[0] and b. The overall truth value of this array is obviously ambiguous. Are they the same if all elements match, or if most match of if at least one matches? Therefore, numpy forces you to be explicit in what you mean. What you want to know, is to test whether all elements are the same. You can do that by using numpy's all method:
any((b is e) or (b == e).all() for e in a)
or put in a function:
def numpy_in(arrayToTest, listOfArrays):
return any((arrayToTest is e) or (arrayToTest == e).all()
for e in listOfArrays)
Use array_equal from numpy
import numpy as np
a = [np.random.rand(3,3),np.random.rand(3,3),np.random.rand(3,3)]
b = np.random.rand(3,3)
for i in a:
if np.array_equal(b,i):
print("yes")
Is there anyway to sum two points not using "class point"
Input
a= (2,5)
b= (3,4)
c= a +b
Output
(5 , 9)
You can use a comprehension plus zip:
c = tuple(a_n + b_n for a_n, b_n in zip(a, b))
This is obviously cumbersome if you need to do it a lot (not to mention slightly inefficient). If you are going to be doing this sort of computation a lot, then you're better off using a library like numpy which allows arrays to be added as first-class objects.
import numpy as np
a = np.array([2, 5])
b = np.array([3, 4])
c = a + b
If you go the numpy route, converting to and from numpy arrays is a bit expensive so I'd recommend that you store your points as arrays rather than tuple.
If you'd like a functional approach:
t = tuple(map(sum, zip(a, b)))
import numpy
a = (2,5)
b = (3,4)
c = tuple(numpy.asarray(a) + numpy.asarray(b)) #Tuple convert is just because this is how your output defined. you can skip it...
Complex numbers are (2-)tuples in disguise:
>>> a = 2+5j
>>> b = 3+4j
>>> c = a + b
>>> c
(5+9j)
My solution:
reduce(lambda x, y: (x[0] + y[0], x[1] + y[1]), zip(a, b))
I see that numpy has many indexing facilities, but still couldn't get them to do what I need.
First, assume there are two one-dimensional arrays A, I of the same shape, a one-dimensional array B which can be indexed with elements of I, and a three-argument function f. Then the result I need can be achieved like starmap(f, zip(A, I, B[I])) (starmap and zip are from pure python, not numpy). So far, so good...
But actually, all the arrays are two-dimensional and I'd like get two-dimensional result as well, which is equivalent to applying the same function as above to each row of the arrays - this is what I now do in a loop.
Are there better ways to do this, than just looping?
UPD:
For example, with one dimensional arrays:
A = np.random.randint(0, 10, size=(3,))
B = np.random.randint(0, 10, size=(5,))
I = np.random.randint(0, 5, size=(3,))
def f(a, i, b):
return (a, i, b)
print A, I, B
print list(starmap(f, zip(A, I, B[I])))
And for two-dimensional:
A = np.random.randint(0, 10, size=(2, 3))
B = np.random.randint(0, 10, size=(2, 5))
I = np.random.randint(0, 5, size=(2, 3))
def f(a, i, b):
return (a, i, b)
print A
print I
print B
print [list(starmap(f, zip(A_row, I_row, B_row[I_row])))
for A_row, I_row, B_row in zip(A, I, B)]
If it's just a normal function, your overhead is going to be primarily function overhead. You could do the zip with an hstack or something, but it's not going to help speed-wise.
If you're just looking for a neater way of doing it, try
x_indexes, _ = numpy.ogrid[:len(I), :0]
numpy.vectorize(f)(A, I, B[x_indexes, I])
Normally a higher-level view can let you vectorize the whole thing, which will be much faster. That's worth keeping in mind if this ends up slow.
What is the most elegant and concise way (without creating my own class with operator overloading) to perform tuple arithmetic in Python 2.7?
Lets say I have two tuples:
a = (10, 10)
b = (4, 4)
My intended result is
c = a - b = (6, 6)
I currently use:
c = (a[0] - b[0], a[1] - b[1])
I also tried:
c = tuple([(i - j) for i in a for j in b])
but the result was (6, 6, 6, 6). I believe the above works as a nested for loops resulting in 4 iterations and 4 values in the result.
If you're looking for fast, you can use numpy:
>>> import numpy
>>> numpy.subtract((10, 10), (4, 4))
array([6, 6])
and if you want to keep it in a tuple:
>>> tuple(numpy.subtract((10, 10), (4, 4)))
(6, 6)
One option would be,
>>> from operator import sub
>>> c = tuple(map(sub, a, b))
>>> c
(6, 6)
And itertools.imap can serve as a replacement for map.
Of course you can also use other functions from operator to add, mul, div, etc.
But I would seriously consider moving into another data structure since I don't think this type of problem is fit for tuples
Use zip and a generator expression:
c = tuple(x-y for x, y in zip(a, b))
Demo:
>>> a = (10, 10)
>>> b = (4, 4)
>>> c = tuple(x-y for x, y in zip(a, b))
>>> c
(6, 6)
Use itertools.izip for a memory efficient solution.
help on zip:
>>> print zip.__doc__
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences. The returned list is truncated
in length to the length of the shortest argument sequence.
JFYI, execution time in my laptop in 100000 times iteration
np.subtract(a, b) : 0.18578505516052246
tuple(x - y for x, y in zip(a, b)) :
0.09348797798156738
tuple(map(lambda x, y: x - y, a, b)) : 0.07900381088256836
from operator import sub tuple(map(sub, a, b)) : 0.044342041015625
operator looks more elegant for me.
This can also be done just as nicely without an import at all, although lambda is often undesirable:
tuple(map(lambda x, y: x - y, a, b))
If you are looking to get the distance between two points on say a 2d coordinate plane you should use the absolute value of the subtraction of the pairs.
tuple(map(lambda x ,y: abs(x - y), a, b))
Since in your question there only examples of 2-number-tuples, for such coordinate-like tuples, you may be good with simple built-in "complex" class:
>>> a=complex(7,5)
>>> b=complex(1,2)
>>> a-b
>>> c=a-b
>>> c
(6+3j)
>>> c.real
6.0
>>> c.imag
3.0
As an addition to Kohei Kawasaki's answer, for speed, the original solution was actually the fastest (For a length two tuple at least).
>>> timeit.timeit('tuple(map(add, a, b))',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.6502681339999867
>>> timeit.timeit('(a[0] - b[0], a[1] - b[1])',number=1000000,setup='from operator import add; a=(10,11); b=(1,2)')
0.19015854899998885
>>>
my element-wise tuple arithmetic helper
supported operations: +, -, /, *, d
operation = 'd' calculates distance between two points on a 2D coordinate plane
def tuplengine(tuple1, tuple2, operation):
"""
quick and dirty, element-wise, tuple arithmetic helper,
created on Sun May 28 07:06:16 2017
...
tuple1, tuple2: [named]tuples, both same length
operation: '+', '-', '/', '*', 'd'
operation 'd' returns distance between two points on a 2D coordinate plane (absolute value of the subtraction of pairs)
"""
assert len(tuple1) == len(tuple2), "tuple sizes doesn't match, tuple1: {}, tuple2: {}".format(len(tuple1), len(tuple2))
assert isinstance(tuple1, tuple) or tuple in type(tuple1).__bases__, "tuple1: not a [named]tuple"
assert isinstance(tuple2, tuple) or tuple in type(tuple2).__bases__, "tuple2: not a [named]tuple"
assert operation in list("+-/*d"), "operation has to be one of ['+','-','/','*','d']"
return eval("tuple( a{}b for a, b in zip( tuple1, tuple2 ))".format(operation)) \
if not operation == "d" \
else eval("tuple( abs(a-b) for a, b in zip( tuple1, tuple2 ))")