您好我发布了我的部分代码,然后我将解释我的目标:
for eachcsv in matches:
with open(eachcsv, 'r') as f:
lines = f.readlines()
for entry in rs:
for line in lines:
if entry in line:
print("found %s in %s" % (entry, eachcsv))
所以"匹配"我得到了一个csv文件列表(它们的路径)。我打开每个csv文件,然后用readlines()将它们加载到内存中。 " RS"是唯一ID的列表。对于列表中的每个元素" rs"我需要搜索csv文件的每一行并在每次在文件中找到id时打印(稍后我将测试该行是否包含另一个固定的单词)。
上面的代码适用于我的目的,但我不知道为什么处理400k行文件需要10多分钟,我需要为数千个文件执行此任务,因此它不可能我完成任务。在我看来,缓慢的部分是测试过程,但我不确定。
请注意我使用python是因为我对它更加舒适,如果使用其他工具我的问题有任何其他解决方案我可以使用它。
编辑: 我会尝试发布一些例子
"rs" list:
rs12334435
rs3244567
rs897686
....
files
# header data not needed
# data
# data
# data
# data
# data [...]
#COLUMN1 COLUMN2 COLUMN3 ...
data rs7854.rs165463 dataSS=1(random_data)
data rs465465data datadata
data rs798436 dataSS=1
data datars45648 dataSS=1
最终目标是计算每个文件在每个文件上出现的次数,如果在第3列中有SS = 1则在输出中标记它。 像
这样的东西found rs12345 SS yes file 3 folder /root/foobar/file
found rs74565 SS no file 3 folder /root/foobar/file
答案 0 :(得分:1)
很多问题是因为你有这么多嵌套循环。你可以通过消除循环来加快程序的运行:
其中一个循环位于文件中的每一行。但如果全部 你想要做的是确定是否存在任何匹配 文件,您可以在一个操作中搜索整个文件正文。成为 当然,这会搜索更长的字符串,但它会在一次操作中执行 在本机代码中,而不是在Python中。
循环遍历所有匹配字符串。但你知道那些在你面前的人 开始,每个文件都是相同的。所以这是一个很好的案例 在做什么时 - 更多的前期工作将在时间上节省下来 其余的计划。 Stand back, I'm going to use a regular expression
这是一个结合了以下两个想法的代码版本:
import re
import random
import sys
import time
# get_patterns makes up some test data.
def get_patterns():
rng = random.Random(1) # fixed seed, for reproducibility
n = 300
# Generate up to n unique integers between 60k and 80k.
return list(set([str(rng.randint(60000, 80000)) for _ in xrange(n)]))
def original(rs, matches):
for eachcsv in matches:
with open(eachcsv, 'r') as f:
lines = f.readlines()
for entry in rs:
for line in lines:
if entry in line:
print("found %s in %s" % (entry, eachcsv))
def mine(rs, matches):
my_rx = re.compile(build_regex(rs))
for eachcsv in matches:
with open(eachcsv, 'r') as f:
body = f.read()
matches = my_rx.findall(body)
for match in matches:
print "found %s in %s" % (match, eachcsv)
def build_regex(literal_patterns):
return "|".join([re.escape(pat) for pat in literal_patterns])
def print_elapsed_time(label, callable, args):
t1 = time.time()
callable(*args)
t2 = time.time()
elapsed_ms = (t2 - t1) * 1000
print "%8s: %9.1f milliseconds" % (label, elapsed_ms)
def main(args):
rs = get_patterns()
filenames = args[1:]
for function_name_and_function in (('original', original), ('mine', mine)):
name, func = function_name_and_function
print_elapsed_time(name, func, [rs, filenames])
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
您的原始代码位于original
,我的替换为mine
。
对于300种模式,我的实现在我的计算机上运行400ms。这大约是加速的30倍。对于更多匹配字符串,改进应该更大。加倍模式的数量大致使实现的运行时间加倍,但基于正则表达式的模式只需要大约3%的时间(尽管这部分是因为我的测试模式都有类似的前缀,而真实数据可能不是这样)。
编辑:更新的代码,为每场比赛打印一条消息。我的代码现在有点慢,但它仍然是一个改进,并且应该相对来说更快,更多字符串匹配:
~/source/stackoverflow/36923237$ python search.py example.csv
found green fox in example.csv
original: 9218.0 milliseconds
found green fox in example.csv
mine: 600.4 milliseconds
编辑:按要求解释正则表达式技术。
假设您要在文件中搜索字符串foobar和umspquux。一种方法是在文件中搜索第一个foobar,然后搜索umspquux。这是您开始使用的方法。
另一种方法是一次搜索两个字符串。想象一下,检查文件的第一个字符。如果它是'f'或'你',你可能正在查看匹配,并应检查第二个字符,看它是否分别为“o”或“m”。等等。如果你到达文件的结尾od,你将找到文件中的所有匹配qre来查找。
告诉计算机一次查找多个字符串的便捷方法是使用正则表达式。普通字符串是正则表达式。正则表达式'foobar'匹配'foobar里面的子字符串'foobar'是模糊的'。但是,你可以做更复杂的事情。您可以将两个正则表达式组合成一个组合的正则表达式,每个正则表达式都匹配一些东西,这些表达式将匹配这些事件中的任这是通过交替符号“|”完成的。所以正则表达式'foobar | umspquux'将匹配'foobar'或'umspquux'。你也可以匹配一个真正的'|'通过转义“|”的意义用反斜杠'\'。
这就是build_regex_literal_patterns
的全部内容。它会将列表['foobar','umspquux']转换为字符串'foobar | umspquux'。尝试一下 - 将函数定义放入您自己的文件中,并使用一些try-out参数调用它以查看它的行为。
顺便说一句,这是一个好方法,可以弄清楚任何一段代码是如何工作的 - 运行部分代码并打印中间结果。对于当然有副作用的程序,这很难安全地做,但是这个程序没有。
re.escape
中对build_regex_literal_patterns
的调用只是确保对任何特殊的正则表达式运算符(例如“|”)进行转义(在本例中为'\ |'),以便它们匹配自己
这里正则表达式方法的最后一部分是使用已编译正则表达式的 findall 方法。这只是在输入字符串(即文件正文)中返回正则表达式的所有匹配项。
您可以在Python documentation on regular expressions中阅读Python正则表达式。该文档基本上是参考资料,因此您可以在Google Develoeprs site has an introduction to Python regular expressions更好地找到更温和的介绍作为起点。 Jeffrey Friedl's Mastering Regular Expressions是关于正则表达式的非常全面的工作,认为它不会覆盖正则表达式的Python方言。
答案 1 :(得分:0)
你最大的内存密集型操作是读取每一行,这应该在外循环上。
您也不想使用readlines一次阅读整个文档,而是使用readline。 Readline的内存密集程度要低得多。
for eachcsv in matches:
with open(eachcsv, 'r') as f:
for line in f:
for entry in rs:
if entry in line:
print("found %s in %s" % (entry, eachcsv))
更多阅读https://docs.python.org/2/tutorial/inputoutput.html
您还可以采取其他超出此问题范围的优化,例如使用线程或使用多处理同时读入许多csv文件。 https://docs.python.org/2/library/threading.html
import threading
def findRSinCSVFile(csvFile,rs)
with open(csvFile, 'r') as f:
for line in f:
for entry in rs:
if entry in line:
print("found %s in %s" % (entry, eachcsv))
for csvFile in csvFiles():
threads.append(threading.Thread(target=findRSinCSVFile,args=(csvFile,rs)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
这将允许您同时解析所有csv文件。
(注意我没有测试任何此代码,仅作为示例)