PHPackages                             ankane/disco - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. ankane/disco

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

ankane/disco
============

Recommendations for PHP using collaborative filtering

v0.2.1(4mo ago)223352[1 issues](https://github.com/ankane/disco-php/issues)MITPHPPHP &gt;= 8.1CI passing

Since Aug 8Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/ankane/disco-php)[ Packagist](https://packagist.org/packages/ankane/disco)[ RSS](/packages/ankane-disco/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (2)Versions (5)Used By (0)

Disco PHP
=========

[](#disco-php)

🔥 Recommendations for PHP using collaborative filtering

- Supports user-based and item-based recommendations
- Works with explicit and implicit feedback
- Uses high-performance matrix factorization

[![Build Status](https://github.com/ankane/disco-php/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/disco-php/actions)

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

[](#installation)

Run:

```
composer require ankane/disco
```

Add scripts to `composer.json` to download the shared library:

```
    "scripts": {
        "post-install-cmd": "Disco\\Library::check",
        "post-update-cmd": "Disco\\Library::check"
    }
```

And run:

```
composer install
```

Getting Started
---------------

[](#getting-started)

Create a recommender

```
use Disco\Recommender;

$recommender = new Recommender();
```

If users rate items directly, this is known as explicit feedback. Fit the recommender with:

```
$recommender->fit([
    ['user_id' => 1, 'item_id' => 1, 'rating' => 5],
    ['user_id' => 2, 'item_id' => 1, 'rating' => 3]
]);
```

> IDs can be integers or strings

If users don’t rate items directly (for instance, they’re purchasing items or reading posts), this is known as implicit feedback. Leave out the rating.

```
$recommender->fit([
    ['user_id' => 1, 'item_id' => 1],
    ['user_id' => 2, 'item_id' => 1]
]);
```

> Each `user_id`/`item_id` combination should only appear once

Get user-based recommendations - “users like you also liked”

```
$recommender->userRecs($userId);
```

Get item-based recommendations - “users who liked this item also liked”

```
$recommender->itemRecs($itemId);
```

Use the `count` option to specify the number of recommendations (default is 5)

```
$recommender->userRecs($userId, count: 3);
```

Get predicted ratings for specific users and items

```
$recommender->predict([['user_id' => 1, 'item_id' => 2], ['user_id' => 2, 'item_id' => 4]]);
```

Get similar users

```
$recommender->similarUsers($userId);
```

Examples
--------

[](#examples)

### MovieLens

[](#movielens)

Load the data

```
use Disco\Data;

$data = Data::loadMovieLens();
```

Create a recommender and get similar movies

```
$recommender = new Recommender(factors: 20);
$recommender->fit($data);
$recommender->itemRecs('Star Wars (1977)');
```

Storing Recommendations
-----------------------

[](#storing-recommendations)

Save recommendations to your database.

Alternatively, you can store only the factors and use a library like [pgvector-php](https://github.com/pgvector/pgvector-php). See an [example](https://github.com/pgvector/pgvector-php/blob/master/examples/disco/example.php).

Algorithms
----------

[](#algorithms)

Disco uses high-performance matrix factorization.

- For explicit feedback, it uses [stochastic gradient descent](https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf)
- For implicit feedback, it uses [coordinate descent](https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf)

Specify the number of factors and epochs

```
new Recommender(factors: 8, epochs: 20);
```

If recommendations look off, trying changing `factors`. The default is 8, but 3 could be good for some applications and 300 good for others.

Validation
----------

[](#validation)

Pass a validation set with:

```
$recommender->fit($data, validationSet: $validationSet);
```

Cold Start
----------

[](#cold-start)

Collaborative filtering suffers from the [cold start problem](https://en.wikipedia.org/wiki/Cold_start_(recommender_systems)). It’s unable to make good recommendations without data on a user or item, which is problematic for new users and items.

```
$recommender->userRecs($newUserId); // returns empty array
```

There are a number of ways to deal with this, but here are some common ones:

- For user-based recommendations, show new users the most popular items.
- For item-based recommendations, make content-based recommendations.

Reference
---------

[](#reference)

Get ids

```
$recommender->userIds();
$recommender->itemIds();
```

Get the global mean

```
$recommender->globalMean();
```

Get factors

```
$recommender->userFactors($userId);
$recommender->itemFactors($itemId);
```

Credits
-------

[](#credits)

Thanks to [LIBMF](https://github.com/cjlin1/libmf) for providing high performance matrix factorization

History
-------

[](#history)

View the [changelog](https://github.com/ankane/disco-php/blob/master/CHANGELOG.md)

Contributing
------------

[](#contributing)

Everyone is encouraged to help improve this project. Here are a few ways you can help:

- [Report bugs](https://github.com/ankane/disco-php/issues)
- Fix bugs and [submit pull requests](https://github.com/ankane/disco-php/pulls)
- Write, clarify, or fix documentation
- Suggest or add new features

To get started with development:

```
git clone https://github.com/ankane/disco-php.git
cd disco-php
composer install
composer test
```

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance74

Regular maintenance activity

Popularity27

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~410 days

Total

4

Last Release

147d ago

PHP version history (2 changes)v0.1.0PHP &gt;= 8.0

v0.2.0PHP &gt;= 8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/220358?v=4)[Andrew Kane](/maintainers/ankane)[@ankane](https://github.com/ankane)

---

Top Contributors

[![ankane](https://avatars.githubusercontent.com/u/220358?v=4)](https://github.com/ankane "ankane (29 commits)")

---

Tags

recommendation-enginerecommender-system

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ankane-disco/health.svg)

```
[![Health](https://phpackages.com/badges/ankane-disco/health.svg)](https://phpackages.com/packages/ankane-disco)
```

###  Alternatives

[hazaveh/verify-domain

Verify Domain Ownership with PHP

238.6k1](/packages/hazaveh-verify-domain)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
