Python Is Not C
ibm.com
ibm.com
Literally any problem can be solved quickly in any language if you're willing to accept an incorrect answer.
The Manhattan (1-norm) metric is strongly equivalent to euclidean (2-norm) metric. Depending on your problem domain, that might be good enough.
Sure, it could be a reasonable choice for some problems, but I have a hard time thinking of which ones those would be, and it would definitely need some discussion about the tradeoffs.
I'm sad, though, that he didn't just try to convert the original sophisticated function to numpy. I suspect the end result would've been "the really accurate function actually performs decently!"
And really, I have no objection at all to approximations, but the lack of any acknowledgement that it even was an approximation is what bugged me.
' ignoring the fact that 1 degree difference in latitude yields a larger distance than 1 degree difference in longitude'
Anyway, I did say that I was using an approximation.
https://www.ibm.com/developerworks/community/blogs/jfp/resou...
Article not worth reading. Would have been much better as a quick tip. "Quick tip: if you need to loop through an array in Python, do it this way instead..."
I see numerous issues with the loop, for example, hash key lookups on 'Lat' and 'Long' for every iteration.
CPython, which is the standard, most common implementation, uses bytecodes (and so does Java). There's nothing preventing one from generating machine code from a Python source. Some of Python's dynamic features are mandated from the spec, and there are limits on how fast that can be. But that has nothing to do with "being an interpreted language".
[1]http://eigen.tuxfamily.org/index.php?title=Main_Page [2]https://software.intel.com/en-us/intel-mkl
Programmers shouldn't be wasting brain power deciphering cryptic variable names. Save that energy for where it counts (solving actual problems!)
I will go so far as to say all of the truly buggy software I have ever seen had the most explicit variables. To the point that it is just a sideshow. Use them if they don't get in the way. Don't if they do.
"I notice a lot of Python programmers tend to use less descriptive variable names."
In the project I work on, I found a wonderful rats nest of variable names in a function that led to an excellent bug where "N" and "n" were swapped, leading to a completely different result.
Poorly named functions/modules/variables/classes, etc are indicative of poorly thought out code.... as the other subject of this post (c vs python) also confirms.
You will see similar naming idiosyncrasies if someone writes Java in Python, or lisp in python (or Python in C, or Java in Lisp, etc.).
no excuse for names like that regardless of language.
"A variable or function name should be sufficient to understand the meaning, while remaining concise. The shorter the lifespan or scope of a variable, the shorter its name should be; conversely, the more important a variable, and the more places it is used, the more descriptive that name should be."
These names certainly conform to this standard.
Another example, if memory isn't a concern he could write a list comprehension with all the distance values, and then get the index of the smallest. This, however, has the problem that, though the list comprhension surely runs faster than the for loop, it takes more memory and then looking for the lowest value can take all the time you saved (and maybe some more).
Without prfiling in his use case, it's difficult to say what is "the best solution", but his problem comes mostly from coding Python as if it were C.
Edit: yes, I ignored the fact tha he used numpy (a good solution, giving his 300x speedup with changing the structures), because sometimes your data isn't prone to "numpy array conversion" -- for example, if you aren't programming numerical code.
How much quicker? It isn't too significant, is it? I mean, we have two O(1) operations to worry about, I suppose: lookup and appending to the list.
squares = []
for x in xrange(100):
squares.append(x*x)
in which you have an append call on every iteration is a mess because it may lead to a lot of memory operations which are really unnecesary. The LC version of it is much shorter an runs faster, because the memory allocation is handled differently: squares = [x*x for x in xrange(100)]
Append may be O(1) but in some cases it doesn't behave nicely. On large lists, you can hit spots in which it reallocates parts of the list in memory, leading to weird slowdowns. Timings from ipython on a Windows 8 64bit Python 2.7.9 machine: In [12]: def f1():
....: sq = []
....: for x in xrange(100):
....: sq.append(x*x)
....: return sq
....:
In [13]: def f2():
....: return [x*x for x in xrange(100)]
....:
In [14]: %timeit f1()
10000 loops, best of 3: 20.7 µs per loop
In [15]: %timeit f2()
100000 loops, best of 3: 11.9 µs per loopThat's a pretty good speed-up! Makes me reconsider writing some "complex" LC as for-loops.
In [1]: (x*x for x in xrange(100))
Out[1]: <generator object <genexpr> at 0x0000000003558438>
And the generator expression could be used inside a for loop in cases where de LC would be awkward or take more time (because you have to allocate memory for a billion numbers all at once, just to check those that are meet a certain requirement).In your case reaching to numpy was probably the best you could do, as it abstracts and solves many things. Using properly "vectorized" numpy is also a big plus for readability.
I just wanted to mention a few things regarding the "pure python optimization" views which could help in cases where you're not writing numerical code that won't benefit from numpy.
I think it's because a lot of the Python (and I figure, other languages too) learning resources treat the learners the same way, whether you do not know any programming or are a 20-year veteran of C/C++.
I'd love to see resources which show the ideological way of doing things in a language. Take some of the most common tasks performed in other languages, and show how they're mapped properly to constructs in Python.
In this particular instance: I'm guessing the author could have used pure Python alone to get a decent speedup, without reaching for NumPy.
(edit) The author could use my handy python quad tree if he so wishes -- https://github.com/Dav3xor/pyquadtree, and if he asks nicely, I could even add support for simple approximation of spherical coordinates.
K-d trees are even built in to SciPy, which the author probably already has installed (Scikit-Learn also has an implementation).
Would this numpy trick work if he still needed an accurate distance calculation? Kind of underwhelming to throw away the accuracy to get speed without adding it back later.
[0] http://doublemap.github.io/blog/2015/05/29/optimizing-python...
1) finding the points Pi within a certain distance d0 of a fixed point P0 in your database
2) finding the nearest point Pmin to P0, with Pmin in your database.
I will keep it for myself, but as a hint here are two steps: first: read the John Cook article about deriving the distance formula, and second: think and easy way of avoiding unneeded computation.
It took me just a minute to realize the correct way to solve the OP, so it shouldn't take you long to solve it.
I contemplated quad trees but the performance of these 2 lines of code was good enough. Why would I bother writing something more complex?
you'd be surprised by my mathematical background ;)
The results were as follows:
~ 14.2 seconds for Python 3.4.3 [1]
~ 9.0 seconds for Python 2.7.9 [1]
~ 9.0 seconds for PHP 5.6 [2]
~ 2.3 seconds for C [3]
~ 2.3 seconds for Java 8 [4]
Again, this was on my machine with out of the box settings. I have linked the test code that I wrote and perhaps there is something wrong with my Python and PHP code but to me the results were quite revealing. Also it's interesting to see that on my configuration C and Java both hit the limit of my CPU (I can't explain the score otherwise) and I can't know for sure if on a more powerful CPU Java would still be on pair with C.
[1] https://gist.github.com/anonymous/7edafa3889be967a1e1d
[2] https://gist.github.com/anonymous/56ff76849f5a312340d9
The type conversion behavior of the math.pow function is clearly documented:
Also, I am thinking if and how much speed gain could one inject by not using OOP in PHP...
math.pow() version: 11.7s
pow() version: 6.4s
** version: 5.2sI also wonder if Java has any kind of optimizations to experiment with.
I don't know anything about Java optimization.
Really cool interesting stuff!
-O2 or -O3 does some neat stuff like unrolling loops and inlining functions
--fast_math is another one I use
And let me get this straight. He can use C, but cannot use PyPy? How does that make sense? If he's able to use C, he's able to run binaries anyways, at which point he should be able to use PyPy. Unless I'm missing something?
Pypy was not an option either, details in the post now.
Not many things approach C speed, but PyPy has always seemed like pretty close
Yes, I used @jit(nopython=True). It does not compile pandas code.
More details here: http://pandas.pydata.org/pandas-docs/version/0.16.2/enhancin...
Also they recently added support for array expressions and allocation so you should upgrade if you haven't already.
> [ ... ]
> The lesson is clear: do not write Python code as you would do in C.
:)
This article changed my opinion quite a bit and highlights the power of having a real macro system: http://julialang.org/blog/2013/09/fast-numeric/
I've begun to leverage the points made in the article quite a bit. Alas, now I get stuck when writing numpy based code because it constrains my ability to express a solution in the best suited idiom.
> Devectorize expressions
Why can't a compiler/whatever do this devectorisation for us if it is faster - I see that there is a macro package for this why not do it as standard?
> Write cache-friendly codes
Well duh.
> Identify opportunities to use BLAS
Is this not what numpy does already?
I suppose my real question about Julia is. Why? Why not put the effort into optimising numpy or making fortran a little more convenient to use rather than making a whole new special snowflake language just for one set of problems.