Python:在浮动列表中查找最小项目的索引[重复]
Posted
技术标签:
【中文标题】Python:在浮动列表中查找最小项目的索引[重复]【英文标题】:Python: Find index of minimum item in list of floats [duplicate] 【发布时间】:2012-10-29 08:28:34 【问题描述】:如何在 Python 浮点数列表中找到最小项的索引?如果它们是整数,我会这样做:
minIndex = myList.index(min(myList))
但是,对于浮点数列表,我会收到以下错误,我认为是因为浮点数相等比较相当不确定。
ValueError: 0.13417985135 is not in list
现在,我知道我可以简单地滚动列表并比较每个项目,看看它是否是 (min - 0.0000000000001),但这有点混乱。有没有更优雅(最好是内置)的方法来查找浮动列表中最小项的索引?
【问题讨论】:
这应该适用于整数和浮点数......你能告诉我们一个浮点数不起作用的具体例子吗? 浮点数的位数是有限的,所以比较不会有问题。 浮点比较不是不确定的。比较两个浮点数是否相等当且仅当数字相等时才返回真,在任何没有严重破坏的浮点实现中。一个潜在的问题是列表中的 NaN。在这种情况下,最小值运算符可以返回 NaN,但相等比较会报告 NaN 不等于任何值(包括它自己),这可能会导致例程返回最小值索引的问题。如果列表中没有 NaN,则表明还有一些其他问题尚未在任何答案中解决。 这个问题被标记为重复,但这比 imo 顶部横幅上链接的问题 ymmv 有更好的答案。 【参考方案1】:我会使用:
val, idx = min((val, idx) for (idx, val) in enumerate(my_list))
那么val
将是最小值,idx
将是它的索引。
【讨论】:
+1。这比首先得到最小值然后找到它更有效,更简单(一旦你理解了生成器表达式)。另外,它自动适用于可以用<
排序但不能与==
比较的值(我不认为实际上是OP的问题,但他似乎是这样认为的)。
@abarnert -- 谨慎地对效率做出宏大的声明。这是一个大小相关的问题。考虑一下:python -m timeit -s 'my_list = range(1000)[::-1]' 'my_list.index(min(my_list))'
——每个循环 96.8 微秒(并精心设计为最坏的情况)。 python -m timeit -s 'my_list = range(1000)' 'min((val, idx) for (idx, val) in enumerate(my_list))'
-- 每个循环 345 微秒 -- 对于大小为 1000 的列表,速度要慢 3.5 倍。但它确实有其他优点 -- 例如,它适用于任何可迭代对象。
@mgilson:当我运行完全相同的测试时,我得到 333us 与 187us,或者快 2 倍而不是慢 3.5 倍……(Python 3.3 与 2.7?64 位与 32 位?谁知道?)同时,index
解决方案也适用于任何可迭代对象;您只需输入list(myiter)
。在某些情况下,空间损失可能是不可接受的,但时间损失可能不会(因为您已经在列表中进行 N 次遍历)。
@abarnert -- 我在 OS-X 10.5.8(因此是 32 位)上使用 py27。在 python3 上,range
没有给出列表……也许这可能是个问题? (虽然它对我来说运行得更快:) -- 83.4 usec
@fractal_7 你可以用itertools.groupby
做一些技巧:_, minimums = next(groupby(sorted((val, idx) for (idx, val) in enumerate(my_list)), key=lambda x: x[0]), [])
。但这并不那么漂亮,所以那时我可能会编写一个函数来以更好的方式做到这一点。【参考方案2】:
您实际上是在扫描列表一次以找到最小值,然后再次扫描它以找到索引,您可以一次性完成:
from operator import itemgetter
min(enumerate(a), key=itemgetter(1))[0]
【讨论】:
啊,整洁。我没有意识到min
(大概是max
)接受key
参数。 +1!
@DavidWolever Yup min
和 max
(如 sort
和 sorted
)带一个键比较功能 - 非常有用 - 只是希望 set
以它为例
对于大小为 1000 的列表,仍然不如 OP 的代码快:)
这将如何处理重复的最小值?
@Borealis 为什么?它模拟 list.index
的行为(这是 OP 正在尝试做的),它找到 first 最小值的索引...你能描述一下你认为这个答案需要考虑的内容吗帐号?【参考方案3】:
对 numpy 数组使用 argmin 方法。
import numpy as np
np.argmin(myList)
但是,这不是最快的方法:它比 OP 在我的计算机上的答案慢 3 倍。不过这可能是最简洁的一个。
【讨论】:
【参考方案4】:我认为值得在这里放一些时间以获得一些观点。
在 OS-X 10.5.8 上使用 python2.7 完成所有计时
约翰克莱门特的回答:
python -m timeit -s 'my_list = range(1000)[::-1]; from operator import itemgetter' 'min(enumerate(my_list),key=itemgetter(1))'
1000 loops, best of 3: 239 usec per loop
大卫·沃尔弗的回答:
python -m timeit -s 'my_list = range(1000)[::-1]' 'min((val, idx) for (idx, val) in enumerate(my_list))
1000 loops, best of 3: 345 usec per loop
OP 的回答:
python -m timeit -s 'my_list = range(1000)[::-1]' 'my_list.index(min(my_list))'
10000 loops, best of 3: 96.8 usec per loop
请注意,我故意将最小的项目放在列表的最后,以使.index
尽可能慢。看看迭代一次的答案会与我们这里的迭代两次答案竞争在多少 N 时会很有趣。
当然,速度并不是一切,而且大多数时候,甚至都不值得担心...选择最容易阅读的那个,除非这是代码中的性能瓶颈(然后在您的典型真实世界数据上进行概要分析——最好在您的目标机器上)。
【讨论】:
+1 表示最后一段。特别是因为OP专门要求最优雅的方式,而不是最快的方式。还值得一提的是,如果 OP 关于float
s 不是自平等的(即使我不认为这是一个实际问题......)是正确的,那么前两个解决方案仍然有效。以上是关于Python:在浮动列表中查找最小项目的索引[重复]的主要内容,如果未能解决你的问题,请参考以下文章
查找列表的“最佳”项并在python中打印第一个实例的索引位置[重复]