5

I have this function:

if elem < 0:
    elem = 0
else:
    elem = 1

I want to apply this function to every element in a NumPy array, which would be done with a for loop when performing this function for only the same dimensions. But in this case, I need it to work regardless of the array dimensions and shape. Would there be any way this can be achieved in Python with NumPy?

Or would there be any general way to apply any def to every element in a NumPy n-dimensional array?

charmander
  • 87
  • 1
  • 6
  • Also: [Replacing Numpy elements if condition is met](https://stackoverflow.com/q/19766757/7851470) – Georgy May 06 '20 at 13:58
  • Also: [Convert NumPy array to 0 or 1 based on threshold](https://stackoverflow.com/q/46214291/7851470) – Georgy May 06 '20 at 13:59

6 Answers6

8

Isn't it

arr = (arr >= 0).astype(int)
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
5

np.where

np.where(arr < 0, 0, 1)
Community
  • 1
  • 1
ansev
  • 30,322
  • 5
  • 17
  • 31
5

You can use a boolean mask to define an array of decisions. Let's work through a concrete example. You have an array of positive and negative numbers and you want to take the square root only at non-negative locations:

arr = np.random.normal(size=100)

You compute a mask like

mask = arr >= 0

The most straightforward way to apply the mask is to create an output array, and fill in the required elements:

result = np.empty(arr.shape)
result[mask] = np.sqrt(arr[mask])
result[~mask] = arr[~mask]

This is not super efficient because you have to compute the inverse of the mask and apply it multiple times. For this specific example, your can take advantage of the fact that np.sqrt is a ufunc and use its where keyword:

result = arr.copy()
np.sqrt(arr, where=mask, out=result)

One popular way to apply the mask would be to use np.where but I specifically constructed this example to show the caveats. The simplistic approach would be to compute

result = np.where(mask, np.sqrt(arr), arr)

where chooses the value from either np.sqrt(arr) or arr depending on whether mask is truthy or not. This is a very good method in many cases, but you have to have the values pre-computed for both branches, which is exactly what to want to avoid with a square root.

TL;DR

Your specific example is looking for a representation of the mask itself. If you don't care about the type:

result = arr >= 0

If you do care about the type:

result = (arr >= 0).astype(int)

OR

result = -np.clip(arr, -1, 0)

These solutions create a different array from the input. If you want to replace values in the same buffer,

mask = arr >= 0
arr[mask] = 1
arr[~mask] = 0
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
2

You can do something like this:

import numpy as np

a=np.array([-2,-1,0,1,2])

a[a>=0]=1
a[a<0]=0

>>> a
array([0, 0, 1, 1, 1])
dawg
  • 98,345
  • 23
  • 131
  • 206
0

An alternative to the above solutions could be combining list comprenhension with ternary operators.

my_array = np.array([-1.2, 3.0, -10.11, 5.2])
sol = np.asarray([0 if val < 0 else 1 for val in my_array])

take a look to these sources https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions https://book.pythontips.com/en/latest/ternary_operators.html

-2

Use numpy.vectorize():

import numpy as np

def unit(elem):
    if elem < 0:
        elem = 0
    else:
        elem = 1
a = np.array([[1, 2, -0.5], [0.5, 2, 3]])
vfunc = np.vectorize(unit)
vfunc(a)

# array([[1, 1, 0], [1, 1, 1]])
bantix
  • 58
  • 8