Fun story, about 18 months ago I was consulting for a telco. One of my tasks was to run a segmentation model on their subscriber base. They wanted me to use SAS in their cluster, but because I had 'brought my infra/laptop', I told them that I could do it with Python instead. I got the gist of it working on Pandas, but it was 'slow'. So they asked me if I was going to run it on a sample, but I said I'll port it to Spark in the evening.
The following morning I presented them with results, and the porting to Spark took about 2 hours (I hadn't used SparkML before), and the thing took an hour to run on the whole population.
Pandas does not also defer computations, which means computing Boolean functions that include the same data multiple times must make multiple passes over said data. Absurd.
Disclaimer: have never used numpy, have used python fairly extensively.
for x in np.nditer(a, op_flags = ['readwrite']):
x[...] = cos(sqrt(sin(pow(x, 2))))
That's some knarly syntax though. I've never seen that ellipsis operator?Edit: just read about `Ellipsis`. I'm a fan, even if it's sort of nonstandard across libraries. Those readwrite flags are a travesty though, but at least you can paper over it with a helper function.
Something like:
def np_apply(a, f):
for x in np.nditer(a, op_flags = ['readwrite']):
x[...] = f(x)
np_apply(x, lambda x: return cos(sqrt(sin(pow(x, 2))))))
or def np_apply(a, *argv):
for x in np.nditer(a, op_flags = ['readwrite']):
for f in argv:
x = f(x)
x[...] = x
np_apply(lambda x: return pow(x, 2), sin, sqrt, cos)
Edit3: There's a way to turn this into "pythonic" list comprehension code, but it would probably only make it look prettier rather than more performant.Either way see https://news.ycombinator.com/item?id=22786958 where I figured out the syntax to do it in place, which shouldn't result in any allocations at all and should solve both your concerns.
1. Memory allocation isn't free 2. Doing multiple loops over the buffer (once per operation) is going to be slower than doing all the operations at once, both because of caching and the opportunity to do the operations on a register and write at the end (though who knows if the python interpreter will do that).
Now I have some more reading to do. Thanks.
It is an ongoing effort to built an intermediary representation that numerical library could share to produce an optimized instructions tree.
1. Without CTEs SQL isn't that expressive and with CTEs queries can be hard to understand. Logical query plans on the other hand are rather easy to understand and can express more queries than SQL can.
2. SQL is hard to modify programmatically. To most software, SQL is simply a string without any inherent meaning. A logical query plan on the hand is a tree structure that can be introspected and modified.
That's basically the same thing you want, except that you want it implemented on dataframes while I want it implemented for database systems.
Eigen does this via expression templates; it essentially optimises the computation graph at compile time.
That's wrong too. The right query execution plan can depend heavily on the sizes and statistical distributions of the operands. Eigen doesn't have enough information at compile time to make good decisions in all cases. This kind of computation really calls for a JIT.
The right way to design a data analysis DSL is to do it the way Python's dask does it: build an operation graph and execute it as the last step. The trouble is that Dask doesn't get it right either because, as part of its graph formation, it computes sizes of operands, and computing operand sizes can involve huge amounts of computation, and so dask, in effect, is also an "immediate mode" system.
What I really want to see is something lazy that can do sane query planning and that can work within limited system resources. Maybe one day I'll open source the work I've done in this space. Query languages are infinitely nicer for analytics than data processing libraries.