Restaurant Recommendation Engine using Neural Collaborative Filtering
A deep learning–based recommendation system that predicts which restaurants a user is most likely to engage with, trained on implicit feedback (real user to restaurant interactions) rather than explicit ratings; mirroring how production recommender systems at food-delivery platforms like Swiggy, Zomato, and DoorDash actually operate.
Most recommender system tutorials use explicit rating data (e.g., 1–5 stars) and assume it's dense and reliable. In practice, most production systems; especially in food delivery, e-commerce, and content platforms; face sparse, implicit signals: a user either engaged with an item (ordered, clicked, viewed) or didn't. This project is built around that realistic constraint.
Instead of relying on a pretrained model, the recommendation model here — Neural Collaborative Filtering (NCF) — is trained from scratch, learning user and item embeddings purely from interaction data.
Given a user and a catalog of restaurants, predict a ranked list of restaurants the user is most likely to want to order from, using only implicit interaction history.
Source: Yelp Open Dataset (free, official release)
| File | Used for |
|---|---|
yelp_academic_dataset_business.json |
Restaurant metadata: name, cuisine/category, location, price range |
yelp_academic_dataset_review.json |
Real user–restaurant interactions (used to construct implicit feedback) |
yelp_academic_dataset_user.json |
User metadata |
Implicit feedback construction:
- A review and tip by
user_idforbusiness_idis treated as a positive interaction (engagement), regardless of star rating — reflecting the reality that food-delivery platforms track orders, not ratings, as the primary signal. - Negative sampling: for each positive interaction, a small number of restaurants the user never reviewed are randomly sampled as negatives, following standard practice for implicit-feedback recommender training.
- Dataset is filtered to a subset of cities/categories (restaurants only) to keep training tractable on a single machine.
User ID ──► User Embedding ─────┐
├─► Concatenate ──► MLP (64 → 32 → 1) ──► Sigmoid ──► Probability
Business ID ──► Item Embedding ─┘
- User and item embeddings: learned dense vectors for each user and restaurant, initialized randomly and optimized during training.
- MLP head: combines the two embeddings through a small multi-layer perceptron with ReLU activations to learn non-linear interactions.
- Output: a score between 0 and 1 representing the likelihood that a user will engage with a restaurant.
- Training setup: the model is trained with binary cross-entropy loss on implicit feedback pairs built from reviews and tips.
- Sampling strategy: each positive interaction is paired with random negative samples so the model learns to distinguish observed from unobserved interactions.
Since this is a ranking problem, standard classification accuracy is not meaningful. The following ranking-focused metrics are used:
- Hit Rate@K — was the true (held-out) interacted item present in the top-K recommendations?
- NDCG@K — rewards correctly ranking the true item higher within the top-K list.
- Baseline comparison: model performance is compared against a popularity-based baseline (recommend the most-reviewed restaurants to every user) to demonstrate that personalization adds real value beyond simple popularity ranking.
| Model | Hit Rate@10 | NDCG@10 |
|---|---|---|
| Popularity Baseline | 0.529303 | 0.330189 |
| Neural Collaborative Filtering | 0.427103 | 0.245820 |
New users/restaurants have no learned embedding at inference time. This system falls back to a popularity-based recommendation for new users, and can incorporate restaurant metadata (cuisine, price range, location) as a content-based fallback for new restaurants — a common hybrid strategy used in production recommender systems.
| Layer | Tool |
|---|---|
| Model training | PyTorch |
| Data processing | Pandas, NumPy |
| API serving | Flask |
| Frontend/demo | HTML, CSS Framework |
| Deployment | AWS EC2, API Gateway |
| Storage | Amazon EC2 Virtual Machine (Instances) |
FoodRec/
├── app.py # Main Flask app entry point
├── api/
│ └── main.py # FastAPI service for recommendation endpoints
├── app/
│ └── streamlit_app.py # Streamlit demo interface
├── assets/
├── data/
│ ├── features/ # Feature-mapped IDs and metadata tables
│ ├── interim/ # Intermediate preprocessing outputs
│ ├── processed/ # Cleaned business, review, user, and tip data
│ └── raw/
│ └── yelp_json/ # Yelp raw JSON datasets
├── models/
│ └── ncf_model.pt # Trained neural collaborative filtering model
├── notebooks/
│ ├── 01_data_loading.ipynb
│ ├── 02_eda.ipynb
│ ├── 03_preprocessing.ipynb
│ ├── 04_feature_engineering.ipynb
│ └── 05_ncf_model.ipynb
├── src/
│ └── recommend.py # Recommendation inference logic
├── static/
│ └── css/ # Frontend stylesheets
├── templates/
│ ├── index.html
│ └── recommend.html
├── requirements.txt
└── README.md
# 1. Clone the repository and install dependencies
git clone https://github.com/Manjushwarofficial/FoodRec.git
cd FoodRec
pip install -r requirements.txt
# 2. Run the main Flask web app
python app.py
The main user-facing app is the Flask interface in app.py.
| Component | Service |
|---|---|
| Model inference | AWS EC2 |
| API | Amazon API Gateway → EC2 |
| Frontend | Amazon S3 (static hosting) + CloudFront |
| Model & data storage | Amazon S3 |
- Learned embeddings vs. pretrained embeddings
- Matrix factorization intuition and how NCF generalizes it with an MLP
- Implicit feedback modeling and negative sampling
- Ranking metrics (Hit Rate@K, NDCG@K) vs. classification accuracy
- Cold-start problem and hybrid fallback strategies
- Production considerations: baseline comparison, latency vs. accuracy tradeoffs, scaling recommendation serving
The gap between the neural CF model and the popularity baseline (0.4290 vs 0.5293), even after fixing the sparsity issue, may not signal a pipeline flaw. It could instead reflect a known finding in recommender systems research: many neural CF models fail to beat well tuned simple baselines under fair evaluation. Dacrema et al. (2019), "Are We Really Making Much Progress?", showed popularity baselines can be deceptively strong, especially under the 1 positive vs 99 random negatives protocol used here.
This would be supported if the gap holds across different seeds and resampled negatives, and if the baseline is genuinely well tuned rather than a weak strawman. If so, the result likely reflects a real limitation of neural CF under this setup, not a bug.
- Incorporate restaurant metadata (price, location) as side features for a hybrid content + collaborative model
- Add approximate nearest neighbor search (e.g., FAISS) for scaling to large item catalogs
- Experiment with sequence-aware recommendation (recent order history) using a lightweight sequential model
This project uses the Yelp Open Dataset, which is provided by Yelp for academic and personal use under their dataset license terms.