🔥 Recommendations for Go using collaborative filtering
- Supports user-based and item-based recommendations
- Works with explicit and implicit feedback
- Uses high-performance matrix factorization
Run:
go get github.com/ankane/disco-go
Import the package
import "github.com/ankane/disco-go"
Prep your data in the format userId, itemId, value
data := disco.NewDataset[string, string]()
data.Push("user_a", "item_a", 5.0)
data.Push("user_a", "item_b", 3.5)
data.Push("user_b", "item_a", 4.0)
IDs can be integers or strings
data.Push(1, "item_a", 5.0)
If users rate items directly, this is known as explicit feedback. Fit the recommender with:
recommender, err := disco.FitExplicit(data)
If users don’t rate items directly (for instance, they’re purchasing items or reading posts), this is known as implicit feedback. Use 1.0
or a value like number of purchases or page views for the dataset, and fit the recommender with:
recommender, err := disco.FitImplicit(data)
Get user-based recommendations - “users like you also liked”
recommender.UserRecs(userId, 5)
Get item-based recommendations - “users who liked this item also liked”
recommender.ItemRecs(itemId, 5)
Get predicted ratings for a specific user and item
recommender.Predict(userId, itemId)
Get similar users
recommender.SimilarUsers(userId, 5)
Load the data
data, err := disco.LoadMovieLens()
Create a recommender
recommender, err := disco.FitExplicit(data, disco.Factors(20))
Get similar movies
recommender.ItemRecs("Star Wars (1977)")
Save recommendations to your database.
Alternatively, you can store only the factors and use a library like pgvector-go. See an example.
Disco uses high-performance matrix factorization.
- For explicit feedback, it uses the stochastic gradient method with twin learners
- For implicit feedback, it uses the conjugate gradient method
Specify the number of factors and iterations
recommender, err := disco.FitExplicit(data, disco.Factors(8), disco.Iterations(20))
Pass a callback to show progress
callback := func(info disco.FitInfo) { fmt.Printf("%+v\n", info) }
recommender, err := disco.FitExplicit(data, disco.Callback(callback))
Note: TrainLoss
and ValidLoss
are not available for implicit feedback
Pass a validation set with explicit feedback
recommender, err := disco.FitEvalExplicit(trainSet, validSet)
The loss function is RMSE
Collaborative filtering suffers from the cold start problem. 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, 5) // 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
Get ids
recommender.UserIds()
recommender.ItemIds()
Get the global mean
recommender.GlobalMean()
Get factors
recommender.UserFactors(userId)
recommender.ItemFactors(itemId)
- A Learning-rate Schedule for Stochastic Gradient Methods to Matrix Factorization
- Faster Implicit Matrix Factorization
View the changelog
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development:
git clone https://github.com/ankane/disco-go.git
cd disco-go
go mod tidy
go test -v