PHPackages                             belisoful/prado-bayesian - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. belisoful/prado-bayesian

ActivePrado4-extension[Framework](/categories/framework)

belisoful/prado-bayesian
========================

Bayesian classification and recommendation for the PRADO PHP framework: Naive Bayes spam filtering, multinomial/Bernoulli/complement Naive Bayes, TF-IDF weighting, evaluation metrics, and a probabilistic recommender.

v0.1.0(today)10BSD-3-ClausePHPPHP &gt;=8.1.0CI passing

Since Aug 28Pushed todayCompare

[ Source](https://github.com/belisoful/prado-bayesian)[ Packagist](https://packagist.org/packages/belisoful/prado-bayesian)[ Docs](https://github.com/belisoful/prado-bayesian)[ RSS](/packages/belisoful-prado-bayesian/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

PRADO Bayesian Extension
========================

[](#prado-bayesian-extension)

Bayesian classification and recommendation for the [PRADO PHP Framework](https://github.com/pradosoft/prado) (version 4.4+), implemented as a PRADO 4 extension.

> **Pre-release (0.1.0).** This extension targets the PRADO `master` branch (the upcoming 4.4 release), which adds the `extra.prado.bootstrap` / `error-messages` / `class-map` Composer plugin hooks it relies on. It does not work with PRADO 4.3.x; because it depends on PRADO's `master` branch (`^4.4@dev`), your application needs `minimum-stability: dev` (see [Installation](#installation)). Public APIs may still change before 1.0.0.

The module is designed for two common use cases out of the box:

- **Spam filtering** — train a Naive Bayes classifier on labeled text and classify new documents with calibrated probability scores.
- **Recommendation** — score items for a user from observed item/category interactions, ranking by the posterior probability the user is in the "likes this" class.

The classifier, tokenizer, and storage are decoupled, so swapping in a different model family, token strategy, or persistence layer is a one-line configuration change.

Documentation
-------------

[](#documentation)

This README is the quick start. Deeper material lives in [`docs/`](docs/README.md):

PageWhat it covers[Concepts](docs/concepts.md)The pipeline, the three Naive Bayes event models, smoothing, TF-IDF, log-space arithmetic, tokenization, and evaluation[Class reference](docs/classes.md)Every public class and interface by namespace, with its role and public API[Storage backends](docs/storage.md)The `IBayesianStorage` contract, the four backends, and how to choose[Configuration](docs/configuration.md)Module and service wiring, and the full error-code listRequirements
------------

[](#requirements)

RequirementScopePurposePHP 8.1 or higherrequiredLanguage runtime`ext-mbstring`requiredMultibyte-safe tokenization (every tokenizer uses `mb_*`)PRADO Framework `^4.4@dev`required (Composer installs it)`TComponent`, `TService`, `TModule`, `TDbPropertiesTrait`, and the `extra.prado.*` Composer plugin hooks`ext-pdo`suggestedRequired by `TSqlBayesianStorage` (via Prado's `TDbConnection`) for SQL-backed persistence`ext-redis`suggestedRequired by `TRedisBayesianStorage` for Redis-backed persistenceSQL and Redis are **opt-in**. Add the extension you need with:

```
composer require ext-pdo    # for TSqlBayesianStorage
composer require ext-redis  # for TRedisBayesianStorage
```

`TMemoryBayesianStorage` (default) and `TFileBayesianStorage` need no extension. Configuring `TSqlBayesianStorage` or `TRedisBayesianStorage` without the matching PHP extension is a configuration error (`bayesian_storage_pdo_missing` / `bayesian_storage_redis_missing`); there is no silent fallback.

Installation
------------

[](#installation)

```
composer require belisoful/prado-bayesian
```

The framework is a real requirement of this package — `pradosoft/prado` at `^4.4@dev` — so Composer installs it for you. Packagist already serves PRADO's `master` branch as `dev-master`, which the framework aliases to `4.4.x-dev`, so `^4.4@dev` resolves from Packagist with no extra repository. Your application needs only the two stability flags and the asset-packagist repository:

```
{
    "repositories": [
        { "type": "composer", "url": "https://asset-packagist.org" }
    ],
    "require": {
        "belisoful/prado-bayesian": "^0.1"
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}
```

`minimum-stability: dev` with `prefer-stable: true` is what lets `^4.4@dev` resolve while every other dependency still comes from its stable release. The constraint matches PRADO's `dev-master` through the branch alias (`dev-master` → `4.4.x-dev`) declared in the framework's own `composer.json`.

The asset-packagist repository is the framework's requirement, not this package's — PRADO depends on `bower-asset/*` packages, and because **Composer reads `repositories` only from the root project, never from a dependency**, your application has to list it; installing without it fails with `bower-asset/jquery ... could not be found`.

Name `pradosoft/prado` in your own `require` as well if you want to pin the framework version your application runs; nothing here prevents it.

The package's `config/` folder holds what PRADO's third-party plugin support reads system-wide from `composer.json` `extra.prado`: `errorMessages.txt` (the `bayesian_*` exception codes, registered through `error-messages`) and `prado-bayesian-classes.json` (Prado3-style short class names → PHP FQNs, registered through `class-map`, so `TNaiveBayesClassifier` resolves in Prado3-style configuration). Both load for every installed extension whether or not the bootstrap module is used.

What it provides
----------------

[](#what-it-provides)

ClassNamespaceRole`TBayesianModule``Belisoful\Prado\Util\Bayesian`The `extra.prado.bootstrap` module; owns the configured default classifier`TBayesianService``Belisoful\Prado\Web\Services`A `TService` exposing classification and recommendation over the PRADO service pipeline (HTTP request)`IBayesianClassifier``Belisoful\Prado\Util\Bayesian\Classifier`The classifier contract: `train()`, `trainOne()`, `classify()`, `score()`, `save()`, `load()``TNaiveBayesClassifier``Belisoful\Prado\Util\Bayesian\Classifier`The classic Naive Bayes (multinomial event model with Laplace smoothing) — the default spam filter`TMultinomialNaiveBayes``Belisoful\Prado\Util\Bayesian\Classifier`Multinomial Naive Bayes; counts token occurrences per category`TBernoulliNaiveBayes``Belisoful\Prado\Util\Bayesian\Classifier`Bernoulli Naive Bayes; tracks token presence/absence per document`TComplementNaiveBayes``Belisoful\Prado\Util\Bayesian\Classifier`Complement Naive Bayes; well-suited to imbalanced text classification`IBayesianTokenizer``Belisoful\Prado\Util\Bayesian\Tokenizer`The tokenizer seam: input text → list of feature tokens`TWordTokenizer``Belisoful\Prado\Util\Bayesian\Tokenizer`Default word tokenizer; lowercases, strips punctuation, drops short tokens, supports stop words`TNGramTokenizer``Belisoful\Prado\Util\Bayesian\Tokenizer`Character or word n-grams (`n` configurable)`TRegexTokenizer``Belisoful\Prado\Util\Bayesian\Tokenizer`A regex-driven tokenizer for custom patterns`TBayesianTokenizerChain``Belisoful\Prado\Util\Bayesian\Tokenizer`Composes multiple tokenizers (each contributes its tokens)`TBayesianTokenizerTrait``Belisoful\Prado\Util\Bayesian\Tokenizer`Shared tokenizer plumbing: property-driven `exportConfig()`/`importConfig()`, safe `matchAll()`, `normalizeText()``TBayesianTokenizerFactory``Belisoful\Prado\Util\Bayesian\Tokenizer`Serializes/restores tokenizers into the saved model, UTF-8 scrubbing, regex validation`IBayesianVocabulary``Belisoful\Prado\Util\Bayesian`The vocabulary seam: resident, or read per token from storage. `getVocabulary()` returns this`TBayesianVocabulary``Belisoful\Prado\Util\Bayesian`The resident vocabulary; per-category token counts, totals, smoothing`TLazyBayesianVocabulary``Belisoful\Prado\Util\Bayesian`The storage-backed vocabulary; reads a document's tokens per classification via `IBayesianTokenStorage``TLazyBayesianCategory``Belisoful\Prado\Util\Bayesian`A category whose per-token counts come from the vocabulary's last prefetch`TBayesianCategory``Belisoful\Prado\Util\Bayesian`One category: its name, document count, and token counts`TBayesianTrainingSet``Belisoful\Prado\Util\Bayesian`An iterable labeled training set: maps categories to tokenized documents`TBayesianModelConverter``Belisoful\Prado\Util\Bayesian`Rewrites a whole-payload model into a per-token backend without retraining`TFIdf``Belisoful\Prado\Util\Bayesian\Math`Term-frequency × inverse-document-frequency weighting`TBayesMath``Belisoful\Prado\Util\Bayesian\Math`Log-space arithmetic helpers used by the classifiers to avoid underflow`TConfusionMatrix``Belisoful\Prado\Util\Bayesian\Evaluation`Confusion matrix for evaluating a classifier against a labeled set`TBayesianMetrics``Belisoful\Prado\Util\Bayesian\Evaluation`Precision, recall, F1, accuracy, macro/micro averages`IBayesianStorage``Belisoful\Prado\Util\Bayesian\Storage`The persistence seam for a trained model`IBayesianTokenStorage``Belisoful\Prado\Util\Bayesian\Storage`A storage backend that also serves a model per token, for models larger than a process`TMemoryBayesianStorage``Belisoful\Prado\Util\Bayesian\Storage`Process-local in-memory storage (default; no I/O)`TFileBayesianStorage``Belisoful\Prado\Util\Bayesian\Storage`JSON file storage (good for development, small models, single host)`TSqlBayesianStorage``Belisoful\Prado\Util\Bayesian\Storage`SQL-backed storage via `TDbConnection` (SQLite, MySQL, PostgreSQL); whole-payload or per-token (`Mode`); connection through `TDbPropertiesTrait``TRedisBayesianStorage``Belisoful\Prado\Util\Bayesian\Storage`Redis-backed storage for shared hosts; whole-payload or per-token (`Mode`), with atomic `HINCRBY` incremental training (requires `ext-redis`)`IBayesianRecommender``Belisoful\Prado\Util\Bayesian`The recommender contract: `recommend()` for a user/item context`TBayesianRecommender``Belisoful\Prado\Util\Bayesian`A probabilistic recommender built on top of any `IBayesianClassifier`Architecture
------------

[](#architecture)

```
  entry points          TBayesianModule ────────────► TBayesianService
                     (extra.prado.bootstrap;         (TService; HTTP
                      owns default classifier)        classify/recommend)
                                 │  both resolve
                                 ▼
  seam                   IBayesianClassifier ◄──────► IBayesianStorage
                                 │                    memory / file / SQL / Redis
                                 │ implemented by
                                 ▼
  classifiers          TNaiveBayesClassifier          TBayesianRecommender
                                 ▲  extends           (ranks candidates by
                 ┌───────────────┼───────────────┐     P(positive), reusing
     TMultinomialNaiveBayes  TBernoulli-  TComplement-  any classifier)
                             NaiveBayes    NaiveBayes
                                 │ reads / writes
                                 ▼
  training state    TBayesianVocabulary ─── TBayesianCategory ─── TBayesianTrainingSet
                                 │ scores with
                                 ▼
  math                       TBayesMath  ───  TFIdf
                                 │ features from
                                 ▼
  tokenizers             IBayesianTokenizer
                    TWordTokenizer / TNGramTokenizer / TRegexTokenizer / TBayesianTokenizerChain
                                 │
                          (text in, tokens out)

```

The layers stack cleanly:

- **Math** — `TBayesMath` works in log-space, so the Naive Bayes product of thousands of small probabilities never underflows. `TFIdf` weights token contributions by how discriminating they are across the corpus.
- **Tokenizer** — `IBayesianTokenizer` is the seam between text and features. Default `TWordTokenizer` is good enough for spam filtering; swap in `TNGramTokenizer` for language-agnostic content or `TRegexTokenizer` for structured input.
- **Vocabulary &amp; categories** — `IBayesianVocabulary` is the statistics the classifier scores against, behind an interface so they need not all be resident: `TBayesianVocabulary` holds the whole model, `TLazyBayesianVocabulary` reads a document's tokens from storage per classification. `TBayesianCategory` represents one class. `TBayesianTrainingSet` is the labeled corpus in training-time form.
- **Classifiers** — All implement `IBayesianClassifier` and accept any tokenizer + storage. `TNaiveBayesClassifier` is the canonical spam filter and the base class of the other three; `TMultinomialNaiveBayes`, `TBernoulliNaiveBayes`, and `TComplementNaiveBayes` override only the likelihood, so switching event model is a one-line change. Each writes a distinct `kind` marker into its saved model, so several variants can share one storage backend safely.
- **Storage** — `IBayesianStorage` persists a trained model. `TMemoryBayesianStorage` is the no-I/O default; `TFileBayesianStorage` writes JSON; `TSqlBayesianStorage` uses Prado's `TDbConnection`/`TDbCommand` for SQL-backed persistence (SQLite, MySQL, PostgreSQL), configured through `TDbPropertiesTrait` like any other Prado database component, and can store a model per token (`Mode="token"`) so it is bounded by the database rather than by PHP memory; `TRedisBayesianStorage` scales across processes and hosts via Redis, and like the SQL backend can store a model per token (`Mode="token"`), though there the model lives in Redis's RAM rather than on disk.
- **Recommender** — `TBayesianRecommender` reuses the classifier: train it on user/item interactions with a positive and a negative label (`PositiveCategory` defaults to `liked`), then ask it to rank candidate items.
- **Module &amp; service** — `TBayesianModule` is the `extra.prado.bootstrap` entry point that owns the configured classifiers and storage; one module can hold several models over one backend. `TBayesianService` exposes a classifier and the recommender over the PRADO service pipeline (HTTP), sourcing its classifier from the module.

Usage
-----

[](#usage)

### Spam filter (the default)

[](#spam-filter-the-default)

```
use Belisoful\Prado\Util\Bayesian\Classifier\TNaiveBayesClassifier;

$classifier = new TNaiveBayesClassifier();
$classifier->setName('comment-spam');
foreach ([
    'Buy cheap watches now!!!',
    'Limited time offer, click here',
    'Congratulations, you have won a prize',
] as $document) {
    $classifier->trainOne('spam', $document);
}
foreach ([
    'Hey, are we still meeting for lunch tomorrow?',
    'I attached the report you asked for.',
    'Thanks for the help with the bug fix.',
] as $document) {
    $classifier->trainOne('ham', $document);
}

$label = $classifier->classify('FREE VIAGRA!!! Lowest prices online');  // 'spam'
$spam  = $classifier->isSpam('FREE VIAGRA!!! Lowest prices online');    // true
$score = $classifier->score('Buy cheap watches now!!!');                // ['spam' => 0.99..., 'ham' => 0.00...]
```

### Persist a trained model

[](#persist-a-trained-model)

```
use Belisoful\Prado\Util\Bayesian\Storage\TFileBayesianStorage;

$storage = new TFileBayesianStorage();
$storage->setDirectory('/var/lib/myapp/bayesian');
$classifier->setStorage($storage);
$classifier->save();                // serialize the trained model
$classifier->load('comment-spam');  // restore on a future request
```

The saved state carries the tokenizer class and its settings, so a model trained with a `TNGramTokenizer` (or a `TBayesianTokenizerChain`) tokenizes identically after `load()` into a fresh classifier. Each classifier variant writes a `kind` marker and refuses to load a payload saved by a different variant (`bayesian_classifier_kind_mismatch`); load a model with the class that saved it. `TSqlBayesianStorage` creates its table on first use with driver-aware DDL (`VARCHAR(191)`/`LONGTEXT` on MySQL); set `AutoCreateTable="false"` to manage the schema yourself.

### As a PRADO module

[](#as-a-prado-module)

PRADO reads either XML or PHP application configuration; both forms are shown throughout.

**`protected/application.xml`**

```

```

**`protected/application.php`**

```
