[英]Python approximate group-by
我想按其值對字典鍵進行分組。 但是,這些值僅近似相等。 在這種情況下進行分組的最好方法是什么。 我有:
buckets = defaultdict(list)
for k, v in my_dict.iteritems():
closest = next((rep for rep in buckets if abs(rep - v) < 1e-3), None)
if closest:
buckets[closest].append(k)
else:
buckets[v].append(k)
任何itertools魔術或其他可以簡化此操作/使其更具有pythonic的功能,或者這是我能做的最好的事情嗎?
您的算法為O(n**2)
因為它在O(n)
循環內執行O(n)
運算:
for k, v in my_dict.iteritems():
closest = next((rep for rep in buckets if abs(rep - v) < 1e-3), None)
通過按值對my_dict.items()
進行排序,然后循環遍歷已排序的項,可以將其設置為O(n log n)
。 請注意,如果buckets
是OrderedDict ,則無需for rep in buckets
中for rep in buckets
,只需查看最后一個存儲桶,因為OrderedDict
的鍵將按排序順序。 因此,如果下一個值接近任何存儲桶,則它必須接近最后一個存儲桶。 因此,通過使用OrderedDict
,您不需要遍歷所有存儲桶。 只需與最后一個比較即可:
import random
random.seed(123)
N = 10
my_dict = dict(zip(range(N), [random.randint(0, 10)/10.0 for k in range(N)]))
print(my_dict)
# {0: 0.0, 1: 0.0, 2: 0.4, 3: 0.1, 4: 0.9, 5: 0.0, 6: 0.5, 7: 0.3, 8: 0.9, 9: 0.1}
import operator
import collections
items = sorted(my_dict.items(), key=operator.itemgetter(1))
buckets = collections.OrderedDict([(items[0][1], [items[0][0]])])
for k, v in items[1:]:
last_val = next(reversed(buckets))
closest = last_val if abs(last_val - v) < 1e-3 else v
buckets.setdefault(closest, []).append(k)
print(buckets)
版畫
OrderedDict([(0.0, [0, 1, 5]), (0.1, [3, 9]), (0.3, [7]), (0.4, [2]), (0.5, [6]), (0.9, [4, 8])])
這會稍微有點“ pythonic”:
buckets = defaultdict(list)
for k, v in my_dict.iteritems():
try:
closest = next((rep for rep in buckets if abs(rep - v) < 1e-3))
buckets[closest].append(k)
except StopIteration:
buckets[v].append(k)
除了您的代碼效率低下外,由於.itetitems()
順序可能是任意的,因此也不保證每次都相同或任何特定的結果。 要解決這兩個問題,您只需使用鍵功能:
key = lambda x: round(x, 3)
然后,您按照通常的方式進行分組,但是使用key(v)
作為索引:
buckets = defaultdict(list)
for k, v in my_dict.iteritems():
buckets[key(v)].append(k)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.