How do I form a matrix identity? [duplicate] - python

This question already has answers here:
Trying to understand nested loops, identity matrix
(4 answers)
Closed 8 years ago.
What I'm trying to accomplish here is to generate a matrix of size n x n. Whatever the matrix is, I have to fill in the number 1 from the top-left corner to the bottom-right corner and 0 everywhere else.
def identity(m):
new_identity = []
old_identity = m
for i in range(len(old_identity)):
new_identity.append(old_list[1])
return new_identity
For example, if the matrix was 3 then the expected result would be:
[[1, 0, 0], [0, 1, 0], [0, 0, 1]]
Or to make it easier to visualize:
[[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]

where n is the size of the identity to make
def identity(n):
return [[1 if i==j else 0 for j in range(n)] for i in range(n)]

This one might not be the most pythonic, but it's faster than the other solution.
def identity(m):
result = []
for i in range(m):
row = [0]*m
row[i] = 1
result.append(row)
return result
On my machine, for a 500x500 matrix, my function takes 3.13 ms to execute, while the python list comprehension solution (that makes m² comparisons) takes 47.48 ms to complete.
Of course, you should use xrange instead of range if you're using python 2.x

Related

Indexed array filled incorrectly [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
I just started programming with Python and I have a question concerning 2D arrays.
I need to create a matrix (numpy forbidden) of a certain size from av[1] and save it so that I can multiply it with another one later on.
The logical thing for me was:
1- Get the length of av[1]; 2- Transform the av[1][] to it's ASCII equivalent with ord and finally 3- Insert that value into a list called key_matrix.
The matrix needs to be the smallest size possible and in a "square form", so I calculate the smallest square containing the len of av[1] ( called matrix_size ) and then I initialize my array like this:
key_matrix = [[0] * matrix_size] * matrix_size;
Like that I get my square matrix filled with 0.
If matrix_size = 3 for example I get:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Now the strange part is (and also the part that I'm stuck on) the following, I use
index1 = 0;
index2 = 0;
key_matrix[index1][index2] = ord(sys.argv[1][0]);
print(key_matrix);
to fill only the 1st element of the 1st line.
While the result should be:
[[97, 0, 0], [0, 0, 0], [0, 0, 0]]
I get:
[[97, 0, 0], [97, 0, 0], [97, 0, 0]]
Me and my friends really cant seem to figure out the reason why it does this, any help is welcome!
Thank you all for reading :)
The memory address of the lists are the same when you write [[0] * matrix_size] * matrix_size, it basically reuses the memory address of the first [0] * matrix_size array as the same reference for multiple times for other lists. Since these lists are not independent from memory address perspective, we would have issue modifing only one of the list. You can do below as a quick fix for the issue:
>>> key_matrix2 = [[0] *3 for i in range(matrix_size)]
>>> key_matrix2
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> key_matrix2[0][1] = 2
>>> key_matrix2
[[0, 2, 0], [0, 0, 0], [0, 0, 0]]

vectorize array: construct matrix with 1 in specified places and 0 elsewhere [duplicate]

This question already has answers here:
NumPy selecting specific column index per row by using a list of indexes
(7 answers)
Convert array of indices to one-hot encoded array in NumPy
(22 answers)
Closed 3 years ago.
I have a (1-dimensional) numpy array a of length L, filled with numbers from 0 to N-1.
Now, I want to construct a NxL matrix such that in each column c, the a[c]'th entry is 1 and all other entries are 0.
For example, If L=4, N=5 and
a = np.array([1,2,0,4])
then we'd want a matrix
m = np.array([[0,0,1,0],
[1,0,0,0],
[0,1,0,0],
[0,0,0,0],
[0,0,0,1]])
Now, I have the following code:
def vectorize(a, L, N):
m = np.zeros((N, L))
for (i,x) in enumerate(a):
m[x][i] = 1.0
return m
This works fine, but I'm sure there is a faster method using some numpy trick (that avoids looping over a).
When you use an array of integers as an index, you need other arrays that broadcast to the same shape to indicate the placement in the other dimensions. In your case, each element of a is a row index. The corresponding column is:
b = np.arange(L)
Now you can index directly into the matrix m:
m = np.zeros((N, L), dtype=bool)
m[a, b] = True
When you index a numpy array, you should use all the indices in a single bracket operator, rather than separate operators like m[a][b]. m[a] is a copy of the portion of m when a is an array of integers, but a view of the original data when a is a single integer, which is the only reason your example works.
You can use an np.arange(..) for the second axis:
def vectorize(a, L, N):
m = np.zeros((N, L), int)
m[a, np.arange(len(a))] = 1
return m
So for the given sample input, we get:
>>> a = np.array([1,2,0,4])
>>> vectorize(a, 4, 5)
array([[0, 0, 1, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 1]])
def vectorize(a, L, N):
m = np.zeros((N, L))
m[a,np.arange(L)] =1
return m

Generating binary lists that sum to a given number

I am attempting Project Euler #15, which essentially reduces to computing the number of binary lists of length 2*size such that their entries sum to size, for the particular case size = 20. For example, if size = 2 there are 6 such lists: [1,1,0,0], [1,0,1,0], [1,0,0,1], [0,1,1,0], [0,1,1,0], [0,1,0,1], [0,0,1,1]. Of course the number of such sequences is trivial to compute for any value size and is equal to some binomial coefficient but I am interested in explicitly generating the correct sequences in Python. I have tried the following:
import itertools
size = 20
binary_lists = itertools.product(range(2), repeat = 2*size)
lattice_paths = {lists for lists in binary_lists if sum(lists) == size}
but the last line makes me run into memory errors. What would be a neat way to accomplish this?
There are far too many for the case of size=20 to iterate over (even if we don't materialize them, 137846528820 is not a number we can loop over in a reasonable time), so it's not particularly useful.
But you can still do it using built-in tools by thinking of the positions of the 1s:
from itertools import combinations
def bsum(size):
for locs in combinations(range(2*size), size):
vec = [0]*(2*size)
for loc in locs:
vec[loc] = 1
yield vec
which gives
>>> list(bsum(1))
[[1, 0], [0, 1]]
>>> list(bsum(2))
[[1, 1, 0, 0], [1, 0, 1, 0], [1, 0, 0, 1], [0, 1, 1, 0], [0, 1, 0, 1], [0, 0, 1, 1]]
>>> sum(1 for x in bsum(12))
2704156
>>> factorial(24)//factorial(12)**2
2704156
I'm not 100% sure of the math on this problem, but your last line is taking a generator and dumping it into a list, and based on your example, and your size of 20, that is a massive list. If you want to sum it, just iterate, but I don't think you can get a nice view of every combo

python how to change value of elements of sublists? [duplicate]

This question already has answers here:
Creating lists of lists in a pythonic way
(8 answers)
Closed 9 years ago.
I have the following code:
matrix = [[0] * 3] * 3
matrix[0][0] = 2
I want to get the following result:
[[2, 0, 0], [0, 0, 0], [0, 0, 0]]
However it changes the first element of each sublist and returns this list:
[[2, 0, 0], [2, 0, 0], [2, 0, 0]]
If I define matrix as follow:
matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
then it works.
Could anyone tell me please, why it happens and how could solve this problem?
Thanks
This is happening because [[0] * 3] * 3 is actually creating an array of 3 of the same object (the [0] * 3 array). One way of looking at it is that the inner array is created once and copied. An alternative would be to use [[0] * 3 for x in xrange(3)], as this executes [0] * 3 each iteration in list comprehension, creating a new array each time.
Here's your problem, matrix, in this example, is basically identical to:
>>> a = [0,0,0]
>>> matrix1 = [a,a,a]
that means when you do matrix1[0][0] = 2, what Python does is follow its pointer located at the first index of matrix1, which points to object a, then looks at the pointer located at the first index of a, which reads 0, then changes that to 2. Then when you ask it to evaluate matrix1, it looks up a three times and finds [2,0,0] each time.
Sean had a good solution above mine, using list comprehensions to force new objects instead of adding pointers for objects that already exist. That may serve you better :)
Python assigns by pointer rather than value* which sometimes leads to undesirable results such as this one. Here is a tutorial that explains what is really happening: http://www.python-course.eu/variables.php Here is one possible fix http://www.python-course.eu/deep_copy.php
*(as has been pointed out this is not quite right, however it similar in result to what happens in other languages like C which I'm more familiar with if you passed a pointer to a variable rather than a copy of the value of the variable.)

Python multiple dimension arrays [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to initialize a two-dimensional array in Python?
In solving a simple problem regarding a two dimensional array I came across a solution on this site that explained how to declare one in Python using the overload operator.
Example:
Myarray = [[0]*3]*3
this would produce the following array (list)
[[0,0,0],[0,0,0],[0,0,0]]
This seems fine until you use it:
if you assign an element for example:
Myarray [0][0] = 1
you get the unexpected output:
[[1,0, 0],[1,0,0] , [1,0,0]]
In effect assigning Myarray [1][0] and Myarray[2][0] at the same time
My solution:
Myarray = [[][][]]
for i in range(0,3):
for j in range (0,3):
Myarray[i].append(0)
This solution works as intended:
Marray[0][1] = 1
gives you
[[1,0, 0],[0,0,0] , [0,0,0]]
Is there a simpler way to do this? This was a solution to an A level Cambridge question and seems too long winded for students compared to other languages.
With vanilla Python, you could use this, a nested list comprehension
>>> m = [[0 for y in range(3)] for x in range(3)]
>>> m
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Unlike the multiplied list you showed in your example, it has the desired behavior
>>> m[1][0] = 99
>>> m
[[0, 0, 0], [99, 0, 0], [0, 0, 0]]
However, for serious use of multidimensional arrays and/or numerical programming, I'd suggest you use Numpy arrays.

Categories

Resources