Python 3.x 听写/列表理解在文本tada上的表现

Python 3.x 听写/列表理解在文本tada上的表现,python-3.x,performance,functional-programming,Python 3.x,Performance,Functional Programming,我必须处理一个包含4000个字符串的列表,其中每个字符串代表一个文档。我的目标是计算每个单词出现的文档数,并返回一个dict,如: {单词:出现的文档数} 我写了两种不同的方法,它们适用于一小部分文档。一个使用基本的迭代和条件,另一个使用理解和一些功能特性,如lambda和map。以下是两个版本: 方法1 def corpus_word_frequency(corpus_text): bag_of_words = " ".join(corpus_text).split() to

我必须处理一个包含4000个字符串的列表,其中每个字符串代表一个文档。我的目标是计算每个单词出现的文档数,并返回一个dict,如:

{单词:出现的文档数}

我写了两种不同的方法,它们适用于一小部分文档。一个使用基本的迭代和条件,另一个使用理解和一些功能特性,如lambda和map。以下是两个版本:

方法1

def corpus_word_frequency(corpus_text):

    bag_of_words = " ".join(corpus_text).split()
    tokens = set(bag_of_words)

    words_frequency = {}

    for doc in corpus_text:
        text = doc.split()

        for word in tokens:
            if word in text:
                if word in words_frequency.keys():
                    words_frequency[word] += 1
                else:
                    words_frequency[word] = 1

    return words_frequency
方法2

def corpus_word_frequency(corpus_text):
    """docstring"""

    bag_of_words = " ".join(corpus_text).split()
    tokens = set(bag_of_words)

    return {
        token: sum(
            map(lambda doc: 1 if token in doc.split() else 0, corpus_text))
        for token in tokens
    }
问题是:方法1对我来说很慢,但它是可行的,但是方法2我不能忍受等待它结束,它太多了。那么,列表理解性能是问题所在吗?地图和lambda的使用?还有别的吗?有没有办法使方法2更有效?

使用示例文件,我将您的函数与内置的
集合进行了比较。Counter

In [1]: from collections import Counter

In [2]: def method1(corpus_text): 
   ...:     bag_of_words = " ".join(corpus_text).split() 
   ...:     tokens = set(bag_of_words) 
   ...:     words_frequency = {} 
   ...:     for doc in corpus_text: 
   ...:         text = doc.split() 
   ...:         for word in tokens: 
   ...:             if word in text: 
   ...:                 if word in words_frequency.keys(): 
   ...:                     words_frequency[word] += 1 
   ...:                 else: 
   ...:                     words_frequency[word] = 1 
   ...:     return words_frequency 

In [3]: def method2(corpus_text): 
   ...:     bag_of_words = " ".join(corpus_text).split() 
   ...:     tokens = set(bag_of_words) 
   ...:     return { 
   ...:         token: sum( 
   ...:             map(lambda doc: 1 if token in doc.split() else 0, corpus_text)) 
   ...:         for token in tokens 
   ...:     }

In [4]: with open("Latin-Lipsum.txt") as file:
   ...:     text = file.read()

In [5]: method1(text)
Out[5]:
{'L': 1,
 'o': 63,
 'r': 72,
 ...
 'O': 1,
 'P': 1,
 'j': 1}

In [6]: Counter(text)
Out[6]:
Counter({'L': 1,
         'o': 63,
         'r': 72,
         ...
         'O': 1,
         'P': 1,
         'j': 1})
它们的执行几乎完全相同,只是在本例中,
计数器也对
\n
字符进行计数

就速度而言,
计数器
要快得多:

In [7]: %timeit method1(text)                                                                                                      
1.96 ms ± 32.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [8]: %timeit method2(text)                                                                                                      
10.5 ms ± 19.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [9]: %timeit Counter(text)                                                                                                      
43.8 µs ± 50.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
您的第二种方法确实比第一种方法慢,而且
计数器
比这两种方法快得多。

使用示例文件,我将您的函数与内置的
集合进行了比较。计数器

In [1]: from collections import Counter

In [2]: def method1(corpus_text): 
   ...:     bag_of_words = " ".join(corpus_text).split() 
   ...:     tokens = set(bag_of_words) 
   ...:     words_frequency = {} 
   ...:     for doc in corpus_text: 
   ...:         text = doc.split() 
   ...:         for word in tokens: 
   ...:             if word in text: 
   ...:                 if word in words_frequency.keys(): 
   ...:                     words_frequency[word] += 1 
   ...:                 else: 
   ...:                     words_frequency[word] = 1 
   ...:     return words_frequency 

In [3]: def method2(corpus_text): 
   ...:     bag_of_words = " ".join(corpus_text).split() 
   ...:     tokens = set(bag_of_words) 
   ...:     return { 
   ...:         token: sum( 
   ...:             map(lambda doc: 1 if token in doc.split() else 0, corpus_text)) 
   ...:         for token in tokens 
   ...:     }

In [4]: with open("Latin-Lipsum.txt") as file:
   ...:     text = file.read()

In [5]: method1(text)
Out[5]:
{'L': 1,
 'o': 63,
 'r': 72,
 ...
 'O': 1,
 'P': 1,
 'j': 1}

In [6]: Counter(text)
Out[6]:
Counter({'L': 1,
         'o': 63,
         'r': 72,
         ...
         'O': 1,
         'P': 1,
         'j': 1})
它们的执行几乎完全相同,只是在本例中,
计数器也对
\n
字符进行计数

就速度而言,
计数器
要快得多:

In [7]: %timeit method1(text)                                                                                                      
1.96 ms ± 32.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [8]: %timeit method2(text)                                                                                                      
10.5 ms ± 19.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [9]: %timeit Counter(text)                                                                                                      
43.8 µs ± 50.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

您的第二种方法确实比第一种方法慢,而且
计数器
比这两种方法快得多。

您看过内置的吗?除此之外,
lambda
与Python中的其他方法相比通常非常慢。我第一次看到如何解决我的问题时遇到了collections.Counter,但在另一次讨论中看到它有点慢,所以我尝试先实现一些东西。如果这两种方法都没有解决方案,这是我的下一个选择。你看过内置的了吗?除此之外,
lambda
与Python中的其他方法相比通常非常慢。我第一次看到如何解决我的问题时遇到了collections.Counter,但在另一次讨论中看到它有点慢,所以我尝试先实现一些东西。这是我的下一个选择,以防这两种方法缺乏解决方案。