amazon-science/XplainRecommendation
Python
Captured source
source ↗amazon-science/XplainRecommendation
Description: Code accompanying "Pairwise Ranking Outperforms Single-Action RL for Offline Explanation Selection: A Practical Lesson" (Tanay Chowdhury, Saeideh Shahrokh Esfahani — RecSys 2026, Research & Practice Notes track).
Language: Python
License: NOASSERTION
Stars: 0
Forks: 0
Open issues: 0
Created: 2026-09-01T17:52:15Z
Pushed: 2026-09-01T18:34:29Z
Default branch: main
Fork: no
Archived: no
README:
XplainRecommendation
Code accompanying *"Pairwise Ranking Outperforms Single-Action RL for Offline Explanation Selection: A Practical Lesson"* (Tanay Chowdhury, Saeideh Shahrokh Esfahani — RecSys 2026, Research & Practice Notes track).
This repo reproduces every headline number in the paper from XRec's published data. It is standalone: the only external dependencies are XRec's data files (trn.pkl / tst.pkl), G-Refer's cached predictions (google_pred.jsonl), and a local review cache (iid_reviews.json).
If you already have the data-prep artefacts in results/ (the release bundle ships with them), jump to §4. If you want to regenerate everything from raw XRec data, start at §1.
> This code is being released solely for academic and scientific > reproducibility purposes, in support of the methods and findings described > in the associated publication. Pull requests are not being accepted in > order to maintain the code exactly as it was used in the paper.
---
0. What's in here
XplainRecommendation/ ├── README.md ← this file ├── LICENSE ← CC-BY-NC-4.0 ├── NOTICE ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── requirements.txt ├── docs/ │ ├── RESEARCH_SUMMARY.md ← problem statement, methods, theory, what didn't work │ └── kg_path_selection_results.md ├── _paths.py ← shared path resolution helper ├── scripts/ ← pool-generation + reranker library modules ├── src/ ← PPO agent, Bedrock client, entropy scheduler ├── pipeline/ ← data-prep stages (verify → sample → pool → featurize → tables) ├── runners/ ← training scripts: PPO, GRPO, DPO, Distillation ├── movielens/ ← parallel pipeline for the MovieLens-1M cross-dataset check └── results/ ← evaluation outputs (baselines, lambdarank, experiments)
By default, external datasets (XRec/, G-Refer/, data/) are expected as siblings of this repo's own top-level directories (i.e. inside this repo's root — see §1). Set the FINAL_RESULT_DATA env var if your datasets live somewhere else.
---
1. Prerequisites
Files that must exist under DATA_ROOT (the repo root, by default):
DATA_ROOT/ ├── XRec/data/google/trn.pkl # 94,663 training pairs ├── XRec/data/google/val.pkl # 11,833 val pairs ├── XRec/data/google/tst.pkl # 3,000 test pairs ├── XRec/data/google/tst_pred.pkl # XRec's cached predictions (baseline) ├── G-Refer/gen_explanations/G-Refer/google_pred.jsonl # G-Refer's cached predictions (baseline) ├── G-Refer/evaluation/bart_score.py # for BARTScore └── data/google_local/iid_reviews.json # same-business review cache
XRec and G-Refer are separate public research repos — clone them yourself; this repo does not vendor their code or data.
Python packages:
pip install -r requirements.txt
AWS credentials for Bedrock (Nova Lite + Claude 3 Haiku + Titan v2 embeddings) are required only if regenerating the candidate pool. If you're using the bundled results, no AWS access is needed.
---
2. Running the data-prep pipeline
The full pipeline is orchestrated by pipeline/prepare_data.py. It runs five stages sequentially; each stage caches its output, so re-runs skip anything already done.
python3 pipeline/prepare_data.py
| Stage | Script | Output | Wall time | Bedrock cost | |---|---|---|---|---| | 1. verify | verify_splits.py | (prints OK) | 1 min | $0 | | 2. sample | sample_training.py | results/trn_5k.pkl | 30 sec | $0 | | 3. pool | build_pool.py | results/pool/exp_pool_clean_xrec_{trn,tst}_*.pkl | ~3 h | ~$11 | | 4. featurize | featurize_and_label.py | results/features/features.pkl | ~4 h | ~$0.40 | | 5. tables | fit_lambdarank_and_build_tables.py | results/paper_ppo_tables.npz, results/lambdarank_*.{pkl,json,npz} | ~2 min | ~$0.20 |
Run individual stages:
python3 pipeline/prepare_data.py --stages verify,sample python3 pipeline/prepare_data.py --force-stage pool
Each standalone script also runs on its own:
python3 pipeline/sample_training.py python3 pipeline/featurize_and_label.py --max_workers 4
---
3. Evaluating baselines
python3 pipeline/eval_baselines.py
Reads XRec's tst_pred.pkl and G-Refer's google_pred.jsonl, scores them with the same BERTScore / BARTScore / USR metrics we use for our methods, writes results/baselines.json. No training, no Bedrock calls — just evaluation on cached predictions.
Expected output (on the shared 2,958-pair test subset):
- XRec F1 = 0.3856, BART = −3.56, USR = 0.9993
- G-Refer 8B F1 = 0.4592, BART = −3.31, USR = 0.60
---
4. Training and evaluating our methods
All four RL-family methods and LambdaRank are trained on the same results/paper_ppo_tables.npz state/reward tables produced by step 5. The 5,000-pair training set and 2,958-pair test set are baked into the tables; no data loading is required at training time.
4a. LambdaRank
Already computed in step 5. Read the result directly:
python3 -c "import json; d=json.load(open('results/lambdarank_result.json')); print(f\"LambdaRank F1 = {d['test_f1_mean']:.4f} ± {d['test_f1_std']:.4f} (n={d['n_test']})\")"
# → LambdaRank F1 = 0.5003 ± 0.0947 (n=2958)4b. PPO (single seed, baseline reward)
python3 runners/run_ppo.py \ --tables results/paper_ppo_tables.npz \ --seed 42 --episodes 500 \ --reward_mode baseline --alpha 0.1 \ --result_out results/experiments/ppo/seed42.json \ --history_out results/experiments/ppo/seed42_history.json
--reward_mode can be baseline, zscore, alpha0, or median (see runners/run_ppo.py for the reward-shape ablation).
4c. GRPO
python3 runners/run_grpo.py \ --tables results/paper_ppo_tables.npz \ --seed 42 --episodes 500 \ --result_out results/experiments/grpo/seed42.json
4d. DPO
python3 runners/run_dpo.py \ --tables results/paper_ppo_tables.npz \ --seed 42 --episodes 500 \ --result_out results/experiments/dpo/seed42.json
4e. Distillation
python3 runners/run_distillation.py \ --tables results/paper_ppo_tables.npz \ --seed 42 \...
Excerpt shown — open the source for the full document.