【问题标题】:Find and replace in CSV files with Python使用 Python 在 CSV 文件中查找和替换
【发布时间】:2011-04-25 10:48:06
【问题描述】:

a previous question 相关,我正在尝试对一些大型 CSV 文件进行替换。

文件之间的列顺序(和内容)会发生变化,但是对于每个文件,我想要并且可以通过列标题名称识别大约 10 列。对于我想要的每一列,我也有 1-2 个字典。因此,对于我想要的列,我只想使用正确的字典并希望按顺序实现它们。

我如何尝试解决此问题的示例:

# -*- coding: utf-8 -*-
import re

# imaginary csv file. pretend that we do not know the column order.
Header = [u'col1', u'col2']
Line1 = [u'A',u'X']
Line2 = [u'B',u'Y']
fileLines = [Line1,Line2]

# dicts to translate lines
D1a = {u'A':u'a'}
D1b = {u'B':u'b'}
D2 = {u'X':u'x',u'Y':u'y'}

# dict to correspond header names with the correct dictionary.
# i would like the dictionaries to be read sequentially in col1.
refD = {u'col1':[D1a,D1b],u'col2':[D2]}

# clunky replace function
def freplace(str, dict):
    rc = re.compile('|'.join(re.escape(k) for k in dict))
    def trans(m):
        return dict[m.group(0)]
    return rc.sub(trans, str)

# get correspondence between dictionary and column
C = []
for i in range(len(Header)):
    if Header[i] in refD:
        C.append([refD[Header[i]],i])

# loop through lines and make replacements
for line in fileLines:
    for i in range(len(line)):
        for j in range(len(C)):
            if C[j][1] == i:
                for dict in C[j][0]:
                    line[i] = freplace(line[i], dict)

我的问题是这段代码很慢,我不知道如何加快速度。 我是初学者,我的猜测是我的 freplace 函数在很大程度上会减慢速度,因为它必须为每一行中的每一列进行编译。我想从该函数中删除rc = re.compile('|'.join(re.escape(k) for k in dict)) 行,但不知道该怎么做,但仍然保留我的其余代码正在执行的操作。

【问题讨论】:

  • 那么对于每一列,您需要一个唯一的正则表达式吗?为什么不只创建 10 个正则表达式,并指向正确的一个,偏移量由标题确定的列确定?这样,它是一次性编译 10 列然后你设置好了吗? (对不起,我根本不懂 Python,我想这将是我的第一个猜测)。
  • @onaclov2000:确实这是我希望做的,但我不知道如何指向正确的正则表达式。

标签: python performance function dictionary csv


【解决方案1】:

您可以做很多事情来加快速度:

首先,使用csv 模块。它为读取和写入 CSV 文件提供了高效且无错误的方法。 DictReader 对象尤其是您感兴趣的对象:它将从文件中读取的每一行呈现为一个以列名作为键的字典。

其次,编译一次正则表达式,而不是每次使用它们。将编译的正则表达式保存在一个字典中,该字典由您要应用它们的列作为键。

第三,考虑如果你对一个长字符串应用一百个正则表达式,你将要从头到尾扫描该字符串一百次。这可能不是解决问题的最佳方法;您最好花点时间在一种方法上,让您从头到尾读取一次字符串。

【讨论】:

  • +1 表示csv 模块。正则表达式在这里不是正确的工具。
  • @罗伯特:谢谢。 1.) 在我的实际文件中,我使用的是 csv 模块。我将研究 DictReader 以匹配列;以前我没有使用它,因为我必须先翻译文本的第一行,然后再将列与其相应的字典匹配,我这样做就像“for line in lines: if firstline == 1: [translate, match translate cols 符合字典等]"。 2.) 事实上,我希望先编译它们,但不知道如何引用它们。 . .我会试试你的建议。
  • @Robert: 3.) 我只想使用具有特定列的特定字典,所以我不知道如何实现你的建议。总而言之,我只有 10 部字典,所以我希望这不会造成太大的速度损失。而且,如果我无论如何都要遍历行中的列,那么除了将正确的正则表达式分配给正确的列的步骤之外,我看不出我调用不同的正则表达式有什么意义,正如您在第二点中所说的那样。
  • 您使用的每个 RE 从头到尾搜索目标字符串。如果您的目标字符串很长,并且您使用了很多 RE,那么您使用多少 RE 可能非常重要。如果不分析您的代码以找出实际花费了这么长时间,就很难知道。
  • @Robert:为什么在整行上使用 1 个大 RE 比使用 10 个小 RE 更快,每列一个?我知道这里涉及一个额外的检查步骤:必须检查每一列以知道要使用哪个 RE。到目前为止,对我来说,RE 被描述为一种“神奇的方式”:“RE 一次搜索所有内容,而不是在字典中迭代一个一个搜索的键”,这让这个 Python/编程初学者感到困惑。你知道 /how/ RE 的参考资料,因为我找不到任何对我有意义的东西。
【解决方案2】:

你不需要re:

# -*- coding: utf-8 -*-

# imaginary csv file. pretend that we do not know the column order.
Header = [u'col1', u'col2']
Line1 = [u'A',u'X']
Line2 = [u'B',u'Y']
fileLines = [Line1,Line2]

# dicts to translate lines
D1a = {u'A':u'a'}
D1b = {u'B':u'b'}
D2 = {u'X':u'x',u'Y':u'y'}

# dict to correspond header names with the correct dictionary
refD = {u'col1':[D1a,D1b],u'col2':[D2]}

# now let's have some fun...

for line in fileLines:
    for i, (param, word) in enumerate(zip(Header, line)):
        for minitranslator in refD[param]:
            if word in minitranslator:
                line[i] = minitranslator[word]

返回:

[[u'a', u'x'], [u'b', u'y']]

【讨论】:

  • 我之前的问题给我的印象是,re 比单独遍历字典中的每个项目要快得多?另外,当给定列有多个字典时,我想依次循环遍历字典,这就是我在 refD 中使用列表的原因。
  • @rallen - 如果您有大型 csv 文件,那么最好正确准备 refD/translator 字典。如果您想一个接一个地应用几个字典(D1a,D1b),然后将它们合并到一个字典中(translator[param]) - 它们的键应该是唯一的,不是吗?在我的最后一个 for 循环中,我只迭代大型 csv 文件的行和列,而不是字典 - 我只是通过键访问它们,这是 fast
  • 由于我的数据的性质,我希望保留字典。如果某些内容通过 D1a 被替换,它会比通过 D1b 提供更多信息(主要由 D1a 中的缩短条目组成)。
【解决方案3】:

因此,如果是这种情况,并且所有 10 列每次都具有相同的名称,但顺序不正确,(我不确定这是否是您在上面做的,但这里是)保留一个数组标题名称,每列一个,拆分为元素(每行应该是 10 个项目),现在只需通过执行 case/select 组合来偏移哪个正则表达式,比较标题数组的元素编号,然后在 case 内引用相同偏移量的数据数组,因为名称是正确的情况,您应该能够重复使用相同的 10 个正则表达式,而不必每次都重新编译一个新的“命令”。

我希望这是有道理的。对不起,我不知道帮助你的语法,但我希望我的想法是你正在寻找的 编辑: 即。

在开始循环之前初始化所有正则表达式。

然后在您阅读一行之后(以及在标题行之后)

选择数组[n]

案例“column1”

正则表达式(数据[0]);

案例“column2”

正则表达式(数据[1]); . . . . 结束选择

这应该为正确的列调用正确的正则表达式

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 2013-05-27
    相关资源
    最近更新 更多