Rounding down to increments Python [duplicate] - python

This question already has answers here:
Python - Rounding by quarter-intervals
(4 answers)
Closed 1 year ago.
I am trying to write a code that rounds down the start list values to the nearest .25 value. How would I be able to do that? So the first index in the start list is 3.645 and that would be rounded to 3.5 since .0, . 25, 0.5, 0.75 are the only increments for 0.25. Since the last index already is a multiple of 0.25 2 stays as 2.
start = [3.645, 33.54656, 1.77, 1.99, 2]
Expected output:
[3.5, 33.5, 1.75, 1.75, 2]

This being Python, there's probably some fancy package that will let you do this, but [int(4*x)/4 for x in start] is one way to do it. You can also do [x - x % .25 for x in start] (the modulus operator does work for non-integer modulus).
However, I notice you had your last number be just 2, rather than 2.0. If you want integers to not be cast as floats, you'll have to do something more complicated, such as [int(x) if int(x) == x else int(4*x)/4 for x in start]. And if you want numbers to be cast as int if they're integers after the rounding, it will have to be even more complicated, such as [x - x%.25 if x%1 > .25 else int(x) for x in start]

Related

numpy arange step iteration error logging for dtype=int vs float

I am new to numpy and have a look at the documentation https://numpy.org/devdocs/reference/generated/numpy.arange.html but cant seem to get an error log or an indication that it is exceeding the stop of int '3'. float seems to work as expected, but not int. i believe its due to how python interpret int and float, but should int not auto round the 0.5 values?
Comparing a float and an int in Python
https://numpy.org/doc/stable/user/basics.types.html
my question is, why and how does arange interpret the int as the stop point is '6' and not '3', if int is used, should it not stop at 2?
Many thanks for enlightenment.
x = np.arange(-1, 3, 0.5, dtype=int)
y = np.arange(-1, 3, 0.5, dtype=float)
print('x = ', x)
print('y = ', y)
x = [-1 0 1 2 3 4 5 6]
y = [-1. -0.5 0. 0.5 1. 1.5 2. 2.5]
According to the docs, which you must have read, since your example is close to the one given there
Another stability issue is due to the internal implementation of
`numpy.arange`.
The actual step value used to populate the array is
``dtype(start + step) - dtype(start)`` and not `step`. Precision loss
can occur here, due to casting or due to using floating points when
`start` is much larger than `step`. This can lead to unexpected
behaviour.
That dtype(start + step) - dtype(start):
In [25]: int(-1 + .5) - int(-1)
Out[25]: 1
Looks like it initially calculates the number of values to return, using the same math as with the float case - hence x and y have the same length.
ceil((stop - start)/step)
In [29]: np.ceil((3-(-1))/.5)
Out[29]: 8.0
My guess is that it 'iterates' for [29] values with the [25] step. It's not a 'iterate until it reaches/passes the stop' logic.
Answer to my question is as what hpaulj mentioned, in correct use of arange could lead to unexpected behavior. decimal point for int is bad practise and therefore resulted in the behavior.

Modulo 10 for large Numbers | Checking if a number is in powers of 10 [duplicate]

This question already has answers here:
Mod function fails in python for large numbers
(2 answers)
Closed 4 years ago.
I want to check in Python if a (large integer) value is in powers of 10. Normally I would simply check the modulo 10 of the value. This works fine for values of up to 1.E+22, after that, it returns weird values:
lowInteger = 1.E12
highInteger = 1.E23
print(lowInteger % 10) #as expected returns 0
>>> 0.0
print(highInteger % 10) #returns 2.0 instead of 0.0, 1.E23 returns 3.0, etc
>>> 2.0
The floating point number 1.E23 is not a power of 10. It is the nearest representable number to the power of 10 you wanted. Its actual value is
>>> int(1e23)
99999999999999991611392
If you want exact integers, use ints, not floats. You want 10**23.
>>> 10**23
100000000000000000000000
Also, if you want to check whether a number is a power of 10, x % 10 == 0 is the wrong check anyway, because that's checking whether the number is a multiple of 10.

Generating duplicates with weights (python) [duplicate]

