繁体   English   中英

如何从数组中获取表示最多的对象

[英]How to get the most represented object from an array

我有一个包含一些对象的数组,并且有几个相似的对象。 例如:水果= [苹果,橙子,苹果,香蕉,香蕉,橙子,苹果,苹果]

从这个数组中获取代表性最高的对象的最有效方法是什么? 在这种情况下,它将是“苹果”,但你会如何以有效的方式出去计算?

不要重新发明轮子。 在Python 2.7+中,您可以使用Counter类

import collections
fruit=['apple', 'orange', 'apple', 'banana', 'banana', 'orange', 'apple', 'apple']
c=collections.Counter(fruit)
print(c.most_common(1))
# [('apple', 4)]

如果您使用的是旧版本的Python,则可以在此处下载Counter

虽然知道如何自己实现这样的事情是很好的,但是习惯使用Counter也是一个好主意,因为它是(或将成为)标准库的一部分。

如果对象是可清洗的,那么您可以使用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))

保留每个对象出现频率的字典。

构建此表,遍历列表一次。 随着时间的推移,跟踪到目前为止最常出现的对象。

此代码未经测试。

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)

你想要一个有效的方法。 显然,它可能在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})

你希望在这里实现的最佳时间是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)
    }
}
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将包含计数,然后您可以评估每个对象的受欢迎程度。

这是一种不同的方法,它基本上对列表进行排序,然后按排序顺序处理它。

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

这不是O(n),而是O(n ^ 2),因此它不适合您的账单作为“最有效的方式”,但它是紧凑的并且避免for循环,这在Python中相当慢。 它将比O(n)选项快11个独特的项目。

def most_common(items):
    s = set(items)
    return max([(items.count(i), i) for i in s])[1]

正如~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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM