1

我正在尝试考虑 Python API 如何查找像 Cassandra 这样的大型数据存储。R、Matlab 和 NumPy 倾向于使用“一切都是矩阵”的公式,并分别执行每个操作。该模型已被证明对可以放入内存的数据有效。然而,SAS 对大数据的好处之一是它逐行执行,在移动到下一个之前完成所有行计算。对于像 Cassandra 这样的数据存储,这个模型似乎是一个巨大的胜利——我们只循环数据一次。

在 Python 中,SAS 的方法可能类似于:

with load('datastore') as data:
  for row in rows(data):
    row.logincome = row.log(income)
    row.rich = "Rich" if row.income > 100000 else "Poor"

这是(太?)明确的,但具有只循环一次的优点。对于较小的数据集,与 NumPy 相比,性能会非常差,因为函数没有使用编译代码进行矢量化。在 R/Numpy 中,我们会得到更简洁和编译的:

data.logincome = log(data.income)
data.rich = ifelse(data.income > 100000, "Rich", Poor")

这将非常快速地执行,因为log并且ifelse都是对向量进行操作的编译函数。然而,一个缺点是我们将循环两次。对于小型数据集,这无关紧要,但对于 Cassandra 支持的数据存储,我看不出这种方法是如何工作的。

问题:有没有办法保留第二个 API(如 R/Numpy/Matlab)但延迟计算。也许通过在最后调用一个同步(数据)函数?

另类的想法?维护 NumPy 类型语法会很好,因为用户将使用 NumPy 进行较小的操作,并且可以直观地掌握它的工作原理。

4

2 回答 2

2

我对 Cassandra/NumPy 一无所知,但如果您采用第二种方法(使用 NumPy)以合理大小的块处理数据,您可能会受益于 CPU 和/或文件系统缓存,因此可以防止任何由循环两次数据,而不会放弃使用优化处理功能的好处。

于 2010-01-05T23:42:47.213 回答
1

我没有完美的答案,只是一个粗略的想法,但也许值得。它以 Python 生成器为中心,是一种生产者-消费者风格的组合。

一方面,由于您不想循环两次,我认为没有办法绕过行的显式循环,如下所示:

for row in rows(data):
    # do stuff with row

现在,将该行提供给(任意数量的)消费者,这些消费者 - 不要阻塞 - 再次生成器。但是您将使用send生成器的方法。作为此类消费者的示例,以下是以下草图riches

def riches():
    rich_data = []
    while True:
        row = (yield)
        if row == None: break
        rich_data.append("Rich" if row.income > 100000 else "Poor")
    yield rich_data

第一个产量(表达式)只是将各个行添加到riches. 它做它的事情,在这里建立一个结果数组。在while循环之后,第二个yield(语句)用于将结果数据实际提供给调用者。

回到调用者循环,它可能看起来像这样:

richConsumer = riches()
richConsumer.next()  # advance to first yield
for row in rows(data):
    richConsumer.send(row)
    # other consumers.send(row) here
richConsumer.send(None)  # make consumer exit its inner loop
data.rich = richConsumer.next() # collect result data

我还没有测试过那个代码,但这就是我的想法。它没有基于向量的函数的简洁紧凑的语法。但它使主循环非常简单,并将所有处理封装在单独的消费者中。其他消费者可以很好地堆叠在一起。并且可以通过将生成器管理代码推到对象边界之后来进一步完善 API。高温高压

于 2010-01-07T22:19:15.737 回答