0

I have a Python list like so:

import numpy

thresholds = numpy.linspace(0.7, 0.9, 21)

print(thresholds)

[0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9]

When I try to create a dict from this list by doing dict.fromkeys(), the result isn't as expected:

thresholds = dict.fromkeys(numpy.linspace(0.7, 0.9, 21))

print(thresholds)

{0.69999999999999996: None, 0.70999999999999996: None, 0.84999999999999998: None, 0.83000000000000007: None, 0.81000000000000005: None, 0.79000000000000004: None, 0.77000000000000002: None, 0.78000000000000003: None, 0.72999999999999998: None, 0.83999999999999997: None, 0.71999999999999997: None, 0.89000000000000001: None, 0.87: None, 0.80000000000000004: None, 0.76000000000000001: None, 0.90000000000000002: None, 0.73999999999999999: None, 0.88: None, 0.85999999999999999: None, 0.82000000000000006: None, 0.75: None}

I was expecting a dict like this:

{0.7: None, 0.71: None, 0.85: None, 0.83: None, 0.81: None, 0.79: None, 0.77: None, 0.78: None, 0.73: None, 0.84: None, 0.72: None, 0.90: None, 0.87: None, 0.80: None, 0.76: None, 0.90: None, 0.74: None, 0.88: None, 0.86: None, 0.82: None, 0.75: None}

Why do I not get rounded values in the final dict and how do I go about correcting this?

lostsoul29
  • 746
  • 2
  • 11
  • 19
  • 3
    What result do you expect? – Sergei Lebedev Jun 05 '16 at 21:18
  • 1
    Note that using floats as dictionary keys isn't a great idea. – jonrsharpe Jun 05 '16 at 21:22
  • I expect the `dict` keys to be exactly equal to the list values, without a large number of decimal digits. – lostsoul29 Jun 05 '16 at 21:23
  • @jonrsharpe Sometimes it's useful to have floats as dictionary keys, but only if you understand the problems. – Sven Marnach Jun 05 '16 at 21:24
  • I'm pretty sure the dict keys **are** equal to the array values. Rounding (in `__str__`) is a feature of NumPy. – Sergei Lebedev Jun 05 '16 at 21:24
  • @jonrsharpe I intend to use the floats as keys, and every key will have a 3-tuple associated with it. – lostsoul29 Jun 05 '16 at 21:25
  • @lostsoul29 to what end? The issue with using float keys is that your sums very rarely end up at precisely the value you hoped. – jonrsharpe Jun 05 '16 at 21:27
  • @jonrsharpe Intriguing! The keys are Jaro-Winkler thresholds, and every threshold has three parameters associated with it - Recall, Precision and F-measure - which I would store as the 3-tuple. Would this be okay to do? – lostsoul29 Jun 05 '16 at 21:29
  • If they're inputs, that is probably OK. If they're results it probably isn't. – jonrsharpe Jun 05 '16 at 21:30
  • I see. In my case the the thresholds are inputs, but the 3-tuple are results (floating point). What would a better idea to store them? – lostsoul29 Jun 05 '16 at 21:33
  • 1
    Related: [Is floating point math broken?](http://stackoverflow.com/q/588004/216074) – poke Jun 05 '16 at 21:33
  • 1
    It's worth noting that `thresholds` is not a list, even though it looks a little like one when you `print` it. It's a `numpy.array`, which does slightly different things in `__str__` and `__repr__` than regular Python containers that hold floats. – Blckknght Jun 05 '16 at 21:46

2 Answers2

2

If you're getting upset about the floating point representations you should try converting the values to decimal types. Otherwise, just let it go.

print('%1.17f' % 0.7)
print('%1.2f' % 0.7)

0.69999999999999996
0.70
Batman
  • 8,571
  • 7
  • 41
  • 80
2

You're better of converting the floats from numpy.linspace into strings. Using floats directly as dictionary keys in python is a terrible idea, for reasons relating to precision (you can't bet on 100% precision) and the way floating point numbers are evaluated.

thresholds = numpy.linspace(0.7, 0.9, 21)

# freezing the precision of your floating point numbers
stringified_thresholds = [str(i) for i in thresholds]

thresholds_dict = dict.fromkeys(stringified_thresholds)

You may continue your work from here.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139