【问题标题】:How to search if large text file contains words from sentence using python?如何使用python搜索大文本文件是否包含句子中的单词?
【发布时间】:2018-07-30 05:44:23
【问题描述】:

我有一个包含单词及其lemma 的文本文件 - 每行在第一列中包含单词形式,在第二列中包含单词引理。

我有一个推文(句子)列表,我需要将其转换为词引理 - 每个词都需要转换为其引理(文本文件中的第二列)

我尝试为每个单词打开和关闭文本文件,但这花费的时间太长(每个单词大约需要 15 秒才能在文本文件中找到它们的引理)。函数如下。

def returnLemma(str):
    str= word_tokenize(str)
    end_str = ""
    for word in str:
        infile = open('MorphDict.txt', 'r')
        for line in infile:
            line.strip()
            prva=line.split()[0] 
            druga=line.split()[1]
            if word==prva:
                end_str = end_str+" "+druga 
                break;
        infile.close()
    return end_str

是否可以更有效地搜索此文本文件 (>100MB)?是否可以使用pandas package 来解决这个问题?

【问题讨论】:

  • 您的两个问题的答案基本上都是肯定的。但是,您可能会考虑重构此代码,以便在函数外部读取来自MorphDict.txt 的数据(一次)并作为参数传递。旁注:您当前使用 str 作为名称,这与 Python 内置冲突
  • 你能发布一个小的可重复输入数据集和你想要的数据集吗? PS你问的是什么语言?是英文的吗?
  • 为什么要在这里使用 Pandas?
  • @Javier 你为什么不呢?您可以在单个命令中连接字符串
  • @roganjosh 好吧,乍一看,这似乎是一个非常简单的函数。添加 Pandas 会使它变得更加复杂。我可能错过了你的意思。可以使用列表来保存要连接的字符串,从而比在帖子中更有效地连接。如果您使用 Pandas 发布此代码,也许它会澄清我的误解。

标签: python pandas search lemmatization


【解决方案1】:

当您需要比较两个列表的元素并且其中一个比另一个小得多时,请在内循环中使用最小的。这样总是更有效率。

尽量不要重复做同样的工作。分割线时,请保留部分,这样您就不需要再次这样做了。

line.strip() 不会改变line,而是生成一个没有空格的新行。使用line = line.strip()

您可以从头开始寻找,而不是重复打开文件。

【讨论】:

    【解决方案2】:

    我会像这样编写相同的函数:

    from collections import defaultdict
    
    
    word_tokenize = lambda s: s.split()
    
    
    def returnLemma(s, morph_lines):
        tokens = word_tokenize(s)
        token_positions = defaultdict(list)
        for i, t in enumerate(tokens):
            token_positions[t].append(i)
    
        drugas = [None] * len(tokens)
        for line in morph_lines:
            line = line.strip()
            parts = line.split(maxsplit=3)
            prva = parts[0]
            try:
                positions = token_positions[prva]
            except KeyError:
                pass
            else:
                druga = parts[1]
                for i in positions:
                    drugas[i] = druga
    
        return ' ' + ' '.join(
            druga if druga is not None else token
            for token, druga in zip(tokens, drugas)
        )
    
    
    import unittest
    
    
    class ReturnLemmaTest(unittest.TestCase):
    
        def test_when_nothing_matches_then_it_returns_a_single_space(self):
            result = returnLemma('hello world', ['line 1', 'line 2'])
            self.assertEqual(' hello world', result)
    
        def test_when_one_line_matches_then_it_returns_its_second_word(self):
            result = returnLemma('hello world line-b', ['line-a 1', 'line-b 2'])
            self.assertEqual(' hello world 2', result)
    
        def test_when_many_lines_match_then_it_returns_their_second_words_separated_by_a_space(self):
            result = returnLemma('hello b world b c', ['a 0', 'b 1', 'c 2'])
            self.assertEqual(' hello 1 world 1 2', result)
    
    
    if __name__ == '__main__':
        unittest.main()
    

    returnLemma 的第二个参数可以是打开的文件,但使用列表更容易测试。

    【讨论】:

    • @roganjosh 在不将整个文件加载到内存的情况下,这是我能做的最好的事情。
    • 抱歉,我被家里的新生儿分心了! pastebin.com/KSRKWQXP 将是 one pandas 方法,但我没有宣布它是最有效的,因为我没有花时间正确思考问题,但我确实想在评论后关闭一个松散的结局原来。
    • 这不是一个完整的方法,但它匹配 OP 检查是否相等
    • 在开始匹配之前需要将整个文件加载到内存中并进行解析... AFAICS,对于少量数据,速度优势可以忽略不计,对于大量数据,它不适合内存。恕我直言,为此使用 Pandas 将有一个非常狭窄的最佳位置。感谢您展示您的意思。
    • 是的,我们同意内存部分。 ">100MB" 是……抽象的。在它成为问题之前有很大的余地,但它是开放式的
    【解决方案3】:

    这是最终的工作代码 - 与 @Javier 的函数略有不同。感谢大家的帮助,尤其是@Javier 和@MaxU。

    from nltk.tokenize import word_tokenize
    from collections import defaultdict
    
    def vratiLemu(s, morph_lines):
        tokens = word_tokenize(s)
        token_positions = defaultdict(list)
        for i, t in enumerate(tokens):
            token_positions[t].append(i)
    
        for line in morph_lines:
            line = line.strip()
            parts = line.split()
            prva = parts[0]
            try:
                positions = token_positions[prva]
            except KeyError:
                pass
            else:
                druga = parts[1]
                for i in positions:
                    tokens[i] = druga
    
        return ' ' + ' '.join(druga for druga in tokens if druga is not None)              
    
    morphDict= open('SveSrpMDANSI.txt', 'r')
    out=vratiLemu1("Suštinsko pitanje nije postavljeno: zašto predsednik odbora nije otvorio pretres a morao je",morphDict)
    print out
    

    Suštinsko pitanje jesam postavljen : zašto predsednik odbor jesam otvoriti pretres a morati jeste

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 2016-02-16
      • 2020-02-28
      • 1970-01-01
      相关资源
      最近更新 更多