Grouping 0s and 1s in python - python

I have an array of zeros and ones like [0,0,0,1,1,1,0,0,0,1,1]. How to write a program to save neighboring 0's and 1's in different arrays.
E.g.
[0,0,0,1,1,1,0,0,0,1,1] giving [0,0,0],[1,1,1],[0,0,0],[1,1].

You can group them with itertools.groupby, like this
>>> data = [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1]
>>> from itertools import groupby
>>> [list(group) for item, group in groupby(data)]
[[0, 0, 0], [1, 1, 1], [0, 0, 0], [1, 1]]
The result of groupby, will be a tuple of actual item and an iterator which gives the grouped items. We just convert the grouped items to a list, with list(group).
As per the comments,
>>> data = [1, 2, 1, 3, 4, 5, 6, 7, 1, 2, 3]
>>> flag = [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1]
Create a generator which will give the values multiplied,
>>> gen = (d * v for d, v in zip(data, flag))
Now, group based on the result of calling bool on each of the numbers. So, if the bool is called on 0, it will give False, otherwise True.
>>> [list(g) for _, g in groupby(gen, key=bool)]
[[0, 0, 0], [3, 4, 5], [0, 0, 0], [2, 3]]

Related

How to add an array twice by two TRUE conditions?

this is my code:
import numpy as np
from scipy.ndimage.interpolation import shift
B = np.array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
F = np.array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
M = np.array([[1, 2, 1, 2, 1],
[1, 2, 1, 2, 1],
[1, 2, 1, 2, 0],
[1, 2, 1, 2, 1],
[1, 2, 1, 2, 1]])
if F[2, 4] == 1:
B = np.add(M, B)
if F[1, 4] == 1:
M_shift = shift(M, (-1, 0), cval=0)
B = np.add(M_shift, B)
print(B)
I want to add M to B if the condition for F is true. In this example both if-conditions are true and i thought that my code will add two times M to B. But apparently it's not working? What is wrong?
Thanks in advance.
EDIT for arra:
My desired output is in this case, my code snippet should add the matrix with B and also the shifted version of M. Because both conditions are True. But as u said the first assignment is overwritten. How can I prevent the overwriting for this case?
The output, after the assignment should look like this:
B = np.array([[2, 4, 2, 4, 2],
[2, 4, 2, 4, 1],
[2, 4, 2, 4, 1],
[2, 4, 2, 4, 2],
[1, 2, 1, 2, 1]])
I guess a good way is to use a for-loop because i want to check all array entries in Matrix F, if there's a 1. But i reckon that if i use the np.add function I'll overwrite it again
You overwrite B in the second if, so any previous value will be erased. Not sure what you are trying to achieve in your code, but don't you want something like:
B = np.add(M_shift, B)
or
intermediateVal = np.add(M_shift, F)
B = np.add(B, intermediateVal)

Swapping two columns in a 2D list

what would be the quickest way to get to :
[[0, 2, 0, 0],\
[0, 2, 0, 0],\
[0, 2, 0, 0],\
[0, 2, 0, 0]]
from:
[[0, 0, 2, 0],\
[0, 0, 2, 0],\
[0, 0, 2, 0],\
[0, 0, 2, 0]]
without using numpy or any other external library
For your specific task:
l = [[0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0]]
for arr in l:
arr[1], arr[2] = arr[2], arr[1]
Let's say we have a list l, which is [0, 0, 2, 0], and we want to shift all the elements one place to left.
Firstly, we need to get all the elements to the right except the first one. List slicing l[1:] would work here, which would get [0, 2, 0].
Secondly, we need to get the remaining elements on the left with l[1:], which would get [0].
You can now probably see that we can shift the elements one place to the left with adding the above 2 lists together:
>>> lst = [0, 0, 2, 0]
>>> first = lst[1:]
>>> second = lst[:1]
>>> first + second
[0, 2, 0, 0]
Which can be summarized in this function:
def shift(lst, n):
return lst[n:] + lst[:n]
Since this can shift one lists position, it can applied to all lists in a nested list and shift their positions to left by 1:
nested_lst = [shift(sublist, 1) for sublist in nested_lst]

Count how often integer y occurs right after integer x in a numpy array

