在Python中处理简单的工作流程

时间:2010-01-24 11:20:48

标签: python workflow

我正在开发一个代码,它接受数据集并在其上运行一些算法。

用户上传数据集,然后选择将在此数据集上运行的算法,并创建如下工作流程:

workflow = 
{0: {'dataset': 'some dataset'},
 1: {'algorithm1': "parameters"},
 2: {'algorithm2': "parameters"},
 3: {'algorithm3': "parameters"}
}

这意味着我将workflow[0]作为我的数据集,我将在其上运行algorithm1。然后,我将获取其结果,我将在此结果上运行algorithm2作为我的新数据集。我将采用新结果并在其上运行algorithm3。直到最后一个项目为止,这个工作流程没有长度限制。

我用Python写这个。您能否提出一些有关处理此工作流程的策略?

5 个答案:

答案 0 :(得分:10)

您想在某些数据集上运行管道。这听起来像是一种减少操作(在某些语言中折叠)。不需要任何复杂的事情:

result = reduce(lambda data, (aname, p): algo_by_name(aname)(p, data), workflow)

这假设工作流程看起来像(面向文本,因此您可以使用YAML / JSON加载它):

workflow = ['data', ('algo0', {}), ('algo1', {'param': value}), … ]

你的算法看起来像:

def algo0(p, data):
    …
    return output_data.filename

algo_by_name采用名称并为您提供算法功能;例如:

def algo_by_name(name):
    return {'algo0': algo0, 'algo1': algo1, }[name]

(旧编辑:如果你想要一个用于编写管道的框架,你可以使用Ruffus。它就像一个make工具,但有进度支持和漂亮的流程图。)

答案 1 :(得分:4)

如果每个algorithm都适用于dataset上的每个元素,那么map()将是一个优雅的选择:

dataset=workflow[0]
for algorithm in workflow[1:]:
    dataset=map(algorithm, dataset)

e.g。对于奇数的平方根,请使用

>>> algo1=lambda x:0 if x%2==0 else x
>>> algo2=lambda x:x*x
>>> dataset=range(10)
>>> workflow=(dataset, algo1, algo2)
>>> for algo in workflow[1:]:
    dataset=map(algo, dataset)
>>> dataset
[0, 1, 0, 9, 0, 25, 0, 49, 0, 81]

答案 2 :(得分:2)

你想要这样做的方式对我来说似乎很合理,或者你需要发布更多关于你想要完成的事情的信息。

建议:我会将工作流结构放在带有元组而不是字典的列表中

workflow = [ ('dataset', 'some dataset'),
             ('algorithm1', "parameters"),
             ('algorithm2', "parameters"),
             ('algorithm3', "parameters")]

答案 3 :(得分:1)

定义一个跟踪...数据的Dataset类。定义此类中的方法。像这样:

class Dataset:
    # Some member fields here that define your data, and a constructor

    def algorithm1(self, param1, param2, param3):
        # Update member fields based on algorithm

    def algorithm2(self, param1, param2):
        # More updating/processing

现在,迭代你的“工作流程”字典。对于第一个条目,只需实例化您的Dataset类。

myDataset = Dataset() # Whatever actual construction you need to do

对于每个后续条目......

  • 以某种方式提取键/值(如果可能,我建议更改您的工作流数据结构,dict在这里不方便)
  • 将param字符串解析为参数元组(此步骤取决于您)。
  • 假设您现在拥有当前迭代的字符串algorithm和元组params ...

    getattr(myDataset,algorithm)(* params)

  • 这将调用myDataset上的函数,其名称由“algorithm”指定,参数列表包含在“params”中。

答案 4 :(得分:1)

以下是我将如何执行此操作(所有代码未经测试):

步骤1:您需要创建算法。数据集可能如下所示:

class Dataset(object):
    def __init__(self, dataset):
        self.dataset = dataset

    def __iter__(self):
        for x in self.dataset:
            yield x

请注意,您从中创建了一个迭代器,因此您一次迭代一个项目。这是有原因的,你稍后会看到:

另一种算法可能如下所示:

class Multiplier(object):
    def __init__(self, previous, multiplier):
        self.previous = previous
        self.multiplier = multiplier
    def __iter__(self):
        for x in previous:
            yield x * self.multiplier

第2步

然后,您的用户需要以某种方式制作链。现在如果他可以直接访问Python,你可以这样做:

dataset = Dataset(range(100))
multiplier = Multiplier(dataset, 5)

然后通过以下方式获得结果:

for x in multiplier:
    print x

它会一次询问一个数据的乘数,乘数又将作为数据集。如果你有一个链,那么这意味着一次处理一个数据。这意味着您可以在不占用大量内存的情况下处理大量数据。

第3步

您可能希望以其他方式指定步骤。例如,文本文件或字符串(这样的声音可能是基于网络的?)。然后你需要一个注册表的算法。最简单的方法是创建一个名为“registry.py”的模块,如下所示:

algorithms = {}

容易,嗯?你会注册一个新的算法,如下:

from registry import algorithms
algorithms['dataset'] = Dataset
algorithms['multiplier'] = Multiplier

您还需要一种方法,可以根据文本文件中的规范创建链。我会把它留给你。 ;)

(我可能会使用Zope组件架构并制作算法组件并在组件注册表中注册它们。但这严格来说就是矫枉过正了。)