Python: using list to index [from:to] arbitrary numpy arrays - python

I want to copy a chunk from a matrix into a piece of another matrix.
To use this with any kind of n-dimensional array, I need to apply a list with offsets via the [] operator. Is there a way to do this?
mat_bigger[0:5, 0:5, ..] = mat_smaller[2:7, 2:7, ..]
like:
off_min = [0,0,0]
off_max = [2,2,2]
for i in range(len(off_min)):
mat_bigger[off_min[i] : off_max[i], ..] = ..

You can do this by creating a tuple of slice objects. For example:
mat_big = np.zeros((4, 5, 6))
mat_small = np.random.rand(2, 2, 2)
off_min = [2, 3, 4]
off_max = [4, 5, 6]
slices = tuple(slice(start, end) for start, end in zip(off_min, off_max))
mat_big[slices] = mat_small

Related

Array Prints like List but its a single integer in variable explorer? Why?

When ı print out the following code Q is prints like it suppose to be (3 5 7 9) sum of the numbers with the next one. but in the variable explorer its a single integer ı want to get the result Q as an array like
Q = [3, 5, 7, 9]
import numpy as np
A = [1, 2, 3, 4, 5]
for i in range(0,4):
Q = np.array(A[i]+A[i+1])
print(Q)
for i in range(0,4):
Q = []
Q.append(Q[i] + A[i]+A[i+1])
print(Q)
This also doesnt work
Currently you're just re-declaring Q each time and it's never added to some collection of values
Instead, start with an empty list (or perhaps a numpy array in your case) and outside of your loop and append the values to it at each loop cycle
Q is a numpy array, but it's not what you're expecting!
It has no dimensions and only references a single value
>>> type(Q)
<class 'numpy.ndarray'>
>>> print(repr(Q))
array(9)
>>> import numpy as np
>>> A = [1, 2, 3, 4, 5]
>>> Q = np.array([], dtype=np.uint8)
>>> for i in range(4):
... Q = np.append(Q, A[i]+A[i+1]) # reassign each time for np
...
>>> print(Q)
[3 5 7 9]
Note that numpy arrays should be reassigned via np.append, while a normal python list has a .append() method (which does not return the list, but directly appends to it)
>>> l = ['a', 'b', 'c'] # start with a list of values
>>> l.append('d') # use the append method
>>> l # display resulting list
['a', 'b', 'c', 'd']
If you're not forced to use a numpy array to begin with, this can be done with a list comprehension
The resulting list can also be made into a numpy array afterwards
>>> [(x + x + 1) for x in range(1, 5)]
[3, 5, 7, 9]
All together with simplified math
>>> np.array([x*2+3 for x in range(4)])
array([3, 5, 7, 9])
If you want to use Numpy, then use Numpy. Start with a Numpy array (one-dimensional, containing the values), which looks like this:
A = np.array([1, 2, 3, 4, 5])
(Yes, you initialize it from the list).
Or you can create that kind of patterned data using Numpy's built-in tool:
A = np.arange(1, 6) # it works similarly to the built-in `range` type,
# but it does create an actual array.
Now we can get the values to use on the left-hand and right-hand sides of the addition:
# You can slice one-dimensional Numpy arrays just like you would lists.
# With more dimensions, you can slice in each dimension.
X = A[:-1]
Y = A[1:]
And add the values together element-wise:
Q = X + Y # yes, really that simple!
And that last line is the reason you would use Numpy to solve a problem like this. Otherwise, just use a list comprehension:
A = list(range(1, 6)) # same as [1, 2, 3, 4, 5]
# Same slicing, but now we have to do more work for the addition,
# by explaining the process of pairing up the elements.
Q = [x + y for x, y in zip(A[:-1], A[1:])]

Find value from one float in an array

I have one array of value and I want to find what position it has in another array of values. So for example if I have:
array1 = [1,2,3,4,5,6]
array2 = [2,6,3,4,1,5,.....]
I want to find what position each element from array 1 has in array 2, so I want it to return something like
what_position = [4,0,2,3,5,1]
I've tried something like this:
for i in range(len(array1)):
what_position = array1[i].index(array[2])
but i get an error that says
'numpy.float64' object has no attribute 'index'
Which i guess means I can't use .index on a float. Is there another way I can go about this.
An alternative solution is provided by np.intersect1d:
import numpy as np
array1 = [1,2,3,4,5,6]
array2 = [2,6,3,4,1,5]
np.intersect1d(array1, array2, return_indices=True)[2]
A list comprehension helps:
positions = [array2.index(item) for item in array1]
A for loop with the same result:
positions = []
for item in array1:
positions.append(array2.index(item))
In other words, you call index() on a list, not on an individual item.
If you don’t have repeating elements in array2 you can use the following solution. It should be faster than the list comprehension with index():
from operator import itemgetter
from itertools import count
array1 = [1, 2, 3, 4, 5, 6]
array2 = [2, 6, 3, 4, 1, 5, 7, 8]
itemgetter(*array1)(dict(zip(array2, count())))
# [4, 0, 2, 3, 5, 1]

Python Numpy append array without flattening

