Trying to construct identity matrix? [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 6 years ago.
Write a function identity(n) that returns the n identity
matrix.
For example: identity(3) outputs [[1,0,0][0,1,0][0,0,1]]
I have tried as follow:
def identity(n):
matrix=[[0]*n]*n
i=0
while i<n:
matrix[i][i]=1
i+=1
return matrix
Also I tried with range but it did'n work like this
def identity(n):
matrix=[[0]*n]*n
k=matrix[:]
i=0
for i in range(1,n):
matrix[i][i]=1
i+=1
return k
print(identity(5))
But it output for n = 5:
[[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]

If numpy is not allowed ... Know this How to define two-dimensional array in python
and do this
def identity(n):
m=[[0 for x in range(n)] for y in range(n)]
for i in range(0,n):
m[i][i] = 1
return m

This is because the way you are initializing matrix. Each sublist of [[0]*n]*n is the same list [0]*n, or in other words, each row of your matrix is a reference to the same underlying row. You can verify this using id:
> x = [[0]*3]*3
> x
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
> id(x[0])
140017690403112
> id(x[1])
140017690403112
> id(x[2])
140017690403112
TTherefore, when you assign a value to the ith row of your matrix, you're assigning it to all rows. So avoid nested list creation using [0]*n. Instead, use
matrix = [[0]*n for _ in range(n)]
Even simpler, avoid all of this with:
import numpy as np
np.eye(n)

Numpy has this built in, you can just use np.eye(n):
In [1]: import numpy as np
In [2]: x = np.eye(4)
In [3]: x
Out[3]:
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])

Related

Split self-intersecting linestring into non-self-intersecting linestrings

I have a list of coordinates defining a line string that might intersect with itself:
coordinates = [
[0, 3],
[0, 5],
[4, 5],
[4, 0],
[0, 0],
[0, 5],
[2, 5]
]
How can I split the linestring into smaller linestrings so none of the linestrings intersects with itself?
smallest number of linestrings
line strings should have equal number of coordinates as possible
the desired outcome in this case would be:
line0 = [
[0, 3],
[0, 5],
[4, 5],
[4, 0]
]
line1 = [
[4, 0],
[0, 0],
[0, 5],
[2, 5]
]
My attempt
In my attempt so far I construct an intersection matrix using Shapely Linestrings to find the intersections:
from shapely.geometry import LineString
from itertools import product, zip_longest
import numpy as np
def get_intersection_matrix(coordinates):
linestrings = [
(ix, LineString([c0, c1]))
for ix, (c0, c1) in enumerate(zip(coordinates[:-1], coordinates[1:]))
]
M = np.zeros((len(linestrings), len(linestrings)))
for (ix0, ls0), (ix1, ls1) in combinations(linestrings, 2):
if abs(ix0 - ix1) == 1: # ignore connecting segments
continue
if ls0.intersects(ls1):
M[ix0, ix1], M[ix1, ix0] = 1, 1
return M
which outputs what I call the "intersection matrix":
>> get_intersection_matrix(coordinates)
array([[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0]])
That you can read as:
segment 1 intersects with segment 5 and 6
segment 2 intersects with segment 5 and 6
segment 5 intersects with segment 1 and 2
segment 6 intersects with segment 1 and 2
Also; I think that the number of "intersection clusters" indicate the number of linestrings: no_clusters + 1
How I solve it now... I changed my intersection matrix, so at no intersection the value is 1 and at any intersection the value is 0.
def get_intersection_matrix(coordinates):
linestrings = [
(ix, LineString([c0, c1]))
for ix, (c0, c1) in enumerate(zip(coordinates[:-1], coordinates[1:]))
]
M = np.ones((len(linestrings), len(linestrings)))
for (ix0, ls0), (ix1, ls1) in combinations(linestrings, 2):
if abs(ix0 - ix1) == 1: # ignore connecting segments
continue
if ls0.intersects(ls1):
M[ix0, ix1], M[ix1, ix0] = 0, 0
return M
>> M = get_intersection_matrix(coordinates)
>> M
array([[1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1.],
[0., 0., 1., 1., 1., 1.],
[0., 0., 1., 1., 1., 1.]])
any combination of split indexes is given by: itertools.combinations(range(1, len(M)), nr_split_ixs) where also ix1 < ix2 < ... < ixn
at one split index you get two squares that should not contain any 0's, and the squares can be optimized by a minimum sum!
This is a legal (but not the best) split with split_ix = 4 and the sum of the two boxes is 16+4 = 20.
This is a better legal (no zeros) split where the sum of the two boxes is 9+9=18
The method to calculate the scored split indexes:
def get_scored_split_ixs_combination(M, nr_split_ixs):
ixs_scores = []
for ixs in combinations(range(1, len(M)), nr_split_ixs):
splitted_matrix = [
M[i0:i1, i0:i1] for i0, i1 in zip((0, *ixs), (*ixs, len(M)))
]
# check if no matrices have zeros
if not all([(m > 0).all() for m in splitted_matrix]):
# ilegal ixs combination
continue
ixs_scores.append((ixs, sum([m.sum() for m in splitted_matrix])))
return ixs_scores
if the return is empty there are no legal options and you should increase the number of splits.
Now return the best split option by increment the number of splits:
def get_best_split_ixs_combination(M):
nr_split_ixs = 0
while True:
ixs_scores = get_scored_split_ixs_combination(M, nr_split_ixs)
if ixs_scores:
return min(ixs_scores, key=lambda x: x[1])[0]
nr_split_ixs +=1
>> get_best_split_ixs_combination(M)
(3,)
And finally wrap it all together:
def get_non_intersecting_linestrings(coordinates):
M = get_intersection_matrix(coordinates)
split_indexes = get_best_split_ixs_combination(M)
return [
coordinates[i1:i2]
for i1, i2 in zip([0] + split_indexes, split_indexes + [len(coordinates)])
]
>> get_non_intersecting_linestrings(coordinates)
[[[0, 3], [0, 5], [4, 5]], [[4, 0], [0, 0], [0, 5], [2, 5]]]

