1

I want to drop limit decimal places to specific position (not round). For example 1.555 to 1.55 not 1.56. Isn't there a better/built-in way with either pandas or numpy? This is the only way I can think of.

import numpy as np

a = np.array([1.555, 2.559])

precision = 2
adj = 10 ** precision
np.floor(a * adj) / adj

array([ 1.55,  2.55])
E.K.
  • 4,179
  • 8
  • 30
  • 50
  • This might help a bit : the term you are looking for is `truncation` – jadsq May 25 '17 at 18:36
  • 1
    https://stackoverflow.com/questions/783897/truncating-floats-in-python – nge May 25 '17 at 18:40
  • Yeah saw this link, but it was 8 years ago. So I thought there might be a better way now. I could also do `float('%.2f'%(1.555))` but does not seem to be the smartest thing. – E.K. May 25 '17 at 18:43
  • It doesn't matter how old a question is. If it's the same as your question, then your question is a duplicate. However, your question isn't *quite* the same, because you are asking if there is a nicer way *in `pandas` or `numpy`*. – John Y May 25 '17 at 19:45
  • Yeah a lot of new features have been added to 'pandas' and ''numpy' since then. So I thought there might be a nice way now. – E.K. May 25 '17 at 19:47
  • You are not getting my point. The **only** thing that is saving your question from being considered a duplicate (and thus closed) is that you are **specifically** asking about `pandas` or `numpy`. The question linked by nge only applies to Python itself. If there is already a question about truncation in `pandas` or `numpy` (and maybe there is), then it **doesn't matter how old the question is** - your question would still be a duplicate and thus should be closed. – John Y May 25 '17 at 19:50

3 Answers3

3

With an array you don't want to use string formatting methods.

In [175]: a = np.array([1.555, 2.559])
In [176]: a*100
Out[176]: array([ 155.5,  255.9])
In [177]: (a*100).astype(int)
Out[177]: array([155, 255])
In [178]: (a*100).astype(int)/100
Out[178]: array([ 1.55,  2.55])

Because floats are not exact, you might get a few 'wrong' results, ones where a truncated value will be off by a digit.


A small 'guard' value might be enough (if some values are negative this would have to be an array with corresponding positive negative values):

In [179]: (a*100+.01).astype(int)/100
Out[179]: array([ 1.55,  2.55])

A somewhat artificial test case for a guard value:

In [65]: a = np.array([1.555, 2.559, 1.25-1e-10])
In [66]: a
Out[66]: array([ 1.555,  2.559,  1.25 ])
In [67]: (a*100).astype(int)/100
Out[67]: array([ 1.55,  2.55,  1.24])
In [68]: (a*100+.01).astype(int)/100
Out[68]: array([ 1.55,  2.55,  1.25])
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • hpaulj... you'd be a good person to ask. Since you mentioned floats not being exact, and we ditch our expectations that it should be, can't we then do some bit shifting back and forth to get this done? – piRSquared May 25 '17 at 19:41
  • I fully appreciate that we have to be careful with floats. They are very tricky beasts. But have you actually encountered off-by-one results when not using a guard value? Can you construct a case where you need a guard value? And if you can, then how do you know that the guard value won't *create* off-by-one results on the other side? Floats are not "exact" in a base-10 sense, that's true. But we're also multiplying and dividing by powers of 10. As long as we're not near the edge of precision (say, asking for 7 decimal digits of float32 values), shouldn't the "promoted" digits be OK? – John Y May 25 '17 at 20:57
  • In this context I'm just guessing that this could be an issue; I can't off hand construct an example. – hpaulj May 25 '17 at 21:39
  • Then I don't think it's a good idea to add a guard value. Just randomly adding an arbitrary value without fully understanding why has just as much chance to push the result to the next-higher digit when you *don't* want it to, as it does to push the result to the next-higher digit when you do want it to. – John Y May 26 '17 at 16:39
  • I added an example. – hpaulj May 26 '17 at 17:22
  • Interesting. The string representation of a numpy array is **already rounded** to a certain extent! (It's a surprise to me because I'm not really a numpy user.) When it shows `1.25` as the last element, that's actually not the value stored in `a[-1]`. You can confirm this by printing just `a[-1]`, which gives `1.2499999999`. But whatever. Let's say we have `np.array([1.555, 2.559, 1.2499])`. When I **truncate**, I want `1.24` at the end. But your method gives `array([ 1.55, 2.55, 1.25])`, which is **rounded**, not truncated. The "guard value" has *introduced* off-by-one error. – John Y May 26 '17 at 19:56
1

Split number. Get decimal part using n-int(n) and convert it to string, truncate, back to float. Add to int part.

n = 553.98896
int(n)+float(str(n-int(n))[1:4])

returns

553.98

Vaishali
  • 37,545
  • 5
  • 58
  • 86
0

You could do it the dirty way:

val = 12.5555

sVal = str(val)

i = sVal.index('.')

val = float(sVal[0:i] + sVal[i:i+3])

print(val)

Live demo

Olian04
  • 6,480
  • 2
  • 27
  • 54