In Python 3 I am importing several data files in a loop, and I would like to be able to store all the data in a single 2-dimensional array. I start with something like data = np.array([]) and on each iteration i want to add a new array datai = np.array([1,2,3]), how can I get my final array to look like this? [[1,2,3],[1,2,3],...,[1,2,3]]
I have tried np.append, np.concatenate, and np.stack, but none seem to work. An example code that I'm trying:
data = np.array([])
for i in range(datalen):
datai = *func to load data as array*
data = np.append(data, datai)
but of course this returns a flattened array. Is there any way I can get back a 2-dimensional array of length datalen with each element being the array datai?
Thanks!
The fastest way would be vstack
data = np.vstack((get_data() for i in range(datalen)))
vstack requires a tuple/iterable
data = np.vstack((data1, data2, data3))
or you can do this by appending with axis=0
data = np.empty(shape=(0, 3))
data = np.append(data, datai.reshape((-1, 3)), axis=0) # -1 will make the rows automatic
You can reshape your array using np.reshape like this
flattened_array = np.array([1,2,3,1,2,3,1,2,3])
wanted_array = np.reshape(flattened_array, (-1, 3))
This would result in
[[1, 2, 3],[1, 2, 3],[1, 2, 3]]
Solution 1 using list comprehensions:
data = []
datalen = 4
datai = range(1,4)
data = [list(datai) for _ in range(datalen)]
print (data)
Output
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
Solution 2 (just a bit lengthy)
data = []
datalen = 4
for i in range(datalen):
datai = range(1,4)
data.append(list(datai))
print (data)
with the same output as above. In the second method you can also just simply use data.append(list(range(1,4))). You can choose if you want to convert datai to list or not. If you want the final output as an array, you can just use np.array()
You can try this-
data = np.zeros(shape=(datalen,len(datai))
for i in range(datalen):
data[i] = datai
It's called numpy.tile.
From the official docs:
>>> c = np.array([1,2,3,4])
>>> np.tile(c,(3,1))
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
so, for your datai do np.tile(datai,(N_repeats,1))

Replace values in a large list of arrays (performance)

I have a performance problem with replacing values of a list of arrays using a dictionary.
Let's say this is my dictionary:
# Create a sample dictionary
keys = [1, 2, 3, 4]
values = [5, 6, 7, 8]
dictionary = dict(zip(keys, values))
And this is my list of arrays:
# import numpy as np
# List of arrays
listvalues = []
arr1 = np.array([1, 3, 2])
arr2 = np.array([1, 1, 2, 4])
arr3 = np.array([4, 3, 2])
listvalues.append(arr1)
listvalues.append(arr2)
listvalues.append(arr3)
listvalues
>[array([1, 3, 2]), array([1, 1, 2, 4]), array([4, 3, 2])]
I then use the following function to replace all values in a nD numpy array using a dictionary:
# Replace function
def replace(arr, rep_dict):
rep_keys, rep_vals = np.array(list(zip(*sorted(rep_dict.items()))))
idces = np.digitize(arr, rep_keys, right=True)
return rep_vals[idces]
This function is really fast, however I need to iterate over my list of arrays to apply this function to each array:
replaced = []
for i in xrange(len(listvalues)):
replaced.append(replace(listvalues[i], dictionary))
This is the bottleneck of the process, as it needs to iterate over thousands of arrays.
How could I do achieve the same result without using the for-loop? It is important that the result is in the same format as the input (a list of arrays with replaced values)
Many thanks guys!!
This will do the trick efficiently, using the numpy_indexed package. It can be further simplified if all values in 'listvalues' are guaranteed to be present in 'keys'; but ill leave that as an exercise to the reader.
import numpy_indexed as npi
arr = np.concatenate(listvalues)
idx = npi.indices(keys, arr, missing='mask')
remap = np.logical_not(idx.mask)
arr[remap] = np.array(values)[idx[remap]]
replaced = np.array_split(arr, np.cumsum([len(a) for a in listvalues][:-1]))

Reverse part of an array using NumPy

I am trying to use array slicing to reverse part of a NumPy array. If my array is, for example,
a = np.array([1,2,3,4,5,6])
then I can get a slice b
b = a[::-1]
Which is a view on the original array. What I would like is a view that is partially reversed, for example
1,4,3,2,5,6
I have encountered performance problems with NumPy if you don't play along exactly with how it is designed, so I would like to avoid "fancy" indexing if it is possible.
If you don't like the off by one indices
>>> a = np.array([1,2,3,4,5,6])
>>> a[1:4] = a[1:4][::-1]
>>> a
array([1, 4, 3, 2, 5, 6])
>>> a = np.array([1,2,3,4,5,6])
>>> a[1:4] = a[3:0:-1]
>>> a
array([1, 4, 3, 2, 5, 6])
You can use the permutation matrices (that's the numpiest way to partially reverse an array).
a = np.array([1,2,3,4,5,6])
new_order_for_index = [1,4,3,2,5,6] # Careful: index from 1 to n !
# Permutation matrix
m = np.zeros( (len(a),len(a)) )
for index , new_index in enumerate(new_order_for_index ):
m[index ,new_index -1] = 1
print np.dot(m,a)
# np.array([1,4,3,2,5,6])

Categories