我正在考虑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进行较小的操作,并且可以直观地掌握它的工作原理。
答案 0 :(得分:2)
我对Cassandra / NumPy一无所知,但是如果你调整你的第二种方法(使用NumPy)以合理大小的块处理数据,你可能会受益于CPU和/或文件系统缓存,因此阻止任何数据循环两次导致的速度减慢,而不会放弃使用优化处理函数的好处。
答案 1 :(得分: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。对象边界。 HTH