This question already has answers here:
A weighted version of random.choice
(28 answers)
Closed 4 years ago.
I have the following list:
priority=['Emergency','High','Normal','Low']
I need to generate a list of 15000 values in the list above, with frequency of each of them being 10%,20%,30%,40%. Can somebody show me how to do it?
Probably the easiest way is to use choice function of numpy.random.
import numpy as np
priority=['Emergency','High','Normal','Low']
b = np.random.choice(priority, 150, replace=True, p=[0.1, 0.2, 0.3, 0.4])
print(b)
Built-in random.choices does the same thing but it is not available <3.6.
You can use random.random(), and assign indexes based on the range of the random number.
In [21]: priority=['Emergency','High','Normal','Low']
In [22]: idx = lambda x: 0 if x < 0.1 else (1 if x < 0.3 else (2 if x < 0.6 else 3))
In [23]: import random
In [24]: [priority[idx(random.random())] for _ in range(15000)]
Out[24]:
['Normal',
'High',
'Emergency',
'Emergency',
'High',
.
.
In the above, I've relied on the order of the elements within your list to generate indexes, such that for 0 to 0.1 it is the first (10%), 0.1 to 0.3 its the second (0.3 - 0.1 will cover 20%), and so on.

how to divide each element in a list of lists by a number in python

I have a list of list 'q' and i want to divide each number in q by the sum in each list (=10)
I tried this:
q = [[0,0,0,10],[1,2,6,1]]
B=[]
for x in q:
y = [z/sum(x[:len(x)]) for z in x]
B.append(y)
print B
It does not give me the expected result
anyone knows whats wrong here?
$ python
>>> q = [[0,0,0,10],[1,2,6,1]]
>>> B = [[float(j)/sum(i) for j in i] for i in q]
>>> B
[[0.0, 0.0, 0.0, 1.0], [0.1, 0.2, 0.6, 0.1]]
Note: in python3, float() is not required.
B = []
for x in q:
theSum = sum(x)
y = [float(xi) / theSum for xi in x]
B.append(y)
print B
You're performing integer division, since both operands are integers.
y = [float(z)/sum(x) for z in x]
As others have noted, your program will use integer division, which seems not to be what you're looking for. Instead of converting one of the values explicitly to a float, however, I'll suggest that the right solution is to add from ___future__ import division to the top of your script (and, indeed, every script you write for Python versions before Python 3). This switches division to returning float values, which eliminates a lot of subtle math bugs. For those occasions where you do need integer division, you can use a double-slash //.
You are using integer division, which will round the result to the next integer towards zero. Convert one of the operands to float to get floating point division. To do convert the array in place, you can do
for row in q:
s = float(sum(row))
row[:] = [x / s for x in row]

Range with step of type float [duplicate]

This question already has answers here:
How do I use a decimal step value for range()?
(34 answers)
Closed 6 years ago.
The documentation basically says that range must behave exactly as this implementation (for positive step):
def range(start, stop, step):
x = start
while True:
if x >= stop: return
yield x
x += step
It also says that its arguments must be integers. Why is that? Isn't that definition also perfectly valid if step is a float?
In my case, I am esp. needing a range function which accepts a float type as its step argument. Is there any in Python or do I need to implement my own?
More specific: How would I translate this C code directly to Python in a nice way (i.e. not just doing it via a while-loop manually):
for(float x = 0; x < 10; x += 0.5f) { /* ... */ }
You could use numpy.arange.
EDIT: The docs prefer numpy.linspace. Thanks #Droogans for noticing =)
One explanation might be floating point rounding issues. For example, if you could call
range(0, 0.4, 0.1)
you might expect an output of
[0, 0.1, 0.2, 0.3]
but you in fact get something like
[0, 0.1, 0.2000000001, 0.3000000001]
due to rounding issues. And since range is often used to generate indices of some sort, it's integers only.
Still, if you want a range generator for floats, you can just roll your own.
def xfrange(start, stop, step):
i = 0
while start + i * step < stop:
yield start + i * step
i += 1
In order to be able to use decimal numbers in a range expression a cool way for doing it is the following:
[x * 0.1 for x in range(0, 10)]
The problem with floating point is that you may not get the same number of items as you expected, due to inaccuracy. This can be a real problem if you are playing with polynomials where the exact number of items is quite important.
What you really want is an arithmetic progression; the following code will work quite happily for int, float and complex ... and strings, and lists ...
def arithmetic_progression(start, step, length):
for i in xrange(length):
yield start + i * step
Note that this code stands a better chance of your last value being within a bull's roar of the expected value than any alternative which maintains a running total.
>>> 10000 * 0.0001, sum(0.0001 for i in xrange(10000))
(1.0, 0.9999999999999062)
>>> 10000 * (1/3.), sum(1/3. for i in xrange(10000))
(3333.333333333333, 3333.3333333337314)
Correction: here's a competetive running-total gadget:
def kahan_range(start, stop, step):
assert step > 0.0
total = start
compo = 0.0
while total < stop:
yield total
y = step - compo
temp = total + y
compo = (temp - total) - y
total = temp
>>> list(kahan_range(0, 1, 0.0001))[-1]
0.9999
>>> list(kahan_range(0, 3333.3334, 1/3.))[-1]
3333.333333333333
>>>
When you add floating point numbers together, there's often a little bit of error. Would a range(0.0, 2.2, 1.1) return [0.0, 1.1] or [0.0, 1.1, 2.199999999]? There's no way to be certain without rigorous analysis.
The code you posted is an OK work-around if you really need this. Just be aware of the possible shortcomings.
Here is a special case that might be good enough:
[ (1.0/divStep)*x for x in range(start*divStep, stop*divStep)]
In your case this would be:
#for(float x = 0; x < 10; x += 0.5f) { /* ... */ } ==>
start = 0
stop = 10
divstep = 1/.5 = 2 #This needs to be int, thats why I said 'special case'
and so:
>>> [ .5*x for x in range(0*2, 10*2)]
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]
This is what I would use:
numbers = [float(x)/10 for x in range(10)]
rather than:
numbers = [x*0.1 for x in range(10)]
that would return :
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]
hope it helps.
Probably because you can't have part of an iterable. Also, floats are imprecise.

Categories

Resources