查找具有数百万行的文件之间的常用短语

时间:2012-12-21 23:52:24

标签: python

我有两个文件,行数如下:

file1 - 110433003
file2 - 4838810

我需要找到它们之间的常用短语。每一行的形式如下:

p1 ||| p2 ||| .......

file1的p1可以是file2中的p2。不幸的是,我写的代码花了太长时间才做到这一点。

import sys
import os

if(len(sys.argv)<2):
        print 'python CommonPhrases.py enFr hrEn commonFile'
        sys.exit()
enFr = open(sys.argv[1],'r')
hrEn = open(sys.argv[2],'r')
common = open(sys.argv[3],'w')
sethrEn = set([])
setenFr= set([])
for line in hrEn:
        englishPhrase = line.split(' ||| ')[1]
        sethrEn.add(englishPhrase)

for line in enFr:
        englishPhrase = line.split(' ||| ')[0]
        if(englishPhrase in sethrEn):
                common.write(englishPhrase+'\n')

有更快的方法吗?

谢谢

2 个答案:

答案 0 :(得分:0)

你肯定需要这样的东西。看起来你将花费大部分时间来搜索比赛。

每当我发现自己试图让python更快时,我就会切换到pypy。 (http://pypy.org/) 它非常容易设置(只需下载二进制文件,将它放在你的路径中并将#!/ usr / bin / env python更改为#!/ usr / bin / env pypy)并提供5-10x范围内的加速比这样的任务。

有关使用PyTrie的参考实现,请参阅下文。

#!/usr/bin/env pypy

import sys
import os
sys.path.append('/usr/local/lib/python2.7/dist-packages/PyTrie-0.1-py2.7.egg/')
from pytrie import SortedStringTrie as trie

if(len(sys.argv)<2):
        print 'python CommonPhrases.py enFr hrEn commonFile'
        sys.exit()
enFr = open(sys.argv[1],'r')
hrEn = open(sys.argv[2],'r')
common = open(sys.argv[3],'w')

sethrEn = trie()

for line in hrEn:
        englishPhrase = line.strip().split(' ||| ')[1]
        sethrEn[englishPhrase] = None

for line in enFr:
        englishPhrase = line.strip().split(' ||| ')[0]
        if(englishPhrase in sethrEn):
                common.write(englishPhrase+'\n')

请注意,它需要最少的更改(4行),您需要安装PyTrie 0.1。在我的ubuntu系统上,“sudo easy_install PyTrie”就行了。

希望有所帮助。

答案 1 :(得分:0)

这听起来像树问题。也许这个想法可以帮助你。

使用树可以帮助找到常用词。我认为基于创建树的想法可以有两种解决方案。

树实现后,需要存储一个文件的每个单词(只有一个文件)。然后,开始读取第二个文件并搜索树中该文件上的每个单词。

这个解决方案当然有一些问题。在存储大量单词(或行)的内存中存储树可能需要大量的MB RAM。

让我们假设您设法使用固定数量的RAM来存储数据,因此,只计算数据本身(行的字符)。在最坏的情况下,您将需要255 ^ N个字节,其中N是最长行的长度(假设您使用almos每个N扩展的单词组合)。因此,存储长度为10的单词的每个组合,您将需要1.16252367019e + 24字节的RAM。那是很多。请记住,这个解决方案(据我所知)是“快速的”,但需要比你能找到的更多的RAM。

所以,其他解决方案,非常非常慢,是读取一行文件A,然后将其与文件B的每一行进行比较。它几乎不需要RAM,但需要太多时间,也许你不会能够真正等待它。

所以,也许另一个解决方案就是解决问题。

你说你有一个行列表,我们不知道它们是按字母顺序排序的。所以,也许你可以开始阅读文件A,并创建新文件。例如,每个新文件将存储'A'起始行,其他以'B'开头的行等等。然后,对文件B执行相同操作,并将两个文件作为'A'开始行,一个用于原始A文件,另一个用于原始B文件。然后,将它们与树进行比较。

在最好的情况下,线条将被平分,让你在内存中使用树。在最坏的情况下,您将只完成一个文件,与起始A文件相同,因为可能所有行都以'A'开头。

所以,也许,你可以实现一种方法来分割更多的文件,如果它们仍然太大,首先是行上的第一个字符。然后,'A'起始行,将它们划分为'AA','AB','AC'等,当然,删除以前的分割文件,直到你得到足够小的文件,使用更好的方法来搜索相同的线(可能在内存中使用树)。

这个解决方案也可能需要很长时间,但可能不会像低ram选项那么长,而且也不需要太多ram来工作。

这些是我现在能想到的解决方案。也许他们的工作,也许不是。