【发布时间】:2015-11-04 08:21:24
【问题描述】:
在我正在开发的程序的一部分中,我想使用作为数据集 X 的某些函数的项执行线性回归。使用的确切模型可由用户配置,特别是要使用哪些术语(或术语集)。这涉及生成矩阵X',其中X' 的每一行都是X 对应行的函数。 X' 的列将是我的回归的预测变量。
例如,假设我的数据集是二维的(X 有 2 列)。如果我们将x 和x' 表示为X 和X' 的对应行,那么假设x 是二维的x' 可能类似于
[ 1, x[0], x[1], x[0] * x[1], sqrt(x[0]), sqrt(x[1]), x[0]**2, x[1]**2 ]
您可以看到这些术语成组出现。首先是一个 1(常数),然后是未转换的数据(线性),然后是两个数据元素的乘积(如果 x 有两个以上的维度,则都是成对乘积),然后是个体的平方根和平方条款。
我需要在 python 中以某种方式定义所有这些术语集,以便每个术语都有一个用户可读的名称、生成术语的函数、从输入维度获取术语数量的函数、生成标签的函数对于基于数据列标签的术语等。从概念上讲,它们都应该是TermSet 类的实例或类似的东西,但这并不完全有效,因为它们的方法需要不同。我的第一个想法是使用这样的东西:
termsets = {} # Keep track of sets
class SqrtTerms:
display = 'Square Roots' # user-readable name
@staticmethod
def size(d):
"""Number of terms based on input columns"""
return d
@staticmethod
def make(X):
"""Make the terms from the input data"""
return numpy.sqrt(X)
@staticmethod
def labels(columns):
"""List of term labels based off of data column labels"""
return ['sqrt(%s)' % c for c in columns]
termsets['sqrt'] = SqrtTerms # register class in dict
class PairwiseProductTerms:
display = 'Pairwise Products'
@staticmethod
def size(d):
return (d * (d-1)) / 2
@staticmethod
def make(X):
# Some more complicated code that spans multiple lines
...
@staticmethod
def labels(columns):
# Technically a one-liner but also more complicated
return ['(%s) * (%s)' % (columns[c1], columns[c2])
for c1 in range(len(columns)) for c2 in range(len(columns))
if c2 > c1]
termsets['pairprod'] = PairwiseProductTerms
这很有效:我可以从字典中检索类,将我想要使用的类放在一个列表中,然后对每个类调用适当的方法。尽管如此,创建仅具有静态属性和方法的类看起来很丑陋且不符合 Python 标准。我想出的另一个想法是创建一个可以像这样使用的类装饰器:
# Convert bound methods to static ones, assign "display" static
# attribute and add to dict with key "name"
@regression_terms(name='sqrt', display='Square Roots')
class SqrtTerms:
def size(d):
return d
def make(X):
return numpy.sqrt(X)
def labels(columns):
return ['sqrt(%s)' % c for c in columns]
这给出了相同的结果,但是(对我自己而言)阅读和写作更干净、更好(尤其是当我需要很多这些时)。然而,事情实际上在幕后工作的方式是模糊的,任何阅读这篇文章的人可能一开始很难弄清楚发生了什么。我也想过为这些创建一个元类,但这听起来有点矫枉过正。我应该在这里使用更好的模式吗?
【问题讨论】:
-
有功能的模块呢?
-
纯静态类的标准替代方案是模块,但在这种情况下,我有许多具有相同名称的函数和属性的类。这一切都已经在一个模块中,但我绝对可以通过将它变成一个包并为每组术语创建一个模块来完成我想要的。不过,这真的完全不像您应该使用模块。
标签: python python-2.7 metaprogramming metaclass python-decorators