我有一个包含一些对象的数组,并且有几个相似的对象。例如:水果= [苹果,橙子,苹果,香蕉,香蕉,橙子,苹果,苹果]
从这个数组中获取代表性最高的对象的最有效方法是什么?在这种情况下,它将是“苹果”,但你会如何以有效的方式出去计算?
答案 0 :(得分:8)
不要重新发明轮子。在Python 2.7+中,您可以使用the Counter class:
import collections
fruit=['apple', 'orange', 'apple', 'banana', 'banana', 'orange', 'apple', 'apple']
c=collections.Counter(fruit)
print(c.most_common(1))
# [('apple', 4)]
如果您使用的是旧版Python,则可以下载Counter
here。
虽然知道如何自己实现这样的东西很好,但是习惯使用Counter也是一个好主意,因为它是(或将成为)标准库的一部分。
答案 1 :(得分:5)
如果对象是可清除的,那么您可以使用dict来存储计数:
results = {}
for item in somelist:
if item not in results:
results[item] = 1
else
results[item] += 1
print max(results.iteritems(), key=operator.itemgetter(1))
答案 2 :(得分:3)
保留每个对象出现频率的字典。
遍历列表一次,构建此表。当你走的时候,记录到目前为止最常出现的对象。
此代码未经测试。
from collections import defaultdict
def mode(objects):
h = defaultdict(int)
max_f = 0
max_obj = None
for o in objects:
f = h[o] = h[o] + 1
if f > max_f:
max_f = f
max_obj = o
return max_obj
如果对象不可清除,您可以改为哈希它们的一些独特功能,例如id(o)
。
答案 3 :(得分:2)
你想要一种有效的方法。显然,它可能在O(n)时间内,因此任何需要对列表进行排序的方法都是O(n log(n))。不可能比O(n)更快地做到这一点,因为即使你检查了前n / 2-1个元素,并且它们都是“苹果”,你也不知道其余的元素不会是香蕉
因此,鉴于我们正在寻找O(n),您必须遍历列表并记录您所看到的每种类型的项目数。
defaultdict将是一种在实践中实现此目的的简单方法。
>>> from collections import defaultdict
>>> d = defaultdict(int)
>>> for i in ['apple', 'banana', 'apple']:
... d[i] += 1
...
>>> d
defaultdict(<type 'int'>, {'apple': 2, 'banana': 1})
答案 4 :(得分:1)
你希望在这里实现的最佳时间是O(n) - 你总是需要至少走一次整个阵列。 最简单的方式肯定是构建直方图。如果您的字典结构(某种类型的地图)提供O(1)插入和检索,那么这就像(groovy-ish伪代码)一样简单:
def histogram = new HashMap()
def maxObj = null
def maxObjCount = 0
objectList.each {
if(histogram.contains(it)) histogram.put(it, histogram.get(it)+1)
else histogram.put(it, 1)
if(histogram.get(it) > maxObjCount) {
maxObj = it
maxObjCount = histogram.get(it)
}
}
答案 5 :(得分:0)
def count_reps(item, agg):
k = hash(item)
try:
agg[k] += 1
except KeyError:
agg[k] = 1
return agg
item_dict = reduce(your_array, {})
item_dict将包含计数,然后您可以评估每个对象的受欢迎程度。
答案 6 :(得分:0)
这是一种不同的方法,它基本上对列表进行排序,然后按排序顺序处理它。
fruits = ['apple', 'orange', 'apple', 'banana', 'banana', 'orange', 'apple', 'apple']
max_fruit_count = 0
max_fruit = ''
current_fruit_count = 0
current_fruit = ''
for fruit in sorted(fruits) :
if fruit != current_fruit :
if current_fruit != max_fruit :
if current_fruit_count > max_fruit_count :
max_fruit = current_fruit
max_fruit_count = current_fruit_count
current_fruit = fruit
current_fruit_count = 1
else :
current_fruit_count += 1
if current_fruit_count > max_fruit_count :
max_fruit = current_fruit
max_fruit_count = current_fruit_count
print max_fruit, max_fruit_count
答案 7 :(得分:0)
这不是O(n),而是O(n ^ 2),因此它不适合您的账单作为“最有效的方式”,但它是紧凑的并避免for
循环,这是相当慢的蟒蛇。它将比O(n)选项快11个唯一项目。
def most_common(items):
s = set(items)
return max([(items.count(i), i) for i in s])[1]
答案 8 :(得分:0)
as~unutbu说:使用collections.Counter 如果不这样做,请为你的代码计时。这是我(可能效率低下)的方法:
python -m timeit -s "fruit = ['apple']*4 + ['banana'] + ['orange']*2" \
"kL = set(fruit); L = [fruit.count(f) for f in kL]; D = dict(zip(kL,L)); \
sorted(D,key = lambda k: D[k],reverse=True)"
100000 loops, best of 3: 10.1 usec per loop