Code with Kira

OSS Updates March and April 2024

This is a summary of the open source work I've spent my time on throughout March and April, 2024. Overall it was a really insightful couple of months for me, with lots of productive discussions and meetings happening among key contributors to Clojure's data science ecosystem and great progress toward some of our most ambitious goals.

Sponsors

This work is made possible by the generous ongoing support of my sponsors. I appreciate all of the support the community has given to my work and would like to give a special thanks to Clojurists Together and Nubank for providing me with lucrative enough grants that I can reduce my client work significantly and afford to spend more time on these projects.

If you find my work valuable, please share it with others and consider supporting it financially. There are details about how to do that on my GitHub sponsors page. On to the updates!

Grammar of graphics in Clojure

With help from Daniel Slutsky and others in the community, I started some concrete work on implementing a grammar of graphics in Clojure. I'm convinced this is the correct long-term solution for dataviz in Clojure, but it is a big project that will take time, including a lot of hammock time. It's still useful to play around with proofs of concept whilst thinking through problems, though, and in the interest of transparency I'm making all of those experiments public.

The discussions around this development are all also happening in public. There were two visual tools meetups focused on this over the last two months (link 1, link 2). And at the London Clojurians talk I just gave today I demonstrated an example of one proposed implementation of a grammar-of-graphics-like API on top of hanami implemented by Daniel.

There are more meetups planned for the coming months and work in this area for the foreseeable future will look like researching and understanding the fundamentals of the grammar of graphics in order to design a simple implementation in Clojure.

Clojure's ML and statistics tools

I spent a lot of time these last couple of months documenting and testing out Clojure's current ML tools, leading to many great conversations and one blog post that generated many more interesting discussions. The takeaway is that the tools themselves in this area are all quite mature and stable, but there are still ongoing discussions around how to best accommodate the different ways that people want to work with them. The overall goal in this area of my work is to stabilize the solutions so we can start advocating for specific ways of using them.

Below are some key takeaways from my research into all this stuff. Note none of these are my decisions to make alone, but represent my current opinions and what I will be advocating for within the community:

Foundations of Clojure's data science stack

I continue to work on guides and tutorials for the parts of Clojure's data science stack that I feel are ready for prime time, mainly tablecloth and all of the amazing underlying libraries it leverages. Every once in a while this turns up surprises, for example this month I was surprised at how column header processing is handled for nippy files specifically. I also fixed one bug in tablecloth itself, which I discovered in the process of writing a tutorial earlier in March. I have a pile of in-progress guides focusing on some more in-depth topics from developing the London Clojurians talk that I'm going to tidy up and publish in the coming months.

The overarching goal in this area is to create a unified data science stack with libraries for processing, modelling, and visualization that all interoperate seamlessly and work with tablecloth datasets, like the tidyverse in R. Part of achieving that is making sure that tablecloth is rock solid, which just takes a lot of poking and prodding.

London Clojurians talk

This talk was a big inspiration for diving deep into Clojure's data science ecosystem. I experimented with a ton of different datasets for the workshop and discovered tons of potential areas for future development. Trying to put together a polished data workflow really exposed many of the key areas I think we should be focusing on and gave me a lot of inspiration for future work. I spent a ton of time exploring all of the possible ways to demonstrate a broad sample of data science tools and learned a lot along the way.

The resources from the talk are all available in this repo and the video will be posted soon.

Summary of future work

I mentioned a few areas of focus above, below is a summary of the ongoing work as I see it. A framework for organizing this work is starting to emerge, and I've been thinking about in terms of four key areas:

Visualisation

Machine learning

Statistics

Foundations

Going forward

My overarching goal (personally) is still to write a canonical resource for working with Clojure's data science stack (the Clojure Data Cookbook), and I'm still working on finding the right balance of documenting "work-in-progress" tools and libraries vs. delaying progress until I feel they are more "ready". Until now I've let the absence of stable or ideal APIs in certain areas hinder development of this book, but I'm starting to feel very confident in my understanding of the current direction of the ecosystem, enough so that I would feel good about releasing something a little bit more formal than a tutorial or guide and recommending usages with the caveat that development is ongoing in some areas. And while it will take a while to get where we want to go, I feel like I can finally see the path to getting there. It just takes a lot of work and lot of collaboration, but with your support we'll make it happen! Thanks for reading.

Published: 2024-04-30

Tagged: clojure oss updates clojurists together open source

The Current State of ML in Clojure

I had a really enlightening talk with Daniel Slutsky this week (who is an exceptional data scientist, software engineer, and community organizer I highly recommended meeting if you haven't already) about the current state of the machine learning landscape in Clojure. This post is my attempt to distill it into a summary for the community's benefit, so more people can understand where things are at and what the active developers in this space are working on.

It's no secret I love Clojure and especially working with data in Clojure, but it's fair to say that the Clojure for data science ecosystem is not anywhere near as easy to use or understand as reasonable potential users might expect. This is the main problem I'm focusing on this year, and there is significant effort being put into refining our tools to make them more accessible to a wider audience.

There are already people doing "real" machine learning work in Clojure, though, and below is an overview of what the current state of our libraries and tools are in that area, as of April 2024.

Update 2024-04-08: It's worth mentioning that deep learning and LLM libraries have been intentionally left out of this post in order to keep it a "reasonable" length. There is enough separate work happening in that space that it warrants its own, separate overview.

Summary

There are a lot of links in this post. This table is an attempt to aggregate and summarize them. There are more details worth reading below, but in case you don't have time, this is the gist of it. To make a very long story short, current efforts are heavily focused on consolidating all of these amazing libraries into one (or at least a small number of clearly delineated ones) that is/are easy-to-use, providing a comphrehensive toolkit for doing machine learning in Clojure.

CategoryLibraryDescriptionLicense
Java ML LibrariesTribuoA comprehensive Java ML framework, preferred library for ML workflowsApache 2.0
Smile 2.xCurrently being phased out of main Clojure ML librariesLGPL
Smile 3.xAvoided due to licensingGPL
XGBoost for JVMImplements gradient boosting algorithms, can be used through TribuoApache 2.0
Clojure Wrappersfastmath 2.4.0+Clojure ML/stats library, dependency on Smile 2.xMIT
fastmath 3.xFastmath with no Smile dependencyMIT
fastmath-clusteringFastmath wrapper around Smile clustering, dependency on Smile 2.xEPL-2.0
scicloj.ml.tribuoClojure wrapper for Tribuo, likely to become the main source for ML algorithmsEPL-1.0
scicloj.ml.smileClojure wrapper for more of Smile (than fastmath), likely to be deprecated due to licensingEPL-2.0
scicloj.ml.xgboostClojure wrapper for XGBoost directlyEPL-1.0
tech.ml.datasetCore dataframe/dataset library in Clojure, incorporates some Tribuo functionalityEPL-1.0
tech.mlEarly Clojure ML library, superceded by various scicloj.ml librariesEPL-1.0
Clojure ML PipelinesmetamorphClojure function composition libraryEPL-2.0
metamorph.mlClojure library for composing ML pipelines based on metamorphEPL-2.0
Collections/Frameworksscicloj.mlCollection of Clojure ML libraries and documentation, being deprecated in favour of nojEPL-2.0
nojConsolidated Clojure data science toolkit, likely to become the main, unified entry-point for Clojure's data science stackEPL-1.0
Interoplibpython-cljPython bindings for Clojure, enabling use of Python code and libraries directly from ClojureEPL-2.0
sklearn-cljUtilizes libpython-clj for access to scikit-learn estimators and models from ClojureEPL-1.0
clojisrBridge from Clojure to R, less relevance for ML compared to Python interopEPL-2.0

In addition to all of these libraries, the post mentions the Clojurians Zulip, the main Clojure-for-data-science community discussion forum, where main contributors to the ecosystem are active daily.

Java ML Libraries

There are two (sort of four) popular Java libraries that implement many of the main algorithms and tools used in machine learning today (e.g. classification, regression, clustering, model development, etc.): Tribuo (including XGBoost, more on that in a second) and Smile. We count Smile as two libraries because Smile 2.x is LGPL-licensed, and Smile 3.x is GPL-licensed, which poses some potential conflicts for some end users. The community consensus is converging around moving away from Smile due to the GPL-relicensing issue, focusing instead on Tribuo and hand-rolled solutions.

There is also XGBoost for the JVM, mentioned above, which is an implementation of gradient boosting. XGBoost is a collection of algorithms whereas Tribuo is a more comprehensive framework (including things like data management, model evaluation, and experiment tracking). XGBoost can be used from Tribuo, so I don't exactly count it as a standalone library, although it can also be used in that way.

Clojure wrappers

There are two main "families" of libraries that wrap these Java ML libraries in Clojure.

Fastmath includes statistical as well as machine learning tools for Clojure. Fastmath 2.4.0+ depends on Smile 2, and the forthcoming fastmath 3.x will have no Smile dependency at all. The clustering functionality in fastmath 2.x that depended on smile has been moved to the fastmath-clustering library, which will have a Smile 2.x dependency going forward. There is a strong preference in the community to avoid introducing GPL-licensed libraries into the ecosystem.

Clustering functionality will mostly be provided by scicloj.ml.tribuo going forward which, as you might expect, wraps the Tribuo Java library, and is likely to become the main source of ML algorithms for the ecosystem. This is one of a few libraries in the second family of libraries that wrap the Java libraries mentioned above. Other (self-explanatory) ones include scicloj.ml.smile, which wraps more of Smile than fastmath did (does), and scicloj.ml.xgboost.

It's also worth mentioning tech.ml.dataset (the core dataframe/dataset library underlying tablecloth), which incorporates some of the functionality of tribuo, with the API centred around individual datasets. There also used to be a library called tech.ml, which implements some machine learning tools, but has been deprecated in favour of the various libraries discussed above.

The concept of orienting an API around individual datasets vs something else leads me to the next group of libraries.

Clojure ML Pipelines

Metamorph is a library that implements a function composition mechanism for composing ML pipelines. It arises from the common ML practice of repeatedly running the same set of functions with varied parameters. You might, for example, try many different test/train splits to see how that affects your results, or fit the same data using many different algorithms, or try training your model using different sets of features. This leads to an explosion of pipeline permutations, so it's useful to have machinery to encapsulate the variable components of your ML pipeline into a single function. This is where metamorph.ml comes in.

Metamorph.ml is based on this concept of meta-functions and pipelines. It is currently the central library for orchestrating ML pipelines in Clojure. The API is stable, but there are currently many ways (10+) to achieve the same outcomes. This is great for power users who have complex needs and a clear understanding of the metamorph mental model, but it can be a bit daunting for newcomers, making it more challenging to pick a clear place to start. The community is actively discussing the best approach for consolidating and/or documenting these different approaches in the interest of making Clojure's ML stack more accessible.

Collections/Frameworks

The community is well aware that it is difficult to know where to get started and several efforts have been made in an attempt to make the path more clear for people who want tools that Just Work. scicloj.ml is one such project. It's a collection of libraries (mostly the ones mentioned above) with some lightweight wrappers and efforts in creating documentation.

The community is heading toward deprecating this library, though, in favour of noj, which we are hoping to stabilize in the near future. The goal is to have a single entry-point into the Clojure data science stack, gathering all the tools one would need to work with data consolidated in one place, with seamless interoperability akin to R's tidyverse of libraries.

Interop

It wouldn't be a complete roundup of the state of ML in Clojure without a mention of libpython-clj. This is a library that provides Python bindings for Clojure, so you can call Python code directly from Clojure if necessary. sklearn-clj makes use of this bridge to provide direct access to all of the estimators and models from Python scikit-learn in Clojure, so for cases where something is truly only available in Python, we can still access it.

It's worth also briefly mentioning clojisr here, which is a similar kind of bridge from Clojure to R (and there exist libraries for Julia and Wolframite, too), but these are all less relevant for the specific area of ML, where Python is the overwhelmingly most popular current tool of choice.

More updates

These discussions all happen in the open, on the Clojurian's Zulip instance, which has become the main gathering place of the Clojure-for-data-science community. The #data-science and #noj-dev streams are the most active on these topics at the time of this writing. You can follow along with developments in the trenches over there, or follow the key libraries on github for updates (scicloj.ml.tribuo, metamorph.ml, noj). I will also post periodic updates here and all the other corners of the internet where I lurk. Thank you for reading!

Discuss this post on Hacker News or Reddit

Published: 2024-04-04

Tagged: clojure scicloj machine learning

OSS Updates January and February 2024

I was lucky enough to get funding this year from Clojurists together to work on some open source projects for the Clojure community. It's been a really fun couple of months getting more involved in the ecosystem and having the time to work on some projects that I've long thought would be valuable for the community. This post is a summary of the things I've been working on over the past two months.

Sponsors

First of all, I want to thank the sponsors that make this work possible. We're living through the worst tech job market since I started working as a software engineer, and I'm lucky to have a little bit of time and runway to work on things I find interesting thanks to the generous sponsors who find my work worthwhile.

Right now my work is primarily funded by Clojurists Together and Cognitect/Nubank. Thank you to these major sponsors, and to everyone who contributes to my continued work in the Clojure open source ecosystem.

If you find the work I do valuable, please share it with others or consider supporting it financially. I would love to be able to turn working on this kind of stuff into a sustainable career in the long term.

Clojure Tidy Tuesdays

The main thing I spent my time working on over the past couple of months was a collection of tutorials and guides for working with data in Clojure. The R for Data Science online learning community publishes toy datasets every week for "Tidy Tuesdays" with a question to answer or example article to reproduce. I've been going through them in Clojure, and it's proven a great tool for uncovering areas for future development in the Clojure data science ecosystem.

Other Work

The explorations with the Tidy Tuesday data have been revealing areas where I think we could benefit from more ergonomic ways to work with tablecloth datasets. I started two little projects each with a couple of little wrappers around existing functions to make them easier to use with tablecloth datasets. So far I'm calling them tcstats (for statistical operations on datasets) and tcutils (with miscellaneous dataset manipulation tools that aren't built-in to tablecloth directly).

I am also still working on the Clojure Data Cookbook. I nudged it forward ever so slightly these last couple of months, and I plan to finish it despite the remaining holes in Clojure's data science stack. I would love to also fill these in eventually, but the Cookbook will be a living document that can easily evolve and be updated as new tools and libraries are developed.

Lastly, one of the main missing pieces I'm discovering we really need to work on in Clojure's data science ecosystem is a robust yet flexible graphics library. There are a few great solutions that already exist, but they take different approaches to graphing that can make them a bit clumsy to work with when it comes time to build more complex visualisations. My dream is to implement a proper grammar of graphics in Clojure, giving the Clojure data ecosystem a "professional quality" graphics library, so to speak. Anyway.. there is still tons of work to do here so I'm grateful for the ongoing funding that will allow me to continue to focus a large amount of time on it for the foreseeable future.

Published: 2024-02-29

Tagged: clojure oss updates clojurists together open source

Archive