I have a list which consists out of two numpy arrays, the first one telling the index of a value and the second containing the belonging value itself. It looks a little like this:
x_glob = [[0, 2], [85, 30]]
A function is now receiving the following input:
x = [-10, 0, 77, 54]
My goal is to swap the values of x with the values from x_glob based on the given index array from x_glob. This example should result in something like this:
x_new = [85, 0, 30, 54]
I do have a solution using a loop. But I am pretty sure there is a way in python to solve this issue more efficient and elegant.
Thank you!
NumPy arrays may be indexed with other arrays, which makes this replacement trivial.
All you need to do is index your second array with x_glob[0], and then assign x_glob[1]
x[x_glob[0]] = x_glob[1]
To see how this works, just look at the result of the indexing:
>>> x[x_glob[0]]
array([-10, 77])
The result is an array containing the two values that we need to replace, which we then replace with another numpy array, x_glob[1], to achieve the desired result.
>>> x_glob = np.array([[0, 2], [85, 30]])
>>> x = np.array([-10, 0, 77, 54])
>>> x[x_glob[0]] = x_glob[1]
>>> x
array([85, 0, 30, 54])
For a non-numpy solution, you could create a dict mapping the indices from x_glob to the respective values and then use a list comprehension with that dict's get method:
>>> x_glob = [[0, 2], [85, 30]]
>>> x = [-10, 0, 77, 54]
>>> d = dict(zip(*x_glob))
>>> [d.get(i, n) for i, n in enumerate(x)]
[85, 0, 30, 54]
Or using map with multiple parameter lists (or without zip using itertools.starmap):
>>> list(map(d.get, *zip(*enumerate(x))))
[85, 0, 30, 54]
My solution also uses for loop, but it's pretty short and elegant (I think), works in place and is effective as it does not have to iterate through full x array, just through list of globs:
for k,v in zip(*x_glob):
x[k] = v
Related
I have a list of arrays generated from another function:
testGroup = [array([18]), array([], dtype=int64), array([56, 75, 55, 55]), array([32])]
I'd like to return the sum of each individual array in the list, with the empty ones returning as zero
I've tried using numpy, as per the documentation:
np.sum([[0, 1], [0, 5]], axis=1)
array([1, 5])np.sum([[0, 1], [0, 5]], axis=1)
array([1, 5])
But when I try np.sum(testGroup, axis=1) I get an axis error as I suppose the empty arrays have a dimension less than one?
I've also tried summing it directly arraySum = sum(testGroup) but get a ValueError
Any ideas on how to achieve a sum of the arrays inside the
testGroup list?
testGroup is a plain python list, that happens to contain numpy.array elements. Instead you can use a list comprehension
>>> [np.sum(a) for a in testGroup]
[18, 0, 241, 32]
Try
list(map(np.sum, testGroup))
it gives
[18, 0, 241, 32]
You might use so-called list-comprehension to apply function to each element of list as follow
import numpy as np
testGroup = [np.array([18]), np.array([], dtype=np.int64), np.array([56, 75, 55, 55]), np.array([32])]
totals = [np.sum(i) for i in testGroup]
print(totals)
output
[18, 0, 241, 32]
I am looking for the equivalent of an SQL 'where' query over a table. I have done a lot of searching and I'm either using the wrong search terms or not understanding the answers. Probably both.
So a table is a 2 dimensional numpy array.
my_array = np.array([[32, 55, 2],
[15, 2, 60],
[76, 90, 2],
[ 6, 65, 2]])
I wish to 'end up' with a numpy array of the same shape where eg the second column values are >= 55 AND <= 65.
So my desired numpy array would be...
desired_array([[32, 55, 2],
[ 6, 65, 2]])
Also, does 'desired_array' order match 'my_array' order?
Just make mask and use it.
mask = np.logical_and(my_array[:, 1] >= 55, my_array[:, 1] <= 65)
desired_array = my_array[mask]
desired_array
The general Numpy approach to filtering an array is to create a "mask" that matches the desired part of the array, and then use it to index in.
>>> my_array[((55 <= my_array) & (my_array <= 65))[:, 1]]
array([[32, 55, 2],
[ 6, 65, 2]])
Breaking it down:
# Comparing an array to a scalar gives you an array of all the results of
# individual element comparisons (this is called "broadcasting").
# So we take two such boolean arrays, resulting from comparing values to the
# two thresholds, and combine them together.
mask = (55 <= my_array) & (my_array <= 65)
# We only want to care about the [1] element in the second array dimension,
# so we take a 1-dimensional slice of that mask.
desired_rows = mask[:, 1]
# Finally we use those values to select the desired rows.
desired_array = my_array[desired_rows]
(The first two operations could instead be swapped - that way I imagine is more efficient, but it wouldn't matter for something this small. This way is the way that occurred to me first.)
You dont mean the same shape. You probably meant the same column size. The shape of my_array is (4, 3) and the shape of your desired array is (2, 3). I would recommend masking, too.
You can use a filter statement with a lambda that checks each row for the desired condition to get the desired result:
my_array = np.array([[32, 55, 2],
[15, 2, 60],
[76, 90, 2],
[ 6, 65, 2]])
desired_array = np.array([l for l in filter(lambda x: x[1] >= 55 and x[1] <= 65, my_array)])
Upon running this, we get:
>>> desired_array
array([[32, 55, 2],
[ 6, 65, 2]])
Can I change multiple items in a list at one time in Python?
Question1:
For example,my list is
lst=[0,0,0,0,0]
I want to the third and fifth item become 99.I know I can do it by
lst[2] = 99
lst[4] = 99
However, is there any easier way to do this?
Question2:in the situation,my target value is[99,98], my index is [2,4],so my result would be [0,0,99,0,98]. Is there any easy way to do this? Thanks.
You could do like this,
>>> lst=[0,0,0,0,0]
>>> target = [99,98]
>>> pos = [2,4]
>>> for x,y in zip(pos,target):
lst[x] = y
>>> lst
[0, 0, 99, 0, 98]
You can use slice assignment as long as the set of indices you're trying to assign to can be referenced by a slice (i.e. via start, stop, increment). For example:
lst=[0,0,0,0,0]
lst[2::2] = [99, 98]
print s
# [0, 0, 99, 0, 98]
Using numpy also gives more control for such operations:
import numpy as np
lst = np.asarray([0,0,0,0,0])
lst[[2,4]]=[99, 100]
>>> lst
array([ 0, 0, 99, 0, 100])
I am trying to define a function that returns elements of a multi-dimensional variable according to a nested list of indices. I am working with variables depending on multiple dimensions like, e.g.: time, altitude, latitude, longitude.
Make it 3D for now (e.g., time, altitude and latitude):
x = np.arange(125).reshape(5,5,5)
If I now want the first 4 time steps, the first 3 altitude levels and the first 2 latitudes I can do several things:
x[[0,1,2,3],:,:][:,[0,1,2],:][:,:,[0,1]]
or
x[ [[[0]],[[1]],[[2]],[[3]]],[[0],[1],[2]],[0,1]]
or
x[np.ix_([0,1,2,3],[0,1,2],[0,1])]
But what I would like to have is a function giving me back the elements like
def get_elements( x, l )
where l is a list of indices
l = [[0,1,2,3],[0,1,2],[0,1]]
How could this function look like? The last alternative comes pretty close but x[np.ix_(l)] gives me an IndexError.
Moreover, it would be great to have the opportunity to leave dimensions untouched. E.g., using all time steps in this pseudo-code:
l = [[:],[0,1,2],[0,1]]
Thanks a lot!
Note the signature of np.ix_:
np.ix_(*args)
so you need to 'expand' l:
x[np.ix_(*l)]
Take a look at the code for ix_. Notice it does things like iterate over args, and returns a tuple. Also look at other functions in np.lib.index_tricks.
In general, if a list gives you problems when indexing, check whether you need to a tuple instead. Also familiarize yourself with slice.
To directly answer your question about making a function, using your list as you're constructing it, though, you'll need to use your np.ix_ function:
def get_elements(x, l):
return x[np.ix_(*l)]
However, I think you want this:
>>> x[:4,:3,:2]
array([[[ 0, 1],
[ 5, 6],
[10, 11]],
[[25, 26],
[30, 31],
[35, 36]],
[[50, 51],
[55, 56],
[60, 61]],
[[75, 76],
[80, 81],
[85, 86]]])
It returns the same as this:
x[np.ix_([0,1,2,3],[0,1,2],[0,1])]
There's a great answer on slicing here: https://stackoverflow.com/a/24713353/541136
You can name your slice objects and pass them like this:
>>> first_four_slice = slice(None, 4)
>>> first_three_slice = slice(None, 3)
>>> first_two_slice = slice(None, 2)
>>> x[first_four_slice, first_three_slice, first_two_slice]
You can pack them all together in a single variable too:
>>> slice_tuple = first_four_slice, first_three_slice, first_two_slice
>>> x[slice_tuple]
And get your all "time steps" (i.e., get all from that dimension) like this:
>>> all_slice = slice(None)
>>> x[all_slice, first_three_slice, first_two_slice]
As far as I can tell, this is not officially not possible, but is there a "trick" to access arbitrary non-sequential elements of a list by slicing?
For example:
>>> L = range(0,101,10)
>>> L
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
Now I want to be able to do
a,b = L[2,5]
so that a == 20 and b == 50
One way besides two statements would be something silly like:
a,b = L[2:6:3][:2]
But that doesn't scale at all to irregular intervals.
Maybe with list comprehension using the indices I want?
[L[x] for x in [2,5]]
I would love to know what is recommended for this common problem.
Probably the closest to what you are looking for is itemgetter (or look here for Python 2 docs):
>>> L = list(range(0, 101, 10)) # works in Python 2 or 3
>>> L
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
>>> from operator import itemgetter
>>> itemgetter(2, 5)(L)
(20, 50)
If you can use numpy, you can do just that:
>>> import numpy
>>> the_list = numpy.array(range(0,101,10))
>>> the_indices = [2,5,7]
>>> the_subset = the_list[the_indices]
>>> print the_subset, type(the_subset)
[20 50 70] <type 'numpy.ndarray'>
>>> print list(the_subset)
[20, 50, 70]
numpy.array is very similar to list, just that it supports more operation, such as mathematical operations and also arbitrary index selection like we see here.
Just for completeness, the method from the original question is pretty simple. You would want to wrap it in a function if L is a function itself, or assign the function result to a variable beforehand, so it doesn't get called repeatedly:
[L[x] for x in [2,5]]
Of course it would also work for a string...
["ABCDEF"[x] for x in [2,0,1]]
['C', 'A', 'B']
Something like this?
def select(lst, *indices):
return (lst[i] for i in indices)
Usage:
>>> def select(lst, *indices):
... return (lst[i] for i in indices)
...
>>> L = range(0,101,10)
>>> a, b = select(L, 2, 5)
>>> a, b
(20, 50)
The way the function works is by returning a generator object which can be iterated over similarly to any kind of Python sequence.
As #justhalf noted in the comments, your call syntax can be changed by the way you define the function parameters.
def select(lst, indices):
return (lst[i] for i in indices)
And then you could call the function with:
select(L, [2, 5])
or any list of your choice.
Update: I now recommend using operator.itemgetter instead unless you really need the lazy evaluation feature of generators. See John Y's answer.
None of the other answers will work for multidimensional object slicing. IMHO this is the most general solution (uses numpy):
numpy.ix_ allows you to select arbitrary indices in all dimensions of an array simultaneously.
e.g.:
>>> a = np.arange(10).reshape(2, 5) # create an array
>>> a
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
>>> ixgrid = np.ix_([0, 1], [2, 4]) # create the slice-like grid
>>> ixgrid
(array([[0],
[1]]), array([[2, 4]]))
>>> a[ixgrid] # use the grid to slice a
array([[2, 4],
[7, 9]])