给出语料库/文本:
Resumption of the session
I declare resumed the session of the European Parliament adjourned on Friday 17 December 1999 , and I would like once again to wish you a happy new year in the hope that you enjoyed a pleasant festive period .
Although , as you will have seen , the dreaded ' millennium bug ' failed to materialise , still the people in a number of countries suffered a series of natural disasters that truly were dreadful .
You have requested a debate on this subject in the course of the next few days , during this part @-@ session .
In the meantime , I should like to observe a minute ' s silence , as a number of Members have requested , on behalf of all the victims concerned , particularly those of the terrible storms , in the various countries of the European Union .
我可以简单地这样做来获得一个包含单词频率的词典:
>>> word_freq = Counter()
>>> for line in text.split('\n'):
... for word in line.split():
... word_freq[word]+=1
...
但如果目标是从最高频率到最低频率实现有序字典,我将不得不这样做:
>>> from collections import OrderedDict
>>> sorted_word_freq = OrderedDict()
>>> for word, freq in word_freq.most_common():
... sorted_word_freq[word] = freq
...
想象一下,我在Counter
对象中有10亿个密钥,迭代most_common()
会复杂地经历语料库(非唯一实例)一次和词汇表(唯一键) 。
注意:Counter.most_common()
会调用临时sorted()
,请参阅https://hg.python.org/cpython/file/e38470b49d3c/Lib/collections.py#l472
鉴于此,我看到以下使用numpy.argsort()
的代码:
>>> import numpy as np
>>> words = word_freq.keys()
>>> freqs = word_freq.values()
>>> sorted_word_index = np.argsort(freqs) # lowest to highest
>>> sorted_word_freq_with_numpy = OrderedDict()
>>> for idx in reversed(sorted_word_index):
... sorted_word_freq_with_numpy[words[idx]] = freqs[idx]
...
哪个更快?
还有其他更快捷的方式从OrderedDict
获得Counter
除了OrderedDict
之外,还有其他python对象可以实现相同的排序键值对吗?
假设内存不是问题。鉴于120 GB的内存,保持10亿个键值对不应该有太多问题吗?假设10亿个密钥每个密钥平均有20个字符,每个值都有一个整数。
答案 0 :(得分:3)
Pandas中的Series
对象是一组键值对(可以具有非唯一键),这可能是有意义的。它有一个sort
方法,按值排序并在Cython中实现。这是一个排序长度为一百万的数组的例子:
In [39]:
import pandas as pd
import numpy as np
arr = np.arange(1e6)
np.random.shuffle(arr)
s = pd.Series(arr, index=np.arange(1e6))
%timeit s.sort()
%timeit sorted(arr)
1 loops, best of 3: 85.8 ms per loop
1 loops, best of 3: 1.15 s per loop
给定普通的Python dict
,您可以通过调用
Series
my_series = pd.Series(my_dict)
然后按值按
排序my_series.sort()
答案 1 :(得分:2)
提高速度的一步是以最佳方式填充计数器。
例如,使用txt
(802 char)。
mycounter=Counter(txt.split())
生成与word_counter
相同的内容,但时间为1/3。
或者如果您必须逐行从文件中读取文本,请使用:
word_freq=Counter()
for line in txt.splitlines():
word_freq.update(line.split())
类似地,可以在没有循环的情况下创建有序字典:
mydict = OrderedDict(sorted(mycounter.items(), key=operator.itemgetter(1), reverse=True))
我在sorted
调用most_common
的方式与OrderedDict
相同(根据您的链接)。我将已排序项目列表直接传递给mycounter
创建者。
当我查看ipython
中的In [160]: mycounter
Out[160]: Counter({'the': 13, ',': 10, 'of': 9, 'a': 7, '.': 4, 'in': 4, 'to': 3, 'have': 3, 'session': 3, ''': 3, 'on': 3, 'you': 3, 'I': 3, 'that': 2, 'requested': 2, 'like': 2, 'European': 2, 'this': 2, 'countries': 2, 'as': 2, 'number': 2, 's': 1, 'various': 1, 'wish': 1, 'will': 1, 'Parliament': 1, 'meantime': 1, 'Resumption': 1, 'natural': 1, 'days': 1, 'debate': 1, 'You': 1, 'Members': 1, 'next': 1, '@-@': 1, 'hope': 1, 'enjoyed': 1, 'December': 1, 'victims': 1, 'particularly': 1, 'millennium': 1, .... 'behalf': 1, 'were': 1, 'failed': 1})
时,我会按排序顺序获取值:
__repr__
那是因为它的most_common
方法调用了items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
。这也是你的链接。
sorted
在进一步测试中,我发现直接调用In [166]: timeit mycounter.most_common()
10000 loops, best of 3: 31.1 µs per loop
In [167]: timeit sorted(mycounter.items(),key=operator.itemgetter(1),reverse=True)
10000 loops, best of 3: 30.5 µs per loop
In [168]: timeit OrderedDict(mycounter.most_common())
1000 loops, best of 3: 225 µs per loop
并不能节省时间:
In [174]: %%timeit
.....: sorteddict=OrderedDict()
.....: for word,freq in word_freq.most_common():
sorteddict[word]=freq
.....:
1000 loops, best of 3: 224 µs per loop
在这种情况下,直接加载字典也不会节省时间。您的迭代也同样如此:
np.argsort
对于此示例,使用argsort
无效(按时间)。只是调用most_common
比In [178]: timeit np.argsort(list(mycounter.values()))
10000 loops, best of 3: 34.2 µs per loop
慢。
x=np.array(list(mycounter.values()))
大部分时间是将列表转换为数组np.argsort(x)
。 numpy
要快得多。许多numpy
功能都是如此。在数组numpy
上运行时速度很快。但是在将列表转换为数组时会有很多开销。
我可以通过OrderedDict(np.sort(np.array(list(mycounter.items()), dtype='a12,i'), order='f1')[::-1])
在一行中创建OrderedDict:
lla = np.array(list(mycounter.items()),dtype='a12,i')
lla.sort(order='f1')
OrderedDict(lla[::-1])
或分段:
items()
我正在从order
创建一个结构化数组,在第二个字段中对其进行排序,然后创建字典。虽然没有节省时间。有关使用Long.parseLong(String s)
对结构化数组进行排序的最新示例,请参阅https://stackoverflow.com/a/31837513/901925。