[HN Gopher] Romeo and Julia, Where Romeo Is Basic Statistics
___________________________________________________________________
Romeo and Julia, Where Romeo Is Basic Statistics
Author : xgdgsc
Score : 102 points
Date : 2024-03-14 07:39 UTC (1 days ago)
(HTM) web link (b-lukaszuk.github.io)
(TXT) w3m dump (b-lukaszuk.github.io)
| naniwaduni wrote:
| With a title like that, one might've expected a case study in how
| the two aren't suited for one another, or something of the
| sort...
| mmahemoff wrote:
| A Bayesian tragedy
| perihelions wrote:
| Shakespeare, Marlowe, et al.: _" Retrospective analysis of
| false positives in medical diagnosis of death"_
| erikerikson wrote:
| Frequently
| aredox wrote:
| They are suited for each other, but their families are at war
| with each other
| dvfjsdhgfv wrote:
| It basically depends if you view the story as an example of
| strong love or as a great drama that had to end badly.
| a1o wrote:
| This title is great, kudos for the creativity.
|
| > So I guess it's gonna be about a programming language named
| Julia and its usage for basic statistics.
|
| This writing is weird, you are the author right?
| Zhyl wrote:
| It's not unheard of for programming books to affect a wacky
| style. See:
|
| http://poignant.guide/book/chapter-2.html
|
| https://learnyouahaskell.com/introduction
| clircle wrote:
| Considering that the book ends by saying that the reader should
| validate Julia code by comparing it against R, i think i will
| continue to use R.
| bb1234 wrote:
| That is a good practice for any statistical software you are
| using. You should validate your R code with Python or Julia.
| Fomite wrote:
| Agreed. Whenever I'm using new statistical software, I
| validate it against one I know.
| affinepplan wrote:
| I validate my C++ code by comparing against a Python
| implementation
|
| this is just a normal sanity check and is not a strike against
| Julia (or R)
| jakobnissen wrote:
| Isn't it always a good idea to test your implementations
| against a known correct implementation? Like, if I were
| testing, say, a SHA implementation, I would also test against
| the results from an independent implementation. How is this an
| issue with Julia the language?
| lolinder wrote:
| The way you frame it makes it sound like the author was saying
| Julia is a less trustworthy language, which isn't what they're
| saying at all. Here's the quote in context:
|
| > Still, if you are new to (Julia) programming and statistics
| then most likely you should calibrate your tools first. Before
| you run some statistical analysis you may want to try it out on
| an example from a textbook written by an expert (not me though)
| and see if you get the same (or at least comparable) result on
| your own. Although this is a sound approach, I suspect you are
| more prone to visit some statistical blog or internet forum and
| go with the examples that are contained there. One such option
| is rseek.org, i.e. a search engine for the R programming
| language.
|
| > ... Once I got both outputs that are similar enough I can be
| fairly sure I did right. Otherwise I should investigate where
| the differences come from and possibly make some necessary
| adjustments.
|
| It doesn't say to compare it against R, it says that if you are
| new to programming and statistics you should check your work
| against known-good answers or against a second implementation
| before rushing ahead, and it gives R as an example of a place
| to find code that you can use to check your work.
|
| This isn't advice about one language being better, it's the
| usual advice to solve the same problem in two different ways to
| make sure you got it right!
| tastyminerals2 wrote:
| well, after https://yuri.is/not-julia/, the above is a very
| valid statement.
| bachmeier wrote:
| An alternative interpretation of the comment you're
| responding to is that you can do the same things in R, so no
| reason to switch.
| waveBidder wrote:
| just because someone programmed something in R successfuly
| one time to compare against doesn't suddenly make it a
| better language.
| ngcc_hk wrote:
| I suspect what is being said is to compare existing stat
| textbook but more likely existing stat result of a web
| site using r. Not to run r but run these and compare the
| result.
|
| I did the same to r using ibm spss. Not that I trust that
| more. Just to make sure when newly program you have used
| the right parameters. If they compare, you finish
| learning and switch over. A cautious approach when your
| job is at stake.
| bachmeier wrote:
| The entire point of my comment was that the initial
| commenter wasn't necessarily saying R is a better
| language. Somehow you've interpreted my comment as "R is
| a better language" which is quite far from what it says.
| fluidcruft wrote:
| "I suppose SAS is too expensive, so R will have to do"?
| empyrrhicist wrote:
| Is anyone aware of a YouTube or tutorial series that goes deep
| into the graphics stacks for Julia? I can make some plots, but I
| feel like I'm missing the deeper understanding of what's going on
| that I have with R base graphics.
| krastanov wrote:
| The presentations and workshops about Makie.jl from the last
| few JuliaCons are pretty good. All recordings from JuliaCon are
| available at the official Julia youtube channel.
| nextos wrote:
| For simple 2D graphics, Gadfly.jl is pretty good and its
| backend is also quite elegant. See [1,2].
|
| [1] https://gadflyjl.org/stable/dev/pipeline
|
| [2] https://giovineitalia.github.io/Compose.jl
| richrichie wrote:
| I used Julia quite a bit, even did a couple of professional
| projects. I quite like the all native code autodiff + ML set up.
|
| Since the LLM breakout on Huggingface, I am back in Python world.
| stared wrote:
| I am curious: What is Julia's current niche?
|
| I mean, I tried it a few times a decade ago, but the environment
| was not mature, and performance improvements were not in the
| places I needed. Though, I guess, things moved from there.
|
| Python has the richest environment for data science. For
| statistics, there are some tools in R, such as the stunning
| ggplot2.
|
| For numerics-heavy arrays, we have PyTorch.
|
| For custom low-level numerics, Rust rocks.
| the__alchemist wrote:
| ODE solving? Best in class.
|
| I tried to use it for quick scripts and calculator-like-use,
| but the JIT compile times made it unfeasible. (Julia's math
| syntax is the best I've seen)
|
| For more complex and performance-intensive programs, I don't
| see the case for choosing it over a general languages like Rust
| and C++.
| tombert wrote:
| > For more complex and performance-intensive programs, I
| don't see the case for choosing it over a general languages
| like Rust and C++.
|
| I mean, the fact that it's getting comparable speeds to C++
| or Rust, while having full garbage collection and nice built-
| in concurrency support is a selling point to me. I'm not
| saying you _couldn 't_ write code faster in C++ or Rust, but
| I'm going to argue that Julia will often be just as fast or
| faster from "default implement".
| CyberDildonics wrote:
| The garbage collection will cause hiccups and hangs. It
| isn't faster if you are leaning on garbage collection. Just
| like any other garbage collected language, you want to
| avoid the garbage collection.
| tombert wrote:
| Before I say anything, I think your username is pretty
| funny. Props for snagging that one.
|
| > It isn't faster if you are leaning on garbage
| collection. Just like any other garbage collected
| language, you want to avoid the garbage collection.
|
| I agree in theory but not in practice. Absolutely, if you
| are good at properly freeing memory, and knowing _when_
| to free memory, and how much to free and all that fun
| stuff, you can definitely get much better performance
| than a GC, with fewer (or zero) pauses and better
| throughput.
|
| However, I don't think I agree that that is the average
| case. A lot of people will simply malloc and free at the
| beginning and ending of the function, or worse they will
| do things incorrectly and so the data won't actually
| free, or it frees before it's completed. A GC does incur
| some overhead, but they can also be extremely optimized
| and and have the advantage of doing things basically
| correctly, or at least safely. If you through multiple
| threads into the mix, then the problems get much harder.
|
| Julia's doesn't do this, but GC in languages like Go also
| basically _don 't_ cause hiccups or hangs, at least not
| long ones. The pause times are sub-millisecond [1], and
| it's pretty impressive. Even Java, the language that
| initially gave GC's a bad name, has the Shenandoah GC in
| some builds of OpenJDK which also gets sub-millisecond
| pauses [2].
|
| Personally, I tend to believe that an application that
| stops working is generally "slower" than one that keeps
| working. A lot of the time savings you get from avoiding
| a GC will be eliminated if your program crashes and
| restarts.
|
| (That said, I will acknowledge that Rust probably makes
| this much better; I haven't done anything "real" with
| Rust so I cannot comment on it.)
|
| What I was trying to say was that Julia, at least in
| benchmarks, does get speeds getting close to something
| like C++, even with GC enabled, and it will certainly run
| circles around something like Python. If you want
| something that gets around at least 80+% of the speed of
| C++, while also giving all the prettiness and easiness of
| Python, I think Julia is a very good choice, and I would
| happily choose it over something like Go.
|
| [1] https://groups.google.com/g/golang-dev/c/Ab1sFeoZg_8
|
| [2]
| https://wiki.openjdk.org/display/shenandoah/Main#Main-
| Perfor...
| CyberDildonics wrote:
| _A lot of people will simply malloc and free at the
| beginning and ending of the function, or worse they will
| do things incorrectly and so the data won 't actually
| free, or it frees before it's completed_
|
| I don't think programming mistakes in other languages
| make a point when talking about garbage collection
| performance.
|
| _but they can also be extremely optimized_
|
| Every language I've ever seen with garbage collection has
| gone through decades of "now the garbage collection is
| better" or "just wait until the next version, garbage
| collection will be better". I've seen it in java, D,
| julia and every scripting language. It's always a thorn
| people have to work around when talking about performance
| interactivity. Julia is right in the middle of this
| common problem and that is fine for what it is because it
| isn't a typical systems language and avoiding the gc is
| not difficult, but to pretend that it is the same as C++
| is just not true.
|
| _A lot of the time savings you get from avoiding a GC
| will be eliminated if your program crashes and restarts._
|
| This is besides the point of performance and no longer
| talking about reality, it's just FUD from a "what if"
| future.
|
| _Julia, at least in benchmarks, does get speeds getting
| close to something like C++, even with GC enabled_
|
| Right, but you get it by avoiding allocation and avoiding
| the garbage collector the same way avoiding allocation in
| C++ is important, but in julia it won't be woven in to
| the performance, it will cause big pauses.
| tombert wrote:
| > Every language I've ever seen with garbage collection
| has gone through decades of "now the garbage collection
| is better" or "just wait until the next version, garbage
| collection will be better".
|
| Ok but the Go example I linked is already in production,
| _right now_ , you can use it. This isn't a "it will get
| better in two releases" situation, Go's GC as of today
| has pause times that are sub-millisecond. The Java
| Shenandoah example I linked is still mostly in beta, but
| it's also something you can use right now, though
| admittedly it'll probably be awhile before it's in a
| mainline release.
|
| > This is besides the point of performance and no longer
| talking about reality, it's just FUD from a "what if"
| future.
|
| It's not "just FUD", there are dozens of reported
| security issues that have happened because of bad manual
| memory management problems. Off the top of my head,
| Heartbleed was a famous case.
|
| This isn't me badmouthing anyone; manual memory
| management is hard to get right, even for very smart
| people.
|
| > Right, but you get it by avoiding allocation and
| avoiding the garbage collector the same way avoiding
| allocation in C++ is important, but in julia it won't be
| woven in to the performance, it will cause big pauses.
|
| Fair enough, I did look at the code for the official
| benchmarks (https://github.com/JuliaLang/Microbenchmarks/
| blob/master/per...) and outside of the integer parsing
| code it does indeed seem to avoid dynamic allocations so
| I will concede that the benchmarks might be a bit more
| skewed compared to real-world code.
|
| I still get a hunch that if you compared it allocation-
| heavy Julia to malloc+free-heavy C++ the differences
| wouldn't really be that far off, but that's just a hunch
| and I don't have data to back that up; might be a fun
| test to write though, so maybe I'll try that this
| weekend.
|
| -----
|
| Sort of tangential, but I also do think that there's
| value in having decent concurrency constructs built into
| the language. With C++, if you stick to built-ins you are
| basically stuck with mutexes and despite what people like
| to pretend, getting correct code with mutexes is really
| really hard to get right, and very easy to screw up in a
| non-obvious way. If you allow yourself to use libraries,
| then you have stuff like ZeroMQ and OpenMP and stuff, so
| it's really not that dire realistically. However, I think
| there's value in having nice, easy to use concurrency
| constructs in the language other than mutexes, and I do
| wonder if as a result of that it encourages people to
| utilize multiple threads more frequently, because they
| don't have to worry about weird deadlock situations as
| much.
|
| Again, I believe Rust actually does address this because
| of the single-owner-enforced-at-compile-time stuff, but I
| haven't used it enough to really draw a conclusion on it.
| CyberDildonics wrote:
| _Ok but the Go example_
|
| This was a thread about julia and garbage collection, you
| keep talking about unrelated things and trying to go off
| in all sorts of other directions.
|
| _manual memory management is hard to get right, even for
| very smart people._
|
| This is very different in modern C++, I basically never
| have memory problems since the actual allocation is
| minimal and inside value types.
|
| _if you compared it allocation-heavy Julia to
| malloc+free-heavy C++ the differences wouldn 't really be
| that far off_
|
| The point is that if you care about performance you don't
| do either of these. If you try this you will see that
| they are both much slower than they need to be, but julia
| will pause and hiccup because of the gc.
|
| _With C++, if you stick to built-ins you are basically
| stuck with mutexes_
|
| This is a bizarre and unrelated tangent, but it's so
| wrong I figured I would say something. Not only does the
| standard library have great primitives, but there are
| great libraries out there for lock free queues, lock free
| hash maps and openmp for fork join parallelism. I don't
| think anyone has concurrency nailed down but julia is not
| any better.
| tombert wrote:
| > This was a thread about julia and garbage collection,
| you keep talking about unrelated things and trying to go
| off in all sorts of other directions.
|
| Yes, but I was referring specifically to your statement
| "Just like any other garbage collected language, you want
| to avoid the garbage collection." I took issue with that
| statement. I think you know that and you're pretending to
| not.
|
| > This is very different in modern C++, I basically never
| have memory problems since the actual allocation is
| minimal and inside value types.
|
| Fair, maybe my C++ is out of date.
|
| > The point is that if you care about performance you
| don't do either of these. If you try this you will see
| that they are both much slower than they need to be, but
| julia will pause and hiccup because of the gc.
|
| You keep asserting different, slightly contrary things,
| and are restating things that I've already conceded to.
| The statement "if you really care about performance" is
| doing a lot of work; most realistic code isn't hyper
| optimized to remove all allocations and the like. Most
| code is written by mediocre engineers. Julia gives very
| good speeds, comparable to C++, in those situations.
|
| If you're doing high frequency trading or something then
| sure, maybe you're writing this hyper optimized code. In
| my experience that's not typical, and the initial point I
| argued that you took issue with for reasons I have to
| admit I still don't understand is this: Julia _can_ be
| used for general purpose stuff in place of C++ and Rust,
| and you 'll get decent performance while also having full
| garbage collection.
|
| > This is a bizarre and unrelated tangent, but it's so
| wrong I figured I would say something.
|
| In the thing you're responding to I said it was a tangent
| so acting like I'm changing the subject unprompted is
| weird. I also mentioned OpenMP and mentioned that this
| wasn't a problem realistically, so I don't see why you
| felt the need to restate it.
|
| Are these the concurrency primitives you're talking
| about? https://en.cppreference.com/w/cpp/thread
|
| Sure, those are fine, but I dispute that they're as
| generally-useful as CSP style message passing. Moreover,
| Julia has parallel for loops out of the box
| (https://julialang.org/blog/2019/07/multithreading/), in
| addition to having built in support for not only parallel
| computing, but also distributed computing across multiple
| nodes
| (https://docs.julialang.org/en/v1/manual/distributed-
| computin...).
|
| Now I again will restate that I am aware that C++ has
| libraries to do this, you don't need to pretend that I
| didn't say that. You can get nice distributed computing
| support with ZeroMQ or Nanomsg and probably a dozen other
| libraries.
|
| Honestly though, this entire topic is frustrating to me
| because you're getting to the point of outright
| dishonesty.
| CyberDildonics wrote:
| I don't even know what you are trying to say. All I said
| was that if you lean on garbage collection, julia is not
| going to be the same as C++ because it will pause and
| hiccup. Everything else you hallucinated into half a
| dozen splintered arguments.
|
| _Julia has parallel for loops out of the box_
|
| Every major C++ compiler has openmp built in. Julia is
| great but I think you should study up on C++ if you want
| to compare them.
| samatman wrote:
| Slow is slow and fast is fast. For some reason you
| consider it cheating to not ref-count everything in C++
| to get speed, but writing idiomatic Julia code which does
| minimal allocation is somehow out of bounds. You'd
| decided what you want to believe and are working backward
| from there.
| samatman wrote:
| > _the JIT compile times made it unfeasible_
|
| Worth trying again unless that was in the last 18 months.
| Precompilation has gotten dramatically faster, like 50x
| improvement in load times faster. So has startup time in
| general, `time julia -e "return 5"` gave 161 milliseconds of
| user time on my computer. I don't actually use Julia for
| simple script munging, simply because I'm used to Python in
| that role and it works fine, but it's suitable for it.
|
| Calculator-like use? Julia, all the way. Of course I keep the
| REPL open at all times. Gotta use tools the way they're
| intended, y'know?
| the__alchemist wrote:
| I'll give it a shot! I've been tracking a steady stream of
| published improvements this area over the years (decade?)
|
| I think the most striking moment I had was when I realized
| through experiment that rust, which has a notoriously slow
| compiler, was faster to compile and run a small plotting
| program than Julia. That was ~5 years ago though!
| sampo wrote:
| > What is Julia's current niche?
|
| Python, but for engineers and scientists. Syntax is friendlier
| for doing mathematics, barrier to entry to first calculation
| script is lower a = [1 2 3] b = [4 5
| 6] a + b
|
| vs import numpy as np a =
| np.array([1, 2, 3]) b = np.array([4, 5, 6]) a +
| b
|
| Also you can learn Julia step by step, and improve your code to
| run faster. Whereas in Python, the eventual road to fast code
| is to write the library in C and call it from Python.
|
| Python is for software people. Matlab, Julia and R are for
| people who only write code because they want answers.
| sampo wrote:
| > Python is for software people. Matlab, Julia and R are for
| people who only write code because they want answers.
|
| Or, Julia can be for both.
|
| Julia lets you start from scientific calculations scripts and
| grow your code to a larger software package. Same as Python
| grew popular 20 years ago because it let you grow your small
| sysadmin scripts to larger software.
|
| Matlab and R are too limited in their "real programming
| language" constructs, and it gets painful when your codebase
| grows larger. Julia has all "real programming language"
| constructs a software engineer would need.
| the__alchemist wrote:
| This syntax is my favorite feature of Julia's. I wish I could
| get something like this in python or rust, without a macro
| mess.
| staplung wrote:
| Scientific computing. Of the languages you cited, none (other
| than Julia) have dynamic dispatch, a feature that turns out to
| be unexpectedly powerful and allows lots of packages to hang
| together much more effectively than you would expect.
|
| Also, Rust specifically doesn't have built-in rational numbers,
| complex numbers, bigints or proper matrixes. There are lots of
| crates that implement them but that's precisely what prevents a
| cohesive ecosystem from developing.
| abdullahkhalids wrote:
| I don't know anything about this, but the wiki article [1]
| says that Python, Rust and Julia all have Dynamic dispatch.
| However, it seems like Python has single dispatch, but Julia
| has multiple dispatch. Is that what you meant?
|
| [1] https://en.wikipedia.org/wiki/Dynamic_dispatch
| tombert wrote:
| My dad recently had me help him port some Matlab code to a web
| service. He eventually ported it over to Octave so I could run
| it, since I don't have any kind of license for Matlab. I couldn't
| find any good web server implementations for Octave, so I was
| looking for free "matlab-like" languages that might, and I found
| Julia. The code wasn't stats-heavy, but it was heavily number-
| crunchy, making heavy use of matrices and tensors and stuff that
| admittedly still kind of goes over my head.
|
| I've not done a lot with "numeric" programming, but I was able to
| pick up Julia really quickly, and I was able to do a more-or-less
| straight port of my dad's code to Julia. What I was _extremely_
| impressed with was how much faster it went out of the box; for
| some of the more crunchy bits, running on the same hardware, the
| Julia code ran quite literally 150x faster, and this was without
| any Julia-specific optimizations other than adding types to the
| function arguments.
|
| Since then I've learned a lot more about Julia, to a point where
| it has sort of become my go-to language for starting new projects
| (assuming I don't need to use a specific JVM library or
| something). It's basically guaranteed to give me fast code out of
| the box, it has most of the concurrency constructs that I
| actually care about, it has a better-than-average macro system
| (at least compared to something like C++), and personally I just
| think that the language looks pretty once you get into some more
| of the details. I wish it were a more popular language, because
| the only thing that has held me back from using it more has been
| the lack of library support. Most of the libraries are fine, but
| for example I had a lot of trouble getting the Bcrypt library
| working, which is something I wouldn't really have a problem with
| on a JVM language or C++ or something.
|
| Of course, this is (hopefully) a temporary problem, as the
| language slowly grows in popularity the library support should
| just get better.
|
| ETA:
|
| I haven't done proper benchmarks on this so this is purely
| speculation, but that said I think that the biggest boost comes
| from the fact that Julia properly optimizes loops. My dad is a
| smart dude, but not being a software engineer in 2024, didn't
| really know that using loop constructs in most higher-level
| language is considered a code smell. I don't now about Octave,
| but I know in Python it's generally considered way better to try
| and avoid vanilla "loops" and try and convert looping things into
| some kind of vector operation.
|
| I think the JIT part of Julia is smart enough to optimize loops
| out of the box, and so my straight port of my dad's code just
| "magically" got faster, and I was extremely impressed, but I
| suspect that if my dad had utilized a lot of the vector
| operations of Octave and/or Matlab, the results wouldn't be
| nearly as impressive. I suspect Julia would still have performed
| better (if nothing else because I was able to add type
| information), but I suspect it wouldn't be the 100+X speed
| increase that I was getting.
| affinepplan wrote:
| > and this was without any Julia-specific optimizations other
| than adding types to the function arguments.
|
| I know this wasn't the point of your post, but just noting that
| adding types to function arguments "usually" shouldn't impact
| performance at all :) when it does, that might mean there is
| some type-instability being papered over (i.e. there is a
| better fix lurking around the corner)
| tombert wrote:
| In one case adding type information into the function args,
| for a function with a loop being run like 20 million times,
| it made a pretty substantial difference; it brought
| processing down from roughly 2 minutes to roughly 10 seconds.
|
| I didn't do a control test to figure out exactly why, but I
| think it was having some issue with a parsed CSV being read
| as a matrix. I think explicitly putting that requirement into
| the function signature allowed for a lot of low-level
| optimizations to be used that it couldn't use before.
|
| I'm not 100% sure though; basically when I was getting some
| performance bottlenecks I did some preliminary searching and
| some of the results said "try adding types to your function
| signatures", and I really couldn't think of a good reason
| _not_ to add them for most of the variables, and so I did and
| it worked.
| samatman wrote:
| What grants speed to Julia code is type assertions, at
| least in the case where the assertions lead to type
| stability. The compiler balances speed (of compilation) and
| accuracy, when inferring types and deciding what methods to
| specialize. If and when it can't figure that out, adding a
| type assert give it more ability to assume the assertion is
| accurate.
|
| Concrete types in a function signature also work as
| assertions, so it's one way to force the compiler's hand
| this way. In many cases it's better to assert the
| _arguments_ , rather than the _parameters_ , to keep the
| method itself generic. The main reason to add types to a
| method is to allow multiple dispatch to pick that method of
| the function for values of the specified type.
| tombert wrote:
| That makes sense; basically giving a hint so that the
| compiler can figure out what kind of special
| optimizations are possible. I would assume that it can
| avoid extra reflection calls as well as a result?
|
| The slow function I added the types to didn't really make
| any sense to be really generic. For nearly all the
| arguments (of which there was like 20), there was only
| one type that made any sense for each. I don't think
| keeping it more generic would have bought me much, and
| adding types worked as an assertion that made things much
| faster.
|
| But yes, once I started adding types to thing, I did
| start utilizing multiple dispatch, since I've always been
| a bit fan of Clojure-style multimethods and this got me
| something more or less comparable to it.
___________________________________________________________________
(page generated 2024-03-15 23:02 UTC)