JavaScript とブラウザで使える統計ライブラリ rStats.js を作り、MIT ライセンスで公開しました。関数の名前・既定値・結果を R に合わせてあり、すべての関数を R の出力と比べてテストしています。R の値が不正確なところでは、高精度の計算で確かめた、より正確な値を返します。
- GitHub: https://github.com/numero-uno-jpn/rStats.js
- デモ: https://numero-uno-jpn.github.io/rStats.js/demo/ (すべての関数の結果を、R が出す値と並べて確かめられます)
- npm:
npm install @numero-uno-jpn/rstats
作るのには AI を全面的に使いました。コードもテストも、書いたのはすべて AI です。AI を使ったことを隠すつもりはありません。むしろ、R のコードを使わずに書くことと、すべての関数を同じ水準でテストすることは、AI なしではできなかったと考えています。
使い方
import { pnorm, pt, setSeed, rnorm, tTest } from "@numero-uno-jpn/rstats";
pnorm(1.96); // ≈ 0.9750021049
pt(2, 10, { lowerTail: false }); // ≈ 0.03669401739 (R の pt(2, 10, lower.tail = FALSE))
setSeed(42);
rnorm(3); // [1.3709584471466685, -0.5646981713960887, 0.3631284113373392]
const r = tTest([5.1, 4.9, 6.2, 5.8, 6.0, 5.5], [4.1, 4.5, 5.0, 4.8, 4.3]);
r.pValue; // ≈ 0.003536530888
r.method; // "Welch Two Sample t-test"
引数も R にそろえてあります。必須の引数は R と同じ順番に位置で渡し、省略できる引数は、R の引数名を camelCase にしたキーを持つオブジェクトで渡します (lower.tail は lowerTail)。R のコードを知っていれば、ほぼそのまま書き換えられます。乱数も R と同じで、setSeed(42); rnorm(3) は R の set.seed(42); rnorm(3) と最後のビットまで一致します。検定の結果は素のオブジェクトなので、そのまま JSON.stringify できます。
TypeScript で書いてあり、型定義も付いています。配布は ESM だけで、依存するパッケージはありません。Node 専用の API も使っていないので、現行のブラウザ、Node.js 22 以降、Deno、Bun で動きます。tree-shaking にも対応していて、pnorm だけを使うなら gzip で 1.6 KB です。
扱える範囲は、分布と乱数、記述統計、各種の検定、分散分析、線形モデルと一般化線形モデル、混合モデル (lme4 の lmer と glmer)、生存時間解析 (Kaplan-Meier と Cox 回帰)、効果量と検出力、評価者間の一致度、線形代数、数値計算です。目標は、EZR や ReactiveStat のような統計ソフトで使われている計算をできるだけカバーすることです。医療統計と心理統計の範囲を一通り扱えるようにしたいと考えています。関数の一覧は README にあります。
作った理由
JavaScript にも統計ライブラリはいくつもあります。ただ、私が探したかぎりでは、R と同じ値になることを確かめたうえで、医療統計や心理統計で使う手法を広く扱えるものは見つけられませんでした。
無料で使える統計ソフトの中では、R がいちばん信頼できると私は考えています。そこで、R とできるだけ同じ値を返すようにすれば、信頼して使ってもらえるのではないかと考えました。信頼できる統計ライブラリが JavaScript にあれば、世の中の役に立つだろうとも思いました。特定のアプリに使うためではなく、ライブラリそのものを作りたかったのです。
自分の数学と統計学への興味を満たしたい、という気持ちもありました。私は 30 年以上前に、中山書店から出た統計ソフト「フィッシャー」の開発に、チームの一員として加わったことがあり、もともとこの分野に興味がありました。AI がとても有能になったので、その実力を試しながら、やってみたかったことを形にしようと思いました。趣味として作ったものです。
R と同じ値であることの確かめ方
正解の値は、R のスクリプトで計算してファイルに保存してあります。テストはこのファイルと比べるので、R がなくても動きます。分布の関数は、R の値との相対誤差が 1e-14 以内であることを確かめています。
R 自身の値が不正確なところもあります。そこでは Rmpfr や gmp で計算した高精度の値を正解とし、rStats.js はそちらに合わせています。分布の裾の深いところや母数の大きいところでは、rStats.js のほうが R より正確なことがよくあります。
AI を使った作り方
役割の分担
何を作るかを決めたのは私ですが、それも AI とのブレインストーミングで決めました。コードとテストは Claude Code (Opus 5.5) が書いています。
バグ出しには ChatGPT を使いました。ChatGPT がエッジケースやオーバーフロー・アンダーフローを調べて自分で GitHub に issue を立て、Claude Code がそれを検証して直す、という流れです。issue は 500 件を超えました。同じモデルだけに調べさせると知識が偏るので、別のモデルに調べさせるようにしました。
クリーンルーム方式
最初から MIT ライセンスで出すと決めていました。使う側の立場では、MIT がいちばん扱いやすいからです。しかし R も、lme4 など R のパッケージの多くも GPL です。そのコードをコピーしたり翻訳したりすると、MIT では出せません。どうすればよいかを Claude Code とブレインストーミングし、次の方式に決めました。
- Claude Code が R や R のパッケージのソースを読み、何を計算しているかを文章の仕様書にまとめる
- コードを書くのは、ソースを読んだ Claude Code とは切り離した、独立したバックグラウンドのエージェントにする。このエージェントは、それらのコードを一切読まず、仕様書と論文だけをもとに rStats.js を実装する
- R は、出力した値の答え合わせにだけ使う
コードを書くエージェントがソースを読まないように、ここは徹底して制御しました。
仕様書は repo の oracle/ に *-behaviour.md として置いてあり、今は 24 本あります。SciPy や Boost のように MIT と両立するライセンスのコードは、ライセンスを明記したうえで移植しています。
ライセンスには特に気を使いました。AI が R のコードを流用していないかを、繰り返し確かめています。Claude Code に、rStats.js のコードと R や R のパッケージのソースをスクリプトで機械的に比べさせ、流用した箇所がないかを調べました。意味のある名前が付いた変数が一致していないかも確かめています。
AI が欠かせなかったところ
関数がたくさんあると、テストも膨大になります。たくさんの関数に同じ水準のテストを用意しようとしても、人手ではどうしてもぶれてしまいます。AI の力を借りるのは非常に有用でした。
AI はとても丁寧な仕事をしてくれて、その進歩に感動しました。私が自分で確かめるようにしたのは、テストがきちんと行われているかどうかです。
作り始めたのは 2026 年 10 月 20 日で、1.2.0 を公開したのは 11 月 7 日です。約 3 週間でここまで来られたのは、AI のおかげです。
使う前に知っておいてほしいこと
R と同じ結果を返すことを基本にしていますが、意図して R と違う動きをするところがあります。主なものは次のとおりです。
- 添字は 0 から始まります
- 結果が定義されない入力には、NaN を返さずエラーを投げます。ただし分布の関数は、R と同じく不正な母数に NaN を返します
- 10 秒ほどを超えそうな計算は、始める前にエラーを投げます
- R の値が不正確なところでは、R と違う、より正確な値を返します
どの関数がどんな結果を返すかは、R との違いと API リファレンス (英語) に書いてあります。使う前に確認してください。
おわりに
使い方は人それぞれでよいと思っています。自分のアプリに組み込んでもらえればうれしいですし、こんなことをやっている人がいると知ってもらえるだけでも十分です。不具合や R との食い違いを見つけたら、GitHub の issue で教えてください。
この記事では紹介にとどめました。作り方の詳しいところは、このあと何回かに分けて書く予定です。