在Python中对落于可变范围内的数字进行舍入
我有一个数字列表:
lst = [3.253, -11.348, 6.576, 2.145, -11.559, 7.733, 5.825]
我想找个办法,把列表里的每个数字替换成一个给定的数字,前提是这个数字在某个范围内。我想根据输入列表的最小值和最大值,以及一个控制范围数量的输入数字,来创建多个范围。举个例子,如果我说我想要3个范围,均匀地分布在最小值和最大值之间。
numRanges = 3
lstMin = min(lst)
lstMax = max(lst)
step = (lstMax - lstMin) / numRanges
range1 = range(lstMin, lstMin + step)
range2 = range(range1 + step)
range3 = range(range2 + step)
那么,能不能让范围的数量由numRanges这个变量来决定呢?之后我想拿这个输入列表,比如说:
for i in lst:
if i in range1:
finalLst.append(1) #1 comes from range1 and will be growing if more ranges
elif i in range2:
finalLst.append(2) #2 comes from range2 and will be growing if more ranges
else i in range3:
finalLst.append(3) #3 comes from range2 and will be growing if more ranges
我现在觉得这一切都是“手动”的,我不太确定怎么让它变得更灵活,这样我只需要指定范围的数量和一个数字列表,代码就能自动处理剩下的事情。提前谢谢你的帮助。
finalLst = [3, 1, 3, 3, 1, 3, 3]
2 个回答
Python有一个非常好用的工具,专门用来处理这种工作,叫做bisect。假设你的范围列表是这样定义的:
ranges = [-15, -10, -5, 5, 10, 15]
对于你的输入列表,你只需要像这样调用bisect:
lst = [3.253, -11.348, 6.576, 2.145, -11.559, 7.733, 5.825]
results = [ranges[bisect(ranges, element)] for element in lst]
这样就会得到:
>>>[5, -10, 10, 5, -10, 10, 10]
你还可以通过在Python 2.7中使用ranges = range(start,stop,step)
,或者在Python 3.X中使用ranges = list(range(start,stop,step))
来扩展到任何任意的范围列表。
更新
重新阅读你的问题,这可能更接近你想要的答案(仍然使用bisect):
from numpy import linspace
from bisect import bisect_left
def find_range(numbers, segments):
mx = max(numbers)
mn = mn(numbers)
ranges = linspace(mn, mx, segments)
return [bisect_left(ranges, element)+1 for element in numbers]
>>> find_range(lst, 3)
[3, 2, 3, 3, 1, 3, 3]
这段代码可以通过基本的数学运算在列表推导式中轻松实现:
numRanges = 3
lstMin = min(lst)
lstMax = max(lst) + 1e-12 # small value added to avoid floating point rounding issues
step = (lstMax - lstMin) / numRanges
range_numbers = [int((x-lstMin) / step) for x in lst]
这段代码会为原始列表中的每个值生成一个整数,其中0
表示这个值属于第一个范围,1
表示第二个范围,依此类推。它和你的代码几乎一样,只是数字是从0
开始的,而不是1
(如果你真的想从1开始,可以在计算中加个+ 1
)。
我在lstMax
中加的小值有两个原因。第一个是为了确保浮点数的舍入问题不会导致列表中的最大值返回numRange
作为它的范围索引,而不是numRange-1
(表示第numRange
个范围)。另一个原因是为了避免在列表中只有一个值(可能重复多次)的情况下出现除以零的错误,这样min(lst)
和max(lst)
会返回相同的结果。