Search code examples
pythonrangefloatingbinning

Putting floating point ranges into bins


Given 5 ranges

[(0., 0.), (0., 0.3), (0.3, 0.5), (0.5, 0.8), (0.8, 1.0)]

that corresponds to:

  • [0.0, 0.0]
  • (0.0, 0.3]
  • (0.3, 0.5]
  • (0.5, 0.8]
  • (0.8, 1.0]

And a list of input floats:

[0.5293113408538,
 0.3105914215541,
 0.7748290363338001,
 0.7745464933980998,
 0.17276995816109997,
 0.83335888200110002,
 0.0]

The goal is to bin the floats into the ranges above and output:

[3, 2, 3, 3, 1, 4, 0]

I have tried this:

score_ranges =  [(0., 0.), (0., 0.3), (0.3, 0.5), (0.5, 0.8), (0.8, 1.0)]

x = [0.5293113408538,
 0.3105914215541,
 0.7748290363338001,
 0.7745464933980998,
 0.17276995816109997,
 0.83335888200110002,
 0.0]

binning = []

for i in x:
    for j, (start, end) in enumerate(score_ranges):
        if i == 0:
            binning.append(0)
            break
        elif start < i <= end:
            binning.append(j)
            break

But is there a less verbose way to get the desired bining outputs?

Additionally, the zero range is sort of hard coded there because its lower bound is inclusive unlike the other classes, is there a better way to handle that?


Solution

  • You can use bisect module, but you'll have to change your code a little. Shrink you list of tuples to the list of floats.

    import bisect
    
    score_ranges =  [0., 0.3, 0.5, 0.8, 1.0]
    binning = []
    
    x = [
        0.5293113408538,
        0.3105914215541,
        0.7748290363338001,
        0.7745464933980998,
        0.17276995816109997,
        0.83335888200110002,
        0.0]
    
    for a in x:
        binning.append(bisect.bisect_left(score_ranges, a))