Numpy replacing elements based on logic and value in an identically shaped array [duplicate]

This question already has answers here:
How do I select elements of an array given condition?
(6 answers)
Closed 3 years ago.
I have 2 numpy arrays. One is filled with boolean values and the other numerical values.
How would I perform logic on the numerical array based on also the current value in the boolean array.
e.g. if true and > 5 then make the value false
matrix1
matrix2
newMatrix = matrix1 > 5 where matrix2 value is false
Please note that these arrays have the same shape e.g.
[[0, 1, 1],
[1, 0, 0]]
and
[[3, 1, 0]
[6, 2, 6]]
And the result I would like would be a new boolean matrix that is true if its value is true in the boolean array and the equivalent value in the numerical array is more than 5 e.g.
[[0, 0, 0]
[1, 0, 0]]
newMatrix = np.logical_and(matrix2 == 0, matrix1 > 5 )
This will iterate over all elements, and make an 'and' between pairs of booleans from matrix == 0 and matrix1 > 5. Note that matrix1 > 5 type of expression generates a matrix of boolean values.
If you want 0,1 instead of False,True, you can add +0 to the result:
newMatrix = np.logical_and(matrix2 == 0, matrix1 > 5 ) + 0
The clearest way:
import numpy as np
matrix1 = np.array([[3, 1, 0],
[6, 2, 6]])
matrix2 = np.array([[0, 1, 1],
[1, 0, 0]])
r,c = matrix1.shape
res = np.zeros((r,c))
for i in range(r):
for j in range(c):
if matrix1[i,j]>5 and matrix2[i,j]==1:
res[i,j]=1
result
array([[0., 0., 0.],
[1., 0., 0.]])
A fancier way, using numpy.where():
import numpy as np
matrix1 = np.array([[3, 1, 0],
[6, 2, 6]])
matrix2 = np.array([[0, 1, 1],
[1, 0, 0]])
r,c = matrix1.shape
res = np.zeros((r,c))
res[np.where((matrix1>5) & (matrix2==1))]=1
result
array([[0., 0., 0.],
[1., 0., 0.]])

Initializing a N x M matrix in python

I'm trying to learn python. In it, I'm trying to dynamically generate a N x M matrix in python, where each cell contains the index value of that cell in python.
The matrix would look like:
[0,1,2,3,4
0,1,2,3,4
...]
I know that in java it would go something like:
a={}{}
for (i=0;i<N;i++)
for (j=0;j<M:j++)
a[i][j] = i
Where N is the width of the matrix and M is the height of the matrix
Except in python it seems like I can't iterate on a matrix on the basis of the cell placement, rather I need to iterate on the basis of the elements in the cell. From my experience something like
a = [][]
a = np.zeroes((N, M))
[ 0, 0, 0
0, 0, 0]
in the case where N = 3, and M = 2
and then the same style of a loop:
j = 0
for i in len(a):
a[i][j] = i
if i == len(a):
j = j+1
doesn't work because python can't iterate on the basis of the places of the elements. Perhaps I am wrong. Would this work? Is there a better way to make such a matrix and fill it with the indexed values?
Since you're already using NumPy, you could use numpy.arange and numpy.tile:
In [26]: N = 5
In [27]: M = 4
In [28]: np.tile(np.arange(N), (M, 1))
Out[28]:
array([[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]])
Another option is to create a row using np.arange(5) and assign it to every row of zeros matrix.
In [22]: m = np.zeros((4,5))
In [23]: m[:,] = np.arange(5)
In [24]: m
Out[24]:
array([[ 0., 1., 2., 3., 4.],
[ 0., 1., 2., 3., 4.],
[ 0., 1., 2., 3., 4.],
[ 0., 1., 2., 3., 4.]])
Some example similar to your Java example, but with python syntax sugar.
>>> N=M=5
>>> for z in [[n for n in xrange(N)] for m in xrange(M)]:
... print z
...
[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]
Here is the code in which matrix contain index value of that cell:
n,m=map(int,raw_input().split())
a=n*[m*[0]]
j=0
for i in range (0,n):
for j in range(0,m):
a[i][j]=j
for i in range (0,n):
for j in range(0,m):
print a[i][j],
print

