Print the row and column numbers of a matrix-python - python

I am trying to print the row number and column number of a matrix where the value is 1.
For example:
A=[0 1 0]
[1 0 1]
[1 0 0]
I want the output to be displayed as:(row number followed by the corresponding column)
0 1
1 0 2
2 0
I tried to use enumerate() but it gave me different kind of output.
G={i: [j for j, y in enumerate(row) if y] for i, row in enumerate(A)}
print (G)

Python's indices are zero-based. You have done everything correctly, but just need to add a couple of +1s to get the output you expected. Also, dictionaries are unordered by nature, so you would be better off just using a list of tuples:
G = [(i+1, [j+1 for j, y in enumerate(row) if y]) for i, row in enumerate(A)]
Or better still; just a 2d list using the indices as the first column when you need them.

Related

Looping backwards in python and getting the index

There are multiple ways to loop back in python
For example we have
arr=[5,6,8]
for i in range(len(arr)-1, -1, -1):
print(i," ",arr[i])
which gives
2 8
1 6
0 5
I can solve what I need with that, but I am curious. There is another way to loop back which is
for im in arr[::-1]:
print(im)
Looks nice, right?
This gives
8
6
5
My question is, using this second method is there a way to get not only the element but also the index? (the 2,1,0)
There's a builtin for that: reversed. This might be more readable and intuitive than using a range or slice with negative step.
For just the index, you can pass the range to reversed directly:
arr = list("ABC")
for i in reversed(range(len(arr))):
print(i, arr[i])
# 2 C
# 1 B
# 0 A
For index and element, you have to collect the enumerate iterator into a list before reversing:
for i, x in reversed(list(enumerate(arr))):
print(i, x)
# 2 C
# 1 B
# 0 A
use the builtin method reversed
arr = [5, 6, 8]
for i in reversed(range(0,len(arr))):
print(i,arr[i])
Here's a way using reversed() and zip() that should be memory efficient:
arr = [5, 6, 8]
for idx, elem in zip(reversed(range(len(arr))),
reversed(arr)
):
print(idx, elem)
Output:
2 8
1 6
0 5
for idx, elem in list(enumerate(arr))[::-1]:
print(idx, elem)
This uses enumerate to keep elements with their specific index. Then we convert it to list and reverse (enumerate result is not reversible without converting). No need to keep track of any order (like subtracting) manually
You can also just reverse the forward range:
for idx in range(len(arr))[::-1]:
print(idx, arr[idx])
Python actually reverses range in a smart way, without converting it to a list, so it works even for big stuff:
>>> range(10)[::-1]
range(9, -1, -1)
This means that range(len(arr))[::-1] will work in exactly the same way, with exactly the same speed, as your range(len(arr)-1, -1, -1) while looking nice!
i = len(arr) - 1
for im in arr[::-1]:
print(i, " ", im)
i -= 1
You can use enumerate and subtract from the initial length:
arr=[5,6,8]
for i,im in enumerate(arr[::-1]):
print(len(arr)-i-1, im)
output:
2 8
1 6
0 5
The normal way to iterate with an index is with enumerate. One can use this to index the other way by subtracting the index from the length of the sequence:
In [51]: arr = [5, 6, 8]
...: for i, n in enumerate(arr):
...: print(i, n)
...:
0 5
1 6
2 8
In [52]: for i, n in enumerate(reversed(arr)):
...: print(len(arr) - i - 1, n)
...:
2 8
1 6
0 5
Note that reversed doesn't create a new list in memory and is preferable to [::-1] if just iterating.

Numpy Matrix Modulo Index Extraction

Suppose I have a 2-dimensional matrix A, say
A = np.mat([[1,2,3,4],
[5,6,7,8],
[9,10,11,12]])
how can I change all elements in row 1 with column index modulo 2 to 0? I.e., I would like to obtain
np.mat([[1,2,3,4],
[0,6,0,8],
[9,10,11,12]])
I have tried
A[1][np.arange(len(A))%2==0] = 0
which results in IndexError.
Column index % 2 = 0 means that the index is an even integer.
You can change the elements of the first row at even column indexes to 0 as follows:
A[1, ::2] = 0 # 2 is the step
If you want to do it as your (incorrect) A[1][np.arange(len(A))%2==0] = 0, you should change it to
A[1, np.arange(A.shape[1]) % 2 == 0] = 0
where A.shape[1] is the number of columns (whereas len(A) gives you the number of rows).

How to replace repeated consecutive elements in a 2d numpy array with single element

I have a numpy array of shape(1080,960)
[[0 0 255 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 255 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 255 255 ... 0 0 0]]
I want to output a numpy array that replaces the repeated values of both 0 and 255 with a single 0 and a single 255
The numpy array is a representation of a binary image that has pixels in the form BBBWWWWWWWBBBBWWW where B is black and W is white. I want to convert it into BWBW.
Example:
input:
[[0,0,0,255,255,255,0,0,0,0],
[255,255,255,0,0,0,255,255,255],
[0,0,255,0,0,255,0,0,255]]
output:
[[0,255,0],
[255,0,255]
[0,255,0,255,0,255]]
You cannot output a 2D numpy array because output rows may have different lengths. I would settle for a list of numpy arrays. So 1st let's generate some data:
img = np.random.choice([0,255], size=(1080, 960))
Then iterate over each row:
out=[]
for row in img:
idx=np.ediff1d(row, to_begin=1).nonzero()[0]
out.append(row[idx])
By taking the difference we are simply detecting where changes take place, and then using those indices idx to select the starting element in a consecutive streak. This solution is a bit simpler and faster than the the one by #DavidWinder (30 ms vs. 150 ms).
A fully vectorized solution can be a bit faster, but the code would be a bit complex. It would involve flattening arrays, raveling and unraveling indices... and applying np.split at the end, which is not a very fast operation because it involves creating a list. So I think this answer is good enough compromise between speed/code simplicity.
Edit #1
If the preferred output is an array padded with 0s at the end, it is better to create a zeros array and fill it with values of out list. First find out which row has more elements, and create array:
max_elms = np.max([len(x) for x in out])
arr = np.zeros((1080, max_elms), dtype=np.int32)
And then iterate over out list and arr, filling values of arr with the ones in out list:
for row, data in zip(arr, out):
row[:len(data)] = data
You can iterate over the rows and group the element by build new array while checking last elements and append only if difference.
Function as follow:
def groupRow(row):
newRow = [row[0]]
for elem in row:
if elem != newRow[-1]:
newRow.append(elem)
return newRow
Iterate and replace every row in the shape with the newRow from that function

Counting conditional occurrences in an array

I have a 2D array of the form: np.zeros((m,n)).
My objective is to look at the first 2 columns, I want to find the element in the first column that is occurring the most (so the mode of the first column), however I do not want to count it twice if the second column is the same.
5x3 example:
[[1 2 x], [1 2 y], [1 3 z], [5 3 w], [5 6 v], [9 2 x], [9 2 y],]
Desired output, i.e. the number of occurrences of:
[1]: 2
[5]: 2
[9]: 1
So in a way it is a counter function but conditional on a second array (column 2).
I am relatively new to Python, is there a function that can do this directly and somewhat efficiently? I need to run it on very large matrices, but could not find such a function.
This funciotn solves your problem.
def count_special(arr):
counter = {}
for i in np.unique(arr[:,0]):
sec = arr[arr[:,0]==i,1]
counter[i] = len(np.unique(sec))
return counter
which, for your input, returns:
arr = np.array([[1,2,0],[1,2,4],[1,3,4],[5,3,1],[5,6,0]])
print(count_special(arr))
-> {1: 2, 5: 2}

select elements from two unequal length numpy arrays

consider two numpy arrays
array1 = np.arange(0,6)
array2 = np.arange(0,12)
i want to a run a loop (preferably a list comprehension) where the desire output for a single round is
print(array1[0])
print(array2[0],array2[1]) or
print(array1[1])
print(array2[2], array2[3])
ie the loop runs six times, but for every round in array1 it selects the two consecutive elements from array2.
I have tried something like
for i in xrange(array1):
for v in xrange(array2):
but this evidently runs the second loop inside the first one, How can i run them simultaneously but select different number of elements from each array in one round?
I have also tried making the loops equal in length such as
array1 = np.repeat(np.arange(0,6),2).ravel()
array1 = [0,0,1,1,2,2.....5,5]
however, this will make the length of the two arrays equal but i still cannot get the desired output
(In actual case, the elements of the array are pandas Series objects)
There are a bunch of different ways of going about this. One thing you can do is use the indices:
for ind, item in array1:
print(item, array2[2*ind:2*ind+2])
This does not use the full power of numpy, however. The easiest thing I can think of is to concatenate your arrays into a single array containing the desired sequence. You can make it into a 2D array for easy iteration, where each column or row will be the sequence of three elements you want:
array1 = np.arange(6)
array2 = np.arange(12)
combo = np.concatenate((array1.reshape(-1, 1), array2.reshape(-1, 2)), axis=1)
for row in combo:
print(row)
Results in
[0 0 1]
[1 2 3]
[2 4 5]
[3 6 7]
[4 8 9]
[ 5 10 11]
In this case, the explicit reshape of array1 is necessary because array1.T will result in a 1D array.
You can use a hybrid of the two approaches, as #Divakar suggests, where you reshape a2 but iterate using the index:
array3 = array2.reshape(-1, 2)
for ind, item in array1:
print(item, array3[ind])
Yes, as #MadPhysicist mentioned, there are a lot of ways to do this.... but the simplest is
>>> for x,y,z in zip(array1,array2[:-1:2],array2[1::2]):
... print x,y,z
...
0 0 1
1 2 3
2 4 5
3 6 7
4 8 9
5 10 11
for i in xrange(array1):
print(array1[i])
print(array2[2*i],array2[2*i+1])

Categories