Selecting indexes of elements with a common property in Python - python

I have a numpy array and would like to obtain the indexes of the elements that verify a common property. For example, suppose the array is np.array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1]), and I want to have the indexes of all elements equal to 1, so the output would be [0, 4, 5, 8, 10, 14].
I have defined the following procedure
def find_indexes(A):
res = []
for i in range(len(A)):
if A[i] == 1:
res.append(i)
return res
Is there a more "pythonesque" way of doing this? More specifically, I am wondering if there is something similar to boolean indexing:
A[A>=1]
that would return the indexes of the elements rather than the elements themselves.

use np.where.
import numpy as np
x = np.array(np.array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1])
indices, = np.where(x == 1)
print(indices)

Use numpy.where
arr = np.array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1])
print np.where(arr == 1)
(array([ 0, 4, 5, 8, 10, 14]),)

List comprehension for pure python:
ar = [i for i in range(len(a)) if a[i] == 1]

Related

Changing the elements of one array with respect to the other in Python

I have two arrays as shown below.
import numpy as np
y1 = [1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1]
y2 = [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1]
y1_a = np.array(y1)
y2_a = np.array(y2)
print(y1_a)
print(y2_a)
I have to modify 'y2_a' array under this condition:
Whenever 'y1_a' is 1 in a given array position and if 'y2_a' is 0 in that same array position, then I have to replace 'y2_a' with 1. I do not want to do this for the 0 values in 'y1_a'.
I have to write this modified array to another array variable.
It looks like you can use the bitwise or operator here. Something like
for i in range(len(y2_a)):
y2_a[i] = y1_a[i] | y2_a[i]
This will keep the ones that are already in y2_a and flip the 0s in y2_a if there is a 1 in that position in y1_a
You can use:
out = y1_a | y2_a
output:
array([1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1])
You can use numpy.where.
# Whenever 'y1_a==1' and 'y2_a==0', we set '1'
# for other conditions we set 'y2_a'.
res = np.where(y1_a & ~y2_a, 1, y2_a)
print(res)
Output: array([1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1])

Replace a single value with multiple values

Given a mask numpy array such as:
mask = np.array([0, 0, 1, 0, 0, 0, 1, ...])
I want to replace each 1 with a target vector. Example:
target = np.array([5, 4, 3, 2, 1])
mask = np.array([0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,...])
output = np.array([0, 0, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, ...])
# Overlaps:
mask = np.array([0, 0, 1, 0, 0, 0, 1, 0, 0, 0,...])
output = np.array([0, 0, 5, 4, 3, 2, 5, 4, 3, 2, ...])
Naivly, one can write this via the following (ignoring boundary problems):
output = np.zeros_like(mask)
for i, x in enumerate(mask):
if x == 1:
output[i:i+len(target)] = target
I'm wondering, whether this is possible without resorting to a for loop?
numpy supports assigning value for the same index multiple times in one go, like so:
mask = np.array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0])
padding_idx = [2,3,4,5,6,5,6,7,8,9,8,9,10,11]
padding_values = [5,4,3,2,1,5,4,3,2,1,5,4,3,2]
mask[padding_idx] = padding_values
>>> mask
array([0, 0, 5, 4, 3, 5, 4, 3, 5, 4, 3, 2])
You just need to find out padding_idx and padding_values.
Note that padding_values = [5,4,3,2,1,5,4,3,2,1,5,4,3,2] has one value missing. So you need also to find a number of values missing. After that you can use broadcasting
vector = np.array([5,4,3,2,1])
N = len(vector)
mask = np.array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0])
idx = np.flatnonzero(mask)
missing_values = len(mask) - idx[-1] - N
#Broadcast
padding_idx = np.flatnonzero(mask)[:,None] + np.arange(N)
padding_values = np.repeat(vector[np.newaxis, :], len(idx), axis=0)
#Flatten
padding_idx = padding_idx.ravel()[:missing_values]
padding_values = padding_values.ravel()[:missing_values]
#Go!
mask[padding_idx] = padding_values
>>> mask
array([0, 0, 5, 4, 3, 5, 4, 3, 5, 4, 3, 2])
Not a full answer, but some thoughts: The for loop is O(n), where n = len(mask). We can use np.split to get that down to O(k), where k = number of 1s in mask:
def set_target(mask, target):
output = []
i, = np.where(mask == 1)
for split in np.split(mask, i):
if len(split) > len(target):
split[:len(target)] = target
output.append(split)
else:
output.append(target[:len(split)])
return np.concatenate(output, 0)

Comparing two lists on Python

I need help comparing two lists and returning the indices that they don't match.
a = [0, 1, 1, 0, 0, 0, 1, 0, 1]
b = [0, 1, 1, 0, 1, 0, 1, 0, 0]
indices 4 and 8 don't match and i need to return that as a list [4,8]
I've tried a few methods but they haven't worked for me.
Use zip to iterate over both lists at the same time and enumerate to get the indices during iteration, and write a list comprehension that filters out the indices where the list values don't match:
>>> [i for i, (x, y) in enumerate(zip(a, b)) if x != y]
[4, 8]
You could also just use a simple loop which scans the lists, item by item:
a = [0, 1, 1, 0, 0, 0, 1, 0, 1]
b = [0, 1, 1, 0, 1, 0, 1, 0, 0]
diff=[]
for i in range(0,len(a)):
if a[i]!=b[i]:
diff.append(i)
print diff
A list comprehension could also do the same thing:
diff=[i for i in range(len(a)) if a[i]!=b[i]]
print diff
If you are happy to use a 3rd party library, numpy provides one way:
import numpy as np
a = np.array([0, 1, 1, 0, 0, 0, 1, 0, 1])
b = np.array([0, 1, 1, 0, 1, 0, 1, 0, 0])
res = np.where(a != b)[0]
# array([4, 8], dtype=int64)
Relevant: Why NumPy instead of Python lists?
You can use zip :
a = [0, 1, 1, 0, 0, 0, 1, 0, 1]
b = [0, 1, 1, 0, 1, 0, 1, 0, 0]
count=0
indices=[]
for i in zip(a,b):
if i[0]!=i[1]:
indices.append(count)
count+=1
print(indices)
output:
[4, 8]

Take array of indices, find matching indices in another array and replace values

I have two arrays, one array that contains all indices of two arrays that meet a certain condition I had made previous to this. The other array is an array of booleans. I want to take the array of indices and find the same place in the array of booleans and replace those values.
So for example what I am looking to do is:
myIdxs = [0, 3, 5]
myBools = [1, 0, 0, 1, 1, 1, 0, 1, 0, 1]
and change myBools to:
myBools = [0, 0, 0, 0, 1, 0, 0, 1, 0, 1]
I've tried:
myBools = [myBools[i] for i in myIdx == 0]
But this does not give me the desired output.
I hope this works (not sure what you need):
myIdxs = [0, 3, 5]
myBools = [1, 1, 1, 1, 1, 0]
myBools = [myBools[i] if i in myIdxs else 0
for i in xrange(len(myBools))]
>>> print myBools
[1, 0, 0, 1, 0, 0]
Poorly worded question, but here are two answers, both are extremely simple and straightforward, and don't required complex list comprehension.
If you want to change the bit to the opposite value
myIdxs = [0, 3, 5]
myBools = [1, 0, 0, 1, 1, 1, 0, 1, 0, 1]
for i in myIdxs:
myBools[i] ^= 1 # Bitwise operator flips the bit
print(myBools)
If you want to change the bit to zero.
myIdxs = [0, 3, 5]
myBools = [1, 0, 0, 1, 1, 1, 0, 1, 0, 1]
for i in myIdxs:
myBools[i] = 0 # Sets bit to zero
print(myBools)
Output
The output is actually the same for both, given the input, but don't let that fool you they do two very different things.
[0, 0, 0, 0, 1, 0, 0, 1, 0, 1]
[0, 0, 0, 0, 1, 0, 0, 1, 0, 1]
Try using list comprehension with if-else statement.
[myBools[i] if i in myIdxs else 0 for i in range(len(myBools))]
Output
[1, 0, 0, 1, 0, 0]

In python how can I set multiple values of a list to zero simultaneously?

Conceptually, I want to do:
arr[20:] = 0
where arr is a list.
How can I do this?
You can do it directly using slice assignment.
arr[20:] = [0] * (len(arr) - 20)
But the natural way is just to iterate.
for i in xrange(20, len(arr)):
arr[i] = 0
Here are a couple of options:
List comprehension
>>> a = [1]*50
>>> a = [aa if i < 20 else 0 for i,aa in enumerate(a)]
>>> a
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0]
List slice assignment:
>>> a = [1]*50
>>> a[20:] = [0 for aa in a[20:]]
>>> a
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0]
Zip(*zip):
>>> a = [1]*50
>>> a[20:] = zip(*zip(a[20:],itertools.repeat(0)))[1]
arr.fill(0)
numpy.ndarray.fill() will fill ndarray with scalar value
You can make a function that you will pass the array to that will zero out the array. I haven't used Python in a while, so I won't attempt to show you the Python code. In that function you could use a for or while loop to iterate through each value and setting each one equal to zero.
If you use list comprehension you make a copy of the list, so there is memory waste.
Use list comprehension or slicing to make new lists, use for cicles to set your list items correctly.

Categories

Resources