array manipulation in numpy

How to obtain new array (new) from original array (x) by calculating mean as follows:
new = [[mean(1,3), mean(1,3), mean(1,3), mean(1,3), mean(1,3)],[mean(2,4),mean(2,4),mean(2,4),mean(2,4),mean(2,4)]]
import numpy as np
arr1 = np.array([[1,1,1,1,1],[2,2,2,2,2]])
arr2 = np.array([[3,3,3,3,3],[4,4,4,4,4]])
my_array = np.array([arr1,arr2])
for x in my_array:
new = np.mean(x,axis=1)
print (new)
IMPORTANT:
The arr1, arr2, and my_array are not really available as inputs, what is available is only x. So, the real data to be manipulated are in the form of for loop given by x as shown above.
Given my_array as defined above
>>> my_array
array([[[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2]],
[[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]]])
You simply need to take the mean over the first axis as follows:
>>> my_array.mean(axis=0)
array([[ 2., 2., 2., 2., 2.],
[ 3., 3., 3., 3., 3.]])
If it must be iterative for subsequent x you could do the following:
sums = 0
counter = 0
for x in my_array:
sums += x
counter += 1
new = sums / counter
Or, if you can store the data:
data = []
for x in my_array:
data.append(x)
new = np.dstack(data).mean(axis=2)

numpy append array to array

I'm trying to append one numpy array to another numpy array, like this:
import numpy as np
meanings = 2
signals = 4
def new_agent(agent_type, context_size):
if agent_type == 'random':
comm_system = np.random.random_integers(0, 1, (meanings, signals))
if agent_type == 'blank':
comm_system = np.zeros((meanings, signals), int)
score_list = np.array([0., 0., 0., 0.])
np.append(comm_system, score_list)
np.append(comm_system, context_size)
return comm_system
if I now call:
random_agent = new_agent('random', 5)
I expect to get something like:
[[0 1 0 0]
[1 1 0 1]
[0. 0. 0. 0.]
5]
But instead I get only:
[[0 1 0 0]
[1 1 0 1]]
So the score_list and the context_size don't get appended. And the same holds for when I call new_agent() with 'blank'.
Thanks!
You can use hstack and vstack to concatenate arrays:
>>> from numpy import array, hstack, vstack
>>> a = array([1, 2, 3])
>>> b = array([4, 5, 6])
>>> hstack([a, b])
array([1, 2, 3, 4, 5, 6])
>>> vstack([a, b])
array([[1, 2, 3],
[4, 5, 6]])
numpy.append() returns a new array containing the data from its inputs together. It does not modify the inputs themselves, and there would be no way for it to do so. This is because arrays in NumPy are generally not resizable.
Try changing your code to capture the value returned from append(), which will be the array you want.
#John is correct about how to use the return value from numpy.append because it doesn't modify the original array. However, there's a problem with your expected output:
[[0 1 0 0]
[1 1 0 1]
[0. 0. 0. 0.]
5]
is not a possible numpy array because of two reasons: one is that some elements are integers and some are floats, but a numpy array's dtype must be uniform; the other is that each row is not the same length, but numpy arrays must have uniform (rectangular) shape.
I think what you might rather do is to just return all three things:
comm_system as an array of ints,
score_list as an array of floats,
and context_size as an int (not an array).
You can do that with a tuple:
def new_agent(agent_type, context_size):
if agent_type == 'random':
comm_system = np.random.random_integers(0, 1, (meanings, signals))
if agent_type == 'blank':
comm_system = np.zeros((meanings, signals), int)
score_list = np.zeros(signals) #This is different too! No need to type out the 0, 0, ...
# now just return all three:
return comm_system, score_list, context_size
Then you can "unpack" the tuple like so:
random_agent, scores, size = new_agent('random', 5)
Or just keep them all in one tuple:
random_agent_info = new_agent('random', 5)
And you'll have
In [331]: random_agent, scores, size = new_agent('random', 5)
In [332]: random_agent
Out[332]:
array([[0, 1, 1, 0],
[0, 1, 0, 1]])
In [333]: scores
Out[333]: array([ 0., 0., 0., 0.])
In [334]: size
Out[334]: 5
In [336]: random_agent_info
Out[336]:
(array([[1, 1, 0, 1],
[0, 1, 0, 0]]),
array([ 0., 0., 0., 0.]),
5)
In [337]: random_agent_info[0]
Out[337]:
array([[1, 1, 0, 1],
[0, 1, 0, 0]])
In [338]: random_agent_info[1]
Out[338]: array([ 0., 0., 0., 0.])
In [339]: random_agent_info[2]
Out[339]: 5
If you do want to have the comm_system and score_list to be one (3,2) array, you can do that with:
def new_agent(agent_type, context_size):
...
return np.vstack([comm_system, score_list]), context_size
Then you'll get one array and one int:
In [341]: random_agent, size = new_agent('random', 5)
In [342]: random_agent
Out[342]:
array([[ 1., 0., 1., 1.],
[ 1., 0., 1., 0.],
[ 0., 0., 0., 0.]])
In [343]: size
Out[343]: 5

Categories

Resources