Specific submatrix extraction in Python - python

it's a really simple problem, but I can't find any solution to it.
If I have a matrix
A = np.array([[1,2,4,2],[1,2,35,4],[3,4,7,0],[8,3,2,6]])
and I want to extract the submatrix made by the first, second and fourth column and first second and fourth row
In MATLAB I would do simply A([1,2,4],[1,2,4]), but I can't do that in Python.
Is there any fast way to do that? I need to avoid for loops since I'm working on a finite element code.

Solution to your problem is np.ix_:
A[np.ix_([0,1,3], [0,1,3])]
Output:
array([[1, 2, 2],
[1, 2, 4],
[8, 3, 6]])

If you have a matrix like this
matrix = [
[1, 2, 4, 2],
[1, 2, 35, 4],
[3, 4, 7, 0],
[8, 3, 2, 6]
];
And you need recover the columns and rows cross, you want the result for:
[1,2,4], [1,2,4]
=>
[
[1:1 1:2 1:4]
[2:1 2:2 2:4]
[4:1 4:2 4:4]
]
This is a simple implementation.
def subMatrix(m, cols, rows):
result = []
for col in cols:
newRow = []
for row in rows:
newRow.append(m[col-1][row-1])
result.append(newRow)
return result
subMatrix(m=matrix, cols=[1,2,4], rows=[1,2,4])

Related

Add repeated elements of array indexed by another array

I have a relatively simple problem that I cannot solve without using loops. It is difficult for me to figure out the correct title for this problem.
Lets say we have two numpy arrays:
array_1 = np.array([[0, 1, 2],
[3, 3, 3],
[3, 3, 4],
[3, 6, 2]])
array_2 = np.array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 4, 4],
[5, 5, 5],
[6, 6, 6]])
array_1 represents indices of the rows in array_2 that we want to sum. So for example, 4th row in result array should contain summed all rows in array_2 that have same row indices as all 3s in array_1.
It is much easier to understand it in the code:
result = np.empty(array_2.shape)
for i in range(array_1.shape[0]):
for j in range(array_1.shape[1]):
index = array_1[i, j]
result[index] = result[index] + array_2[i]
Result should be:
[[ 0 0 0]
[ 0 0 0]
[ 3 3 3]
[10 10 10]
[ 2 2 2]
[ 0 0 0]
[ 3 3 3]]
I tried to use np.einsum but I need to use both elements in array as indices and also its rows as indices so I'm not sure if np.einsum is the best path here.
This is the problem I have in graphics. array_1 represent indices of vertices for triangles and array_2 represents normals where index of a row corresponds to the index of the vertex
Any time you're adding something from a repeated index, normal ufuncs like np.add don't work out of the box because they only process a repeated fancy index once. Instead, you have to use the unbuffered version, which is np.add.at.
Here, you have a pair of indices: the row in array_1 is the row index into array_2, and the element of array_1 is the row index into the output.
First, construct the indices explicitly as fancy indices. This will make it much simpler to use them:
output_row = array_1.ravel()
input_row = np.repeat(np.arange(array_1.shape[0]), array_1.shape[1]).ravel()
You can apply input_row directly to array_2, but you need add.at to use output_row:
output = np.zeros_like(array_2)
np.add.at(output, output_row, array_2[input_row])
You really only use the first four rows of array_2, so it could be truncated to
array_2 = array2[:array_1.shape[0]]
In that case, you would want to initialize the output as:
output = np.zeros_like(array_2, shape=(output_row.max() + 1, array2.shape[1]))

Nested arrays in python

If i have a nested array lets say:
arr = [[1, 2, 3, 4], [5, 6, 7, 8]]
I want to divide element wise so my output would be:
[5/1, 6/2, 7/3, 8/4]
Just using fractions to be clear on what i'm asking. Thank you
Try to use the zip() function:
d=[] #This is done to avoid name 'd' is not defined
arr = [[1, 2, 3, 4], [5, 6, 7, 8]]
zipped = zip(arr[1], arr[0])
for i1,i2 in zipped:
d.append(i1/i2)
You can easily do this with numpy.
Extract the second row, and divide it by the first row element wise:
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
np.array(arr[1, :] / arr[0, :])
# [5. 3. 2.33333333 2. ]
If instead you want to do it with a for loop:
[arr[1][i] / arr[0][i] for i in range(len(arr[0]))]

Numpy: operations on columns (or rows) of NxM array

This may be a silly question, but I've just started using numpy and I have to figure out how to perform some simple operations.
Suppose that I have the 2x3 array
array([[1, 3, 5],
[2, 4, 6]])
And that I want to perform some operation on the first column, for example subtract 1 to all the elements to get
array([[0, 3, 5],
[1, 4, 6]])
How can I perform such an operation?
arr
# array([[1, 3, 5],
# [2, 4, 6]])
arr[:,0] = arr[:,0] - 1 # choose the first column here, subtract one and
# assign it back to the same column
arr
# array([[0, 3, 5],
# [1, 4, 6]])

how to search for unique elements by the first column of a multidimensional array

I am trying to find a way how to create a new array from a multidimensional array by taking only elements that are unique in the first column, for example if I have an array
[[1,2,3],
[1,2,3],
[5,2,3]]
After the operation I would like to get this output
[[1,2,3],
[5,2,3]]
Obviously the second an third columns do not need to be unique.
Thanks
Since you are looking to keep the first row of first column uniqueness, you can just use np.unique with its optional return_index argument which will give you the first occurring index (thus fulfils the first row criteria) among the uniqueness on A[:,0] elements, where A is the input array. Thus, we would have a vectorized solution, like so -
_,idx = np.unique(A[:,0],return_index=True)
out = A[idx]
Sample run -
In [16]: A
Out[16]:
array([[1, 2, 3],
[5, 2, 3],
[1, 4, 3]])
In [17]: _,idx = np.unique(A[:,0],return_index=True)
...: out = A[idx]
...:
In [18]: out
Out[18]:
array([[1, 2, 3],
[5, 2, 3]])
main = [[1, 2, 3], [1, 3, 4], [2, 4, 5], [3, 6, 5]]
used = []
new = [[sub, used.append(sub[0])][0] for sub in main if sub[0] not in used]
print(new)
# Output: [[1, 2, 3], [2, 3, 4], [3, 6, 5]]

How to use a pair of nested for loops to iterate over a 2-d array?

Need to take the values from one array, put them through a function and put them in another array. It is meant to be done using a pair of nested for loops. Please help. Complete beginner here.
EDIT: Ok to clarify, I have a 2-d array with various values in it. I want to apply a function to all of these values and have a 2-d array returned with the values after they have gone through the function. I am working in python. Thanks for the quick responses and any help you can give!
EDIT3: Example code:
import numpy as N
def makeGrid(dim):
''' Function to return a grid of distances from the centre of an array.
This version uses loops to fill the array and is thus slow.'''
tabx = N.arange(dim) - float(dim/2.0) + 0.5
taby = N.arange(dim) - float(dim/2.0) + 0.5
grid = N.zeros((dim,dim), dtype='float')
for y in range(dim):
for x in range(dim):
grid[y,x] = N.sqrt(tabx[x]**2 + taby[y]**2)
return grid
import math
def BigGrid(dim):
l= float(raw_input('Enter a value for lambda: '))
p= float(raw_input('Enter a value for phi: '))
a = makeGrid
b= N.zeros ((10,10),dtype=float) #Create an arry to take the returned values
for i in range(10):
for j in range (10):
b[i,j] = a[i][j]*2
if __name__ == "__main__":
''' Module test code '''
size = 10 #Dimension of the array
newGrid = BigGrid(size)
newGrid = N.round(newGrid, decimals=2)
print newGrid
def map_row(row):
return map(some_function,row)
map(map_row,my_2d_list)
Is probably how I would do it...
Based on your question, it appears you're using Numpy. If you're not too concerned about speed, you can simply call the function with a numpy array; the function will operate on the entire array for you.
There's no need to write the iteration explicitly, though if you can find a way to take advantage of numpy's special features, that will be faster than using a function designed to operate on one element at a time. Unless you're working with a very large dataset, though, this should be fine:
import numpy as np
>>> g = np.array( [ [1,2,3], [ 4,5,6] ] )
array([[1, 2, 3],
[4, 5, 6]])
>>> def myfunc( myarray ):
... return 2 * myarray
...
>>> myfunc(g)
array([[ 2, 4, 6],
[ 8, 10, 12]])
First, you have a bug in your code in the following line:
a = makeGrid
You are setting a to be a function, not an array. You should have the following:
a = makeGrid(dim)
That is why you had the TypeError when you tried the answer by #abought.
Now, to apply an operation element-wise in numpy there are many possibilities. If you want to perform the same operation for every element in the array, the simplest way is to use array operations:
b = a * 2
(Note that you don't need to declare b beforehand. And you also don't need any loops.) Numpy has also many C-optimised functions that perform the same operation on each element of an array. These are called ufuncs. You can combine ufuncs to get complex expressions evaluated element-wise. For example:
b = N.sin(a**2) + N.log(N.abs(a))
Your a array from makeGrid() can also be much more efficiently created using array operations and numpy's mgrid:
grid = N.mgrid[-dim//2 + 1:dim//2:0.5, -dim//2 + 1:dim//2:0.5]
grid = N.sqrt(grid[0]**2 + grid[1]**2)
If you want to perform different operations on each array element, things get more complicated and it may not be possible to avoid loops. For these cases, numpy has a way to decompose loops on a nD array using ndenumerate or ndidex. Your example with ndenumerate:
for index, x in N.ndenumerate(a):
b[index] = x * 2
This is faster than multiple loops, but the array operations should be used whenever possible.
From what I can get in terms of context from the question and what a 2d-array typically means it looks like you are trying to do the following:
>>>> array2d = [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
>>> def add_two( v ):
... return v + 2
...
>>> [ [ add_two( v ) for v in row ] for row in array2d ]
[[2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6]]
The above uses a list comprehension which is the same as using the two nested for loops and in this case more readable and involves less direct interaction of the list methods as you're describing what the list is rather than building it.
Here is a one-line with double map
map(lambda x:map(func, x), l)
Example:
l=[[1,2,3],[4,3,1]]
map(lambda x:map(lambda x:x*10,x),l)
[[10, 20, 30], [40, 30, 10]]
Easy to do it with a nested loop:
def my_function(n): # n will become y from the next part
new_num = # do whatever you want with it
return new_num
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # just an example
new_list, final_list = [], [] # multiple assignment
for x in my_list:
print x
new_list = []
for y in x:
# y is now the first value of the first value of my_list--- 1.
my_num = my_function(y)
new_list.append(my_num)
final_list.append(new_list)
print final_list
That should do it.
Returns: [[2, 3, 4], [5, 6, 7], [8, 9, 10]].
for(int i; i < x; i++)
for(int j; j < y; j++)
array2[i][j] = func(array2[i][j])
Something like that?

Categories

Resources