I have a very large numpy.array of integers, where each integer is in the range [0, 31].
I would like to count, for every pair of integers (a, b) in the range [0, 31] (e.g. [0, 1], [7, 9], [18, 0]) how often b occurs right after a.
This would give me a (32, 32) matrix of counts.
I'm looking for an efficient way to do this with numpy. Raw python loops would be too slow.
Here's one way...
To make the example easier to read, I'll use a maximum value of 9 instead of 31:
In [178]: maxval = 9
Make a random input for the example:
In [179]: np.random.seed(123)
In [180]: x = np.random.randint(0, maxval+1, size=100)
Create the result, initially all 0:
In [181]: counts = np.zeros((maxval+1, maxval+1), dtype=int)
Now add 1 to each coordinate pair, using numpy.add.at to ensure that duplicates are counted properly:
In [182]: np.add.at(counts, (x[:-1], x[1:]), 1)
In [183]: counts
Out[183]:
array([[2, 1, 1, 0, 1, 0, 1, 1, 1, 1],
[2, 1, 1, 3, 0, 2, 1, 1, 1, 1],
[0, 2, 1, 1, 4, 0, 2, 0, 0, 0],
[1, 1, 1, 3, 3, 3, 0, 0, 1, 2],
[1, 1, 0, 1, 1, 0, 2, 2, 2, 0],
[1, 0, 0, 0, 0, 0, 1, 1, 0, 2],
[0, 4, 2, 3, 1, 0, 2, 1, 0, 1],
[0, 1, 1, 1, 0, 0, 2, 0, 0, 3],
[1, 2, 0, 1, 0, 0, 1, 0, 0, 0],
[2, 0, 2, 2, 0, 0, 2, 2, 0, 0]])
For example, the number of times 6 is followed by 1 is
In [188]: counts[6, 1]
Out[188]: 4
We can verify that with the following expression:
In [189]: ((x[:-1] == 6) & (x[1:] == 1)).sum()
Out[189]: 4
You can use numpy's built-in diff routine together with boolean arrays.
import numpy as np
test_array = np.array([1, 2, 3, 1, 2, 4, 5, 1, 2, 6, 7])
a, b = (1, 2)
sum(np.bitwise_and(test_array[:-1] == a, np.diff(test_array) == b - a))
# 3
If your array is multi-dimensional, you will need to flatten it first or make some small modifications to the code above.

Searching numpy array for for pattern

I'd like to find a value in a numpy array given a search pattern. For instance for the given array a, I want to retrieve a result of 1 when using the search pattern s because 1 is the element at index 0 of a[:,1] (=array([1, 0, 0, 1])) and the elements of a[1:,1] match s (i.e. (a[1:,1] == s).all() == True => return a[0,1]).
Another example would be s=[1, 0, 1] for which I would expect a search result of 2 (match at 4th column starting (1-based)). 2 would also be the search result for s=[2, 0, 0], etc.
>>> import numpy as np
>>> a = np.asarray([[0, 1, 2, 2, 2, 2, 2, 2], [0, 0, 1, 1, 2, 2, 3, 3], [0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0, 1]])
>>> a
array([[0, 1, 2, 2, 2, 2, 2, 2],
[0, 0, 1, 1, 2, 2, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 0, 1]])
>>> s = np.asarray([0, 0, 1])
I came up with a[0, np.where((a[1:,:].transpose() == s).all(axis=-1))[0][0]], but thought there must be something more elegant...
Additionally, it would be great if I could do this operation with one call on multiple search patters, so that I retrieve the 0-element for which the values of index 1 to index 3 match.
Single search pattern
Here's one approach with help from broadcasting and slicing -
a[0,(a[1:] == s[:,None]).all(0)]
Multiple search patterns
For multiple search patterns (stored as 2D array), we just need to broadcast as before and look for ANY match at the end -
a[0,((a[1:] == s[...,None]).all(1)).any(0)]
Here's a sample run -
In [327]: a
Out[327]:
array([[0, 1, 2, 2, 2, 2, 2, 2],
[0, 0, 1, 1, 2, 2, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 0, 1]])
In [328]: s
Out[328]:
array([[1, 0, 1],
[2, 0, 0]])
In [329]: a[0,((a[1:] == s[...,None]).all(1)).any(0)]
Out[329]: array([2, 2])

Insert value dynamically in 2D list python

I am having a two dimensional list like:
[[1, 1, 0, 0], [1, 0, 1, 0], [0, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 1, 1, 0], [1, 1, 1, 1]]
and I want to XOR the inner sub-lists with each other. So at some point of time with some combination I will be getting a sub list with all zeros like [0,0,0,0] and if I don't get with two sub lists I have to go for XORing of three sub-lists till I get again [0,0,0,0], if not then, have to go for four sub-lists.
The problem is I can do like picking up two lists and XOR each element then save it in separate sub-list and this works but each time I have to change my code so is there any way to XOR sub-list like [1, 1, 0, 0] ^ [1, 0, 1, 0] instead of doing like lis[i][j]^lis[i+1][j] so that I can manage my code recursively?
You could find shorter but I think this would work:
STOP=[0,0,0,0]
def nxor(l,res=None,p=1):
if not res: res= l[0]
if res == STOP:
return p-1 # or l[:p]
try:
return nxor(l,list(iter.imap (operator.xor, *list([res,l[p]]) )),p+1)
except:
return None # or res
print nxor (l)
It returns the position of the last sub-list that lead to [0,0,0,0]; it would be easy to return the sub-list instead, or the actual result (see comments).
If you want to test all the combinations, you could use itertools:
for i in xrange(2,len(l)):
for j in itertools.combinations(l,i):
print nxor(list(j))
What you could do is to convert the 2-D bit lists to a 1-D number list and then XOR them together.
a = [[1, 1, 0, 0], [1, 0, 1, 0], [0, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 1, 1, 0], [1, 1, 1, 1]]
b = map(lambda x: int("".join(map(lambda y: str(y), x)),2), a)
b is now: [12, 10, 6, 14, 14, 6, 15]
Now you are working with a 1-D list which will make that easier.

Categories

Resources