如何重构这个python代码块以提高效率

时间:2009-12-19 17:25:31

标签: python

此代码块有效 - 它循环遍历具有重复数据集的文件 并提取每组的5条信息中的每一条。

但我知道当前的因子分解效率并不高,因为它是循环的 通过每条线找到每条线。

想知道一些python专家能否提供更好的方法来更有效地做到这一点。

def parse_params(num_of_params,lines):

  for line in lines:
    for p in range(1,num_of_params + 1,1):
      nam = "model.paramName "+str(p)+" "
      par = "model.paramValue "+str(p)+" "
      opt = "model.optimizeParam "+str(p)+" "
      low = "model.paramLowerBound "+str(p)+" "
      upp = "model.paramUpperBound "+str(p)+" "
      keys = [nam,par,opt,low,upp]
      for key in keys:
        if key in line:
          a,val = line.split(key)
          if key == nam: names.append(val.rstrip())
          if key == par: params.append(val.rstrip())
          if key == opt: optimize.append(val.rstrip())
          if key == upp: upper.append(val.rstrip())
          if key == low: lower.append(val.rstrip())

print "Names   = ",names   
print "Params   = ",params
print "Optimize = ",optimize
print "Upper    = ",upper
print "Lower    = ",lower

7 个答案:

答案 0 :(得分:2)

虽然这不能回答你的问题(其他答案正在解决这个问题)但是在做与你正在做的事情相似的事情上帮助了我很多的事情List Comprehensions。它们允许您以简洁和(我认为)易于阅读的方式构建列表。

例如,下面的代码使用您尝试获取的值构建一个二维数组。 some_funct这里有一个小正则表达式,如果我这样做,它使用键中最后一个空格的索引作为参数,并向前看以收集你想要在行中获得的值(与当前正在查看的键对应的值)并将其附加到seen_keys 2D数组中的正确索引。

罗嗦,是的,但是如果你得到列表理解并且你能够构建正则表达式来做到这一点,你就会有一个很好的,简洁的解决方案。

keys = ["model.paramName ","model.paramValue ","model.optimizeParam ""model.paramLowerBound ","model.paramUpperBound "]
for line in lines:
    seen_keys = [[],[],[],[],[]]
    [seen_keys[keys.index(k)].some_funct(line.index(k) for k in keys if k in line]

答案 1 :(得分:1)

那里有很多重复,如果你添加了另一个keyparam,你将不得不在很多地方添加它,这使你很容易出错。你想要做的就是削减所有重复的地方并使用某种数据模型,例如dict

其他一些人提供了一些很好的例子,所以我会在这里留下我的答案给你一些思考。

答案 2 :(得分:1)

看到预期的格式并不容易。从我所看到的,格式如下:

lines = [
    "model.paramName 1 foo",
    "model.paramValue 2 bar",
    "model.optimizeParam 3 bat",
    "model.paramLowerBound 4 zip",
    "model.paramUpperBound 5 ech",
    "model.paramName 1 foo2",
    "model.paramValue 2 bar2",
    "model.optimizeParam 3 bat2",
    "model.paramLowerBound 4 zip2",
    "model.paramUpperBound 5 ech2",
]

如果每行中有多个值,我看不到上面的代码。这意味着除非我遗漏了某些东西,否则数字并不重要。在这种情况下,这非常容易:

import re

def parse_params(num_of_params,lines):
    key_to_collection = {
        "model.paramName":names,
        "model.paramValue":params,
        "model.optimizeParam":optimize,
        "model.paramLowerBound":upper,
        "model.paramUpperBound":lower,
    }

    reg = re.compile(r'(.+?) (\d) (.+)')

    for line in lines:
        m = reg.match(line)
        key, digit, value = m.group(1, 2, 3)
        key_to_collection[key].append(value)

答案 3 :(得分:1)

从您的代码中看并不完全明显,但看起来每条线最多只能有一个“命中”;如果确实如此,那么就像:

import re

def parse_params(num_of_params, lines):
  sn = 'Names Params Optimize Upper Lower'.split()
  ks = '''paramName paramValue optimizeParam
          paramLowerBound paramUpperBound'''.split()
  vals = dict((k, []) for k in ks)
  are = re.compile(r'model\.(%s) (\d+) (.*)' % '|'.join(ks))
  for line in lines:
    mo = are.search(line)
    if not mo: continue
    p = int(mo.group(2))
    if p < 1 or p > num_of_params: continue
    vals[mo.group(1)].append(mo.group(3).rstrip())
  for k, s in zip(ks, sn):
    print '%-8s =' % s,
    print vals[k]

可能有效 - 我用一些代码对它进行了如下操作:

if __name__ == '__main__':
  lines = '''model.paramUpperBound 1 ZAP
    model.paramLowerBound 1 zap
    model.paramUpperBound 5 nope'''.splitlines()
  parse_params(2, lines)

它会发出

Names    = []
Params   = []
Optimize = []
Upper    = ['zap']
Lower    = ['ZAP']

我认为这是你想要的(如果某些细节必须有所不同,请准确说明它们是什么,让我们看看我们是否可以解决它。)

两个关键想法是:使用dict代替大量if s;使用re将“以下任何可能性”与re模式中的带括号的组匹配,以捕获感兴趣的位(model.之后的关键字,此后的整数,以及“值”这是行的其余部分),而不是大量的if x in y检查和字符串操作。

答案 4 :(得分:1)

OP中给出的代码每行进行多次测试,以尝试匹配预期的值集,每个值都是动态构建的。我们可以使用正则表达式来尝试以更便宜(更健壮)的方式进行匹配,而不是为每一行构造paramValue1paramValue2等。

这是我的代码片段,摘自已发布的一些想法。这允许您向key_to_collection字典添加新关键字,而不必更改任何其他内容。

import re

def parse_params(num_of_params, lines):

    pattern = re.compile(r"""
        model\.
        (.+)    # keyword
        (\d+)   # index to keyword
        [ ]+    # whitespace
        (.+)    # value
        """, re.VERBOSE)

    key_to_collection = {
        "paramName": names,
        "paramValue": params,
        "optimizeParam": optimize,
        "paramLowerBound": upper,
        "paramUpperBound": lower,
    }

    for line in lines:
        match = pattern.match(line)
        if not match:
            print "Invalid line: " + line
        elif match[1] not in key_to_collection:
            print "Invalid key: " + line
        # Not sure if you really care about enforcing this
        elif match[2] > num_of_params:
            print "Invalid param: " + line
        else:
            key_to_collection[match[1]].append(match[3])

完全披露:我没有编译/测试过这个。

答案 5 :(得分:1)

你确定parse_params是瓶颈吗?你有没有想过你的应用程序?

import re
from collections import defaultdict 

names = ("paramName paramValue optimizeParam "
         "paramLowerBound paramUpperBound".split())
stmt_regex = re.compile(r'model\.(%s)\s+(\d+)\s+(.*)' % '|'.join(names))

def parse_params(num_of_params, lines):
    stmts = defaultdict(list)
    for m in (stmt_regex.match(s) for s in lines):
        if m and 1 <= int(m.group(2)) <= num_of_params: 
           stmts[m.group(1)].append(m.group(3).rstrip())

    for k, v in stmts.iteritems():
        print "%s = %s" % (k, ' '.join(v))

答案 6 :(得分:0)

当然可以提高效率。但是,说实话,除非这个函数每秒被调用数百次,或者在数千行上工作,是否有必要呢?

我会更关心明确发生了什么......目前,我在这方面还不太清楚。

只要注意它,输入看起来像这样:

model.paramName 1 a model.paramValue 1 B model.optimizeParam 1 C model.paramLowerBound 1 D model.paramUpperBound 1 E model.paramName 2 F model.paramValue 2 G model.optimizeParam 2 H model.paramLowerBound 2我model.paramUpperBound 2 J

你想要的输出似乎是这样的:

Names     = AF
Params    = BG
etc...

现在,既然我的输入肯定与你的输入不匹配,输出也可能会关闭,但我认为我有这个要点。

有几点。首先,将多少参数传递给函数是否重要?例如,如果输入有两组参数,我是否只想读取这两个参数,或者是否有必要允许该函数只读取一个?例如,您的代码允许我调用parse_params(1,1)并让它只读取来自同一输入的以1结尾的参数。如果这实际上不是一个要求,你可以跳过很大一部分代码。

第二,仅阅读给定参数是否重要?例如,如果我有一个名为'paramFoo'的参数,那么如果我读它会不好?您还可以通过抓取所有参数(无论其名称如何)并提取其值来简化过程。

def parse_params(input):
  parameter_list = {}
  param = re.compile(r"model\.([^ ]+) [0-9]+ ([^ ]+)")
  each_parameter = param.finditer(input)
  for match in each_parameter:
    key = match[0]
    value = match[1]
    if not key in paramter_list:
      parameter_list[key] = []

    parameter_list[key].append(value)

  return parameter_list

在这种情况下,输出将是这样的:

{'paramName':[A,F],'paramValue':[B,G],'optimizeParam':[C,H]等......}

注意:我不太了解Python,我是一个Ruby人,所以我的语法可能会关闭。道歉。