Notation of swapping rows on a numpy array in Python - python

Lets say we have a numpy array:
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]])
Can anyone explain why this line is used to swap two rows(in this occasion the 1st with the 4th)?
'A[[0, 3]] = A [[3, 0]]'

You are updating the positions of two subarrays simultaneously.
However, doing:
A[0] = A[3]
A[3] = A[0]
would not work because the subarray A[0] has already been updated, so you need to do it simultaneously with:
A[[0, 3]] = A [[3, 0]]
A
array([[10, 11, 12],
[ 4, 5, 6],
[ 7, 8, 9],
[ 1, 2, 3]])

Related

Rearranging the values inside a NumPy array

lets assume that i have a numpy array and its like this:
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]]
and I like to have a new numpy array, that the first half exactly the same as array above but second half it should be started from the bottom till it reaches the half of array. how do I do that?
EDIT: The method i need it has to work for an array with 60000 elements. not for this simple example!!
Output should be like this:
[[1, 2, 3],
[4, 5, 6],
[10, 11, 12],
[7, 8, 9]]
Use numpy indexes:
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
array[[0,1,3,2], :]
array([[ 1, 2, 3],
[ 4, 5, 6],
[10, 11, 12],
[ 7, 8, 9]])
Another solution would be to simply swap the rows with an assignment, like:
arr[2], arr[3] = arr[3], arr[2]
After your edit, here's a solution that inverts just the bottom half of the array:
arr = np.array([[...],...])
arr[int(len(a)/2):] = arr[int(len(a)/2):][::-1]
[::-1] returns the elements of an array in reverse order. So applying it to the bottom half of the original array and assigning this new array to the bottom half of the original array will give you an array with the first n/2 rows unchanged and last n/2 rows in reverse order.
This might be kinda crude but you simply need to replace the 3rd (index = 2) row in array e with the 4th (index = 3) row. 'a' is a placeholder for switching the 3rd and 4th row.
for i in range(len(e)):
if i == 2:
a = e[i]
e[i] = e[3]
if i == 3:
e[i] = a
Takes always half the array as requested. (Based on mathfux's answer)
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
sl = range(0, len(array)//2)
s2 = reversed(range(len(array)//2, len(array)))
b = array[(*sl, *s2), :]
print(b)
prints
[[ 1 2 3]
[ 4 5 6]
[10 11 12]
[ 7 8 9]]
Of course cou could just index the last half:
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
from_to = tuple(range(len(array)//2, len(array)))
to_from = tuple(reversed(from_to))
array[from_to, :] = array[to_from, :]
print(array)
Same result.
array = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
n = (int)(array.shape[0]//2) # change n accordingly
# n is the row number from which you want to start the reversal
temp = array[n:]
temp = temp[::-1]
array[n:] = temp

How to create a 2D array of ranges using numpy

I have an array of start and stop indices, like this:
[[0, 3], [4, 7], [15, 18]]
and i would like to construct a 2D numpy array where each row is a range from the corresponding pair of start and stop indices, as follows:
[[0, 1, 2],
[4, 5, 6],
[15, 16, 18]]
Currently, i am creating an empty array and filling it in a for loop:
ranges = numpy.empty((3, 3))
a = [[0, 3], [4, 7], [15, 18]]
for i, r in enumerate(a):
ranges[i] = numpy.arange(r[0], r[1])
Is there a more compact and (more importantly) faster way of doing this? possibly something that doesn't involve using a loop?
One way is to use broadcast to add the left hand edges to the base arange:
In [11]: np.arange(3) + np.array([0, 4, 15])[:, None]
Out[11]:
array([[ 0, 1, 2],
[ 4, 5, 6],
[15, 16, 17]])
Note: this requires all ranges to be the same length.
If the ranges were to result in different lengths, for a vectorized approach you could use n_ranges from the linked solution:
a = np.array([[0, 3], [4, 7], [15, 18]])
n_ranges(a[:,0], a[:,1], return_flat=False)
# [array([0, 1, 2]), array([4, 5, 6]), array([15, 16, 17])]
Which would also work with the following array:
a = np.array([[0, 3], [4, 9], [15, 18]])
n_ranges(*a.T, return_flat=False)
# [array([0, 1, 2]), array([4, 5, 6, 7, 8]), array([15, 16, 17])]

Sum each row of a numpy array with all rows of second numpy array (python)

I would like to know if there is any fast way to sum each row of a first array with all rows of a second array. In this case both arrays have the same number of colulmns. For instance if array1.shape = (n,c) and array2.shape = (m,c), the resulting array would be an array3.shape = ((n*m), c)
Look at the example below:
array1 = np.array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
array2 = np.array([[0, 1, 2],
[3, 4, 5]])
The result would be:
array3 = np.array([[0, 2, 4],
[3, 5, 7]
[3, 5, 7]
[6, 8, 10]
[6, 8, 10]
[9, 11, 13]])
The only way I see I can do this is to repeat each row of one of the arrays the number of rows of the other array. For instance, by doing np.repeat(array1, len(array2), axis=0) and then sum this array with array2. This is not very practical however if the number of rows is too big. The other way would be with a for loop but this is too slow.
Any other better way to do it..?
Thanks in advance.
Extend array1 to 3D so that it becomes broadcastable against 2D array2 and then perform broadcasted addition and a final reshape is needed for desired output -
In [30]: (array1[:,None,:] + array2).reshape(-1,array1.shape[1])
Out[30]:
array([[ 0, 2, 4],
[ 3, 5, 7],
[ 3, 5, 7],
[ 6, 8, 10],
[ 6, 8, 10],
[ 9, 11, 13]])
You could try the following inline code if you haven't already. This is the simplest and probably also the quickest on a single thread.
>>> import numpy as np
>>> array1 = np.array([[0, 1, 2],
... [3, 4, 5],
... [6, 7, 8]])
>>>
>>> array2 = np.array([[0, 1, 2],
... [3, 4, 5]])
>>> array3 = np.array([i+j for i in array1 for j in array2])
>>> array3
array([[ 0, 2, 4],
[ 3, 5, 7],
[ 3, 5, 7],
[ 6, 8, 10],
[ 6, 8, 10],
[ 9, 11, 13]])
>>>
If you are looking for speed up by treading, you could consider using CUDA or multithreading. This suggestion goes a bit out of scope of your question but gives you an idea of what can be done to speed up matrix operations.

selecting values from array with indexes and summing over them

I have two arrays, values and indexes
>>> values
array([[5, 4, 2, 4, 6],
[7, 9, 7, 3, 6]])
>>> indexes
array([[2, 4],
[0, 3],
[0, 1],
[1, 3]])
What i would like is a fast way (as my arrays are very large) to get, for each value of values the sum of the elements corresponding to all index collections that are in indexes.
I.e I want, for the first value [5, 4, 2, 4, 6] to get
>>> values[0][indexes.flatten()].reshape(indexes.shape)
array([[2, 6],
[5, 4],
[5, 4],
[4, 4]])
>>> values[0][indexes.flatten()].reshape(indexes.shape).sum(axis=1)
array([8, 9, 9, 8])
using this technique and looping over all values is the fastest I could come up with. Is there a better way? Thank you in advance for your time.
Approach #1
Simply index into columns and sum along the last axis -
values[:,indexes].sum(axis=-1)
Sample run -
In [39]: values
Out[39]:
array([[5, 4, 2, 4, 6],
[7, 9, 7, 3, 6]])
In [40]: indexes
Out[40]:
array([[2, 4],
[0, 3],
[0, 1],
[1, 3]])
In [41]: values[:,indexes].sum(axis=-1)
Out[41]:
array([[ 8, 9, 9, 8],
[13, 10, 16, 12]])
Approach #2
If there are no duplicates in each row of indexes, we can simply use matrix-multiplication to get the sum-reductions and this would be much faster -
m,n = indexes.shape[0], values.shape[1]
mask = np.zeros((n,m),dtype=bool) # faster with float dtype
mask[indexes, np.arange(m)[:,None]] = 1
out = values.dot(mask)

How to set a value to elements in a column filtered by another array

I have an m X 3 matrix and an array of length m.
I want to do the following
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]])
b = np.array([1, 2, 1, 3, 3])
me = np.mean(a[np.where(b==1)][:, 0])
a[np.where(b==1)][:, 0] = me
The problem is that
a[np.where(b==1)][:, 0]
returns [1, 7] instead of [4, 4].
You are combining index arrays with slices:
[np.where(b==1)] is a index array, [:, 0] is a slice. The way you do it a copy is returned and therefore you set the new values on the copy. You should instead do:
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]])
b = np.array([1, 2, 1, 3, 3])
me = np.mean(a[np.where(b==1)][:, 0])
a[np.where(b==1), 0] = me
Also see https://docs.scipy.org/doc/numpy/user/basics.indexing.html for combining index arrays with slices.

Categories

Resources