Library / SDK
yoshoku/rumale avatar
yoshoku/rumale

Rumale: a scikit-learn-style machine learning library for Ruby

Rumale is a machine learning library in Ruby

918 stars34 forksRubyBSD-3-Clause

At a glance

What is it?
Rumale brings estimators, cross-validation and dataset loading into plain Ruby with an API modelled on scikit-learn. It is a reasonable fit for Ruby codebases that need classical models in-process, and a poor fit for anyone expecting deep learning or GPU acceleration.
Who is it for?
Adopt Rumale if your application is already Ruby and you need classical estimators such as LinearModel::SVC, Ensemble::RandomForestClassifier or ModelSelection::CrossValidation without leaving the process. Do not adopt it if your work depends on deep learning, GPU training, or an ecosystem of pretrained models, since nothing in the repository material points in that direction.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap Rumale fills in a Ruby application

Most machine learning tooling assumes Python. If your service is Rails, Sinatra or a plain Ruby worker, the usual options are to shell out to a Python process, run a separate model server, or maintain a second language in the repository. Rumale takes the third path and removes the boundary: it is a Ruby gem, installed with gem install rumale or a single Gemfile line, and the estimators run in the same process as the rest of your code. The README describes it as providing algorithms "with interfaces similar to Scikit-Learn in Python", and that is the design intent rather than a marketing line. Objects expose fit, transform, predict and score, so a developer who knows scikit-learn can read a Rumale script without a guide.

The audience is narrow but real. It is Ruby teams doing tabular work: classification, regression, clustering and dimensionality reduction on feature matrices that fit in memory. It is not aimed at people training language models, and nothing in the material suggests it tries to be. The dataset loaders, the evaluation measures and the model selection classes matter as much as the algorithms here, because they are what let a Ruby project keep an experiment loop inside one language instead of exporting CSVs to a notebook.

What the estimator catalogue actually covers

The README lists a broad set of classical algorithms: Support Vector Machine, Logistic Regression, Ridge and Lasso, Multi-layer Perceptron, Naive Bayes, Decision Tree, Gradient Tree Boosting, Random Forest, K-Means, Gaussian Mixture Model, DBSCAN, Spectral Clustering, Multidimensional Scaling, t-SNE, Fisher Discriminant Analysis, Neighbourhood Component Analysis, Principal Component Analysis and Non-negative Matrix Factorization, followed by "and many other algorithms".

That trailing phrase is doing work, and it is the first place to be careful. The README's list is a summary, not a manifest. The authoritative inventory is the API documentation at yoshoku.github.io/rumale/doc/, and the namespace structure visible in the examples gives a sense of how it is organised: LinearModel::SVC, LinearModel::LogisticRegression, KernelApproximation::RBF, Ensemble::RandomForestClassifier, ModelSelection::StratifiedKFold, ModelSelection::CrossValidation, EvaluationMeasure::Accuracy, Dataset.load_libsvm_file. Estimators, kernels, splitters, evaluators and datasets are separate namespaces rather than one flat module, which is what makes the cross-validation example short.

The spread is wide for a single-language library, but the depth per algorithm is not documented in the material supplied here. There is no hyperparameter table, no statement about which solvers back which estimator, and no note on convergence criteria. If you need a specific variant, for example a particular SVM formulation or a specific tree-splitting rule, check the API reference before assuming it exists.

The Numo::NArray Alternative dependency and what changed in v2.0.0

Rumale does not carry its own numerical array implementation. It depends on typed arrays, and since v2.0.0 that dependency is Numo::NArray Alternative rather than Numo::NArray. The README flags this as a note, which understates it: it is a breaking dependency change for anyone whose code touches the array layer directly, and it is the reason the 2.x line is not a drop-in for 1.x.

The practical consequence is that matrix and vector products are the performance floor for everything built on top. Rumale itself does not ship a BLAS binding. You install one separately: gem install numo-linalg-alt, then require 'numo/linalg' before require 'rumale' in your script. The README states that this allows matrix and vector product of Numo::NArray Alternative to use OpenBLAS libraries, and that algorithms computing such products frequently "can be expected to be accelerated". That phrasing is deliberate on the maintainer's part and worth preserving: it is an expectation, not a measured guarantee, and no benchmark numbers appear in the material.

The ordering of the two require statements is not cosmetic. Loading Rumale before the linear algebra backend means the acceleration path is not in place. This is the kind of detail that produces a silent slow path rather than an error, so it belongs at the top of any script you write.

Parallelism is opt-in and depends on a third gem

Several estimators support parallel processing, but the mechanism is external. Rumale uses the Parallel gem, so you install it with gem install parallel and require 'parallel' before require 'rumale'. Estimators that support it expose an n_jobs parameter, and passing -1 uses all processors. The README's example is Rumale::Ensemble::RandomForestClassifier.new(n_jobs: -1, random_seed: 1).

Two constraints follow. First, the README says "several estimators", not all, so n_jobs is not a universal parameter and you should not assume a given estimator accepts it. Second, because the parallelism comes from the Parallel gem rather than from threads inside Rumale, the behaviour of n_jobs is bound to how that gem forks or threads work. That matters in a Rails process or a container with a CPU quota, where "all processors" may mean something different from what you expect.

Note also that random_seed appears alongside n_jobs in the example. Reproducibility is a first-class parameter in the API, and several constructors in the README examples take it: KernelApproximation::RBF takes random_seed: 1, and StratifiedKFold takes shuffle: true, random_seed: 1. If you are comparing runs, set it.

Getting a model trained and reloaded: the two-script pattern

The README's first example is a complete train and test cycle. You download the pendigits dataset in LIBSVM format with wget from the LIBSVM Data site, yielding two files, pendigits and pendigits.t. Training loads the data with samples, labels = Rumale::Dataset.load_libsvm_file('pendigits'), maps it into an RBF kernel feature space with KernelApproximation::RBF.new(gamma: 0.0001, n_components: 1024, random_seed: 1), then fits LinearModel::SVC.new(reg_param: 0.0001) on the transformed matrix.

Persistence uses Ruby's Marshal, not a portable format: File.open('transformer.dat', 'wb') { |f| f.write(Marshal.dump(transformer)) } and the same for the classifier. The test script reverses it with Marshal.load(File.binread('transformer.dat')), calls transform (not fit_transform) on the test samples, and reports accuracy either through classifier.score or through EvaluationMeasure::Accuracy. The README gives the result as 98.5% on pendigits and 95.5% mean accuracy for the five-fold cross-validation example with LogisticRegression.

Those numbers describe that dataset and that configuration. They are not a claim about Rumale's general accuracy, and the material contains no comparison against another implementation on the same task. Treat them as evidence that the example runs, nothing more. The Marshal choice is also a real constraint: the dumped files are Ruby-specific and carry version sensitivity, so a model trained on one Rumale version is not a durable artifact the way an ONNX or PMML file would be.

Where Rumale is the wrong tool

The clearest limitation is scope. There is no neural network framework here in the modern sense. Multi-layer Perceptron is listed among the algorithms, and Rumale::Torch is mentioned as a related project that provides learning and inference for networks defined in torch.rb with a Rumale interface, but that is a separate gem and a separate dependency chain. If your problem needs convolutional or transformer architectures, Rumale is not the layer you want, and the README does not pretend otherwise.

A second limitation is the data interface. Rumale::Dataset.load_libsvm_file reads LIBSVM format, which is a sparse text format suited to the datasets the library targets. There is no mention of Parquet, Arrow, database adapters or streaming. Everything is in-memory typed arrays. For a feature matrix that does not fit comfortably in RAM, the design works against you.

A third is operational. Model artifacts are Marshal dumps, so serving a model means running Ruby. There is no mention of a serialisation format other languages can read. If your inference path is Go, Java or a Python service, Rumale's output does not cross that boundary, and the cost of the Ruby dependency lands on your serving tier rather than your training tier.

Finally, the ecosystem is thin by construction. Rumale::SVM wraps LIBSVM and LIBLINEAR, and Rumale::Torch wraps torch.rb. Those are the related projects the README names. A library that delegates its SVM and neural network work to companion gems has a smaller core than its algorithm list suggests.

Rumale against shelling out to scikit-learn

The realistic alternative for a Ruby team is not another Ruby library. It is a Python service or subprocess running scikit-learn. The difference is architectural rather than algorithmic. Scikit-learn gives you a far larger estimator set, a mature ecosystem of preprocessing and pipeline tooling, and a serialisation path through joblib or pickle that at least has broad tooling around it. What it does not give you is a single process. You add a Python runtime to your deployment, a cross-language boundary, and either an HTTP hop or a subprocess spawn per prediction.

Rumale inverts that trade. You keep one language and one process, and you accept a smaller catalogue and Ruby-only artifacts. For a batch job that scores a table once a night, the Python route is usually cheaper in engineering time. For a Rails endpoint that needs a decision tree or a logistic regression inline, the subprocess cost and the operational surface of a second runtime are real, and Rumale removes both.

A fair reading of the material: Rumale is not competing with scikit-learn on breadth. It is competing on the cost of not leaving Ruby. If that cost is zero for you, Rumale has no advantage. If it is high, the narrower algorithm list is the price.

Licence, maintenance and what to check before adopting

Rumale is released under the BSD-3-Clause License, stated in the README and in the badge, with the licence text at LICENSE.txt in the repository. That is a permissive licence, which generally means you can use the gem in closed-source and commercial software provided you retain the copyright notice and licence text, and it does not carry the copyleft obligations of a GPL-family licence. It also means the licence grants no patent rights, unlike Apache-2.0. That is a general property of BSD-3-Clause, not legal advice; if patent exposure matters to your organisation, take it to counsel rather than to a README.

Maintenance looks active. The repository is not archived, the last push is dated 2026-09-05, and the releases run v2.0.2 in November 2025, v2.1.0 in February 2026 and v2.2.0 in July 2026. That is a steady cadence across roughly eight months. The material does not state a support policy, a Ruby version requirement, or a deprecation policy, so those are the things to establish yourself before you depend on it.

The upgrade cost is concentrated in the 2.0 boundary. The switch from Numo::NArray to Numo::NArray Alternative is a dependency-level change, and any code that constructs or manipulates the underlying arrays directly will need attention. Within the 2.x line the API surface shown in the README looks stable, but the README examples are not a changelog and the material supplied here contains no release notes.

What to verify first, concretely: confirm the gem's required Ruby version from the gemspec or the RubyGems page, since it is not in the README; confirm that every estimator you plan to use appears in the API documentation rather than only in the summary list; and check whether the estimator you need accepts n_jobs, because the README says only that several do. Then run the pendigits example end to end on your own machine, including the require 'numo/linalg' line before require 'rumale', so you find out whether the OpenBLAS path is actually active in your environment before you build on top of it.

Editorial conclusion

Adopt Rumale if your application is already Ruby and you need classical estimators such as LinearModel::SVC, Ensemble::RandomForestClassifier or ModelSelection::CrossValidation without leaving the process. Do not adopt it if your work depends on deep learning, GPU training, or an ecosystem of pretrained models, since nothing in the repository material points in that direction. Before committing, verify two things yourself: that your Ruby version satisfies the gem's requirement, and that the estimators you actually need are present in the current API documentation rather than only in the README's summary list. Then run one real dataset through Rumale::Dataset.load_libsvm_file and a cross-validation report on your own machine, because the README's accuracy figures come from the pendigits dataset and say nothing about your data.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. README
  4. Releases
  5. yoshoku/rumale on GitHub
Community notes

Community notes