我是一名数据挖掘者,因此,我花费大量时间以各种方式转换原始数据,以支持预测模型的消费。例如,以某种格式读取文件、标记化、语法化并投影为某种数字表示。多年来,我开发了一套丰富的方法来完成我能想到的大多数数据处理任务,但除了最基本的方式之外,我没有一个很好的方法来配置这些组件——通常我所做的是很多源代码中依赖于特定任务的特定方法的调用次数。我现在正在尝试将我的库重构为更好的东西,但我不太确定这是什么。
我目前的想法是,有一个函数对象列表,每个函数对象定义一些方法(比如,operate(...)),它们按顺序调用,每个对象要么通过引用处理某些数据流的内容,要么消耗前一个函数对象。这与我想要的很接近,但是由于输入和输出的数据类型会有所不同,因此使用泛型变得非常困难。要使用我上面的例子,我想通过这个处理数据的“管道”传递一些东西,比如:
input: string filename
filename -> collection of strings
collection<string> -> (stemming, stopword removal) -> collection of strings
collection<string> -> (tokenize) -> collection of string arrays
collection<string[]> -> (gram-ify) -> augment individual token strings with n-grams -> collection of string arrays
collection<string[]> -> projection into numeric vectors -> collection< double[] >
这是一个简单的例子,但想象一下我有 100 个这样的组件,我想将它们添加到一些数据流中。这满足了我易于配置的要求——我可以轻松地构建一个管道工厂来读取一些 yaml 文件并将其构建出来。然而,组件的设计模式一直困扰着我一段时间?合适的接口是什么样的?似乎在这里做事的唯一简单方法是传递对象,本质上取消对象(或者传递一些将对象作为成员变量的上下文对象),然后在输入时检查兼容性,抛出运行时异常. 这两种选择似乎同样糟糕。然而,我觉得我在这里接近一个非常好的和灵活的系统。你们能帮我把它推过栅栏吗?