numpy.where with more than one condition

Viewed 119

I am here because I have a question with the function numpy.where. I need to develop a program that rounds the grades of a student in the danish grading scale.

(Danish grading scale is a 7-step-scale from the best one (12) to the worst one (-3) : 12 10 7 4 02 00 −3)

Here is the array of the grades :

grades=np.array([[-3,-2,-1,0],[1,2,3,4],[5,6,7,8],[9,10,11,12]])

and what I am trying to do is this :

gradesrounded=np.where(grades<-1.5, -3, grades)
gradesrounded=np.where(-1.5<=grades and grades<1, 0, grades)
gradesrounded=np.where(grades>=1 and grades<3, 2, grades)
gradesrounded=np.where(grades>=3 and grades<5.5, 4, grades)
gradesrounded=np.where(grades>=5.5 and grades<8.5, 7, grades)
gradesrounded=np.where(grades>=8.5 and grades<11, 10, grades)
gradesrounded=np.where(grades>=11, 12, grades)
print(gradesrounded)

and what I found out is that np.where works when there is one condition (so grades below -1.5 works and grades over 11 works for example) but if there are 2 different conditions (for example this one : np.where(grades>=1 and grades<3, 2, grades)) it won't work.

Do you know how I could fix this ?

Thank you very much.

4 Answers

You are using the logical operator and which doesn't work for array operations. Use bitwise operators instead that will operate element by element.

np.where((grades>=1) & (grades<3), 2, grades))

Have a look at this: link

Another way is np.searchsorted:

scales = np.array([-3,0,2,4,7,10,12])

grades=np.array([[-3,-2,-1,0],[1,2,3,4],[5,6,7,8],[9,10,11,12]])

thresh = [-1.5, 0.5 ,2.5,5.5,8.5,10]
out = scales[np.searchsorted(thresh, grades)]

# or
# thresh = [-3, -1.5, 1, 3, 5.5, 8.5, 11]
# out = scales[np.searchsorted(thresh, grades, side='right')-1]

Out:

array([[-3, -3,  0,  0],
       [ 2,  2,  4,  4],
       [ 4,  7,  7,  7],
       [10, 10, 12, 12]])

This is an excellent case for the np.select() function. The docs can be found here.

The setup is simple:

  • Create a list of Danish system grades.
  • Create a list of mappings. The case below uses the logical and & operator to link multiple conditions.

Setup:

import numpy as np

# Sample grades.
x = np.array([-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

# Define limits and lookup.
grades = [12, 10, 7, 4, 2, 0, -3]
scale = [(x >= 11), 
         (x >= 8.5) & (x < 11),
         (x >= 5.5) & (x < 8.5),
         (x >= 3.0) & (x < 5.5),
         (x >= 1.0) & (x < 3.0),
         (x >= -1.5) & (x < 1.0 ),
         (x < -1.5)]

Use:
Call the np.select function and pass in the two lists created above.

# Map grades to Danish system.
np.select(condlist=scale, choicelist=grades)

Output:

array([-3, -3,  0,  0,  2,  2,  4,  4,  4,  7,  7,  7, 10, 10, 12, 12])

If you want to put it as a string you could also use a pandas dataframe and the query function on it. Here is an example:

df = df.query('grades>=1 & grades<3')
Related