Text Classification
Transformers
Joblib
Safetensors
bert
sentiment-analysis
finance
macroeconomics
climate
esg
policy
ensemble
dictionary
finbert
Eval Results (legacy)
text-embeddings-inference
Instructions to use peyterho/macro-sentiment-finbert with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use peyterho/macro-sentiment-finbert with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="peyterho/macro-sentiment-finbert")# Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("peyterho/macro-sentiment-finbert") model = AutoModelForSequenceClassification.from_pretrained("peyterho/macro-sentiment-finbert", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Update README with complete evaluation results and usage guide
Browse files
README.md
CHANGED
|
@@ -1,68 +1,204 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
#
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
-
|
| 46 |
-
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
##
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
-
|
| 67 |
-
-
|
| 68 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# π¦ Macroeconomic Sentiment Analysis Pipeline
|
| 2 |
+
|
| 3 |
+
A multi-head NLP system for scoring macroeconomic text β news articles, central bank policy statements, regulatory documents, tweets, and climate/ESG reports.
|
| 4 |
+
|
| 5 |
+
## Architecture
|
| 6 |
+
|
| 7 |
+
The pipeline combines **four dictionary-based signal layers** with a **three-head transformer ensemble** through intelligent domain routing:
|
| 8 |
+
|
| 9 |
+
```
|
| 10 |
+
Input Text
|
| 11 |
+
β
|
| 12 |
+
βββΊ [Keyword Topic Router] βββΊ Policy/Macro βββΊ Financial-RoBERTa-Large
|
| 13 |
+
β βββΊ Climate/ESG βββΊ ClimateBERT
|
| 14 |
+
β βββΊ News/Corp βββΊ FinBERT
|
| 15 |
+
β βββΊ Social/Tweet βββΊ FinBERT
|
| 16 |
+
β
|
| 17 |
+
βββΊ [Loughran-McDonald (2011)] βββΊ polarity, subjectivity
|
| 18 |
+
βββΊ [Henry (2008)] βββββββββββββΊ earnings tone
|
| 19 |
+
βββΊ [Sautner et al. (2023)] ββββΊ climate risk/opportunity density
|
| 20 |
+
βββΊ [Macro Policy Dict] ββββββββΊ hawkish/dovish, crisis, uncertainty
|
| 21 |
+
β
|
| 22 |
+
βββΊ [Dynamic Combiner] βββΊ Weighted fusion with crisis-adaptive weights
|
| 23 |
+
βββΊ Final macro sentiment score [-1, +1]
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
### Key Design Decisions
|
| 27 |
+
|
| 28 |
+
1. **Crisis-adaptive weighting**: When `crisis_signal` is high, dictionary weight increases (transformers may not generalize to unseen crisis patterns).
|
| 29 |
+
2. **Policy stance from dictionaries**: The hawk/dove dictionary gets 80% weight in policy_stance scoring, since the general sentiment models don't distinguish monetary policy direction.
|
| 30 |
+
3. **Topic routing**: Deterministic keyword-based router (no model required) β tested and working reliably across domains.
|
| 31 |
+
|
| 32 |
+
## Quick Start
|
| 33 |
+
|
| 34 |
+
```python
|
| 35 |
+
from macro_sentiment import MacroSentimentPipeline
|
| 36 |
+
|
| 37 |
+
pipe = MacroSentimentPipeline(device="cpu")
|
| 38 |
+
|
| 39 |
+
# Score any macro text
|
| 40 |
+
result = pipe("The Federal Reserve raised rates by 75bps citing persistent inflation.")
|
| 41 |
+
print(result.summary())
|
| 42 |
+
# Sentiment: Positive (+0.472) | Policy: Very Hawkish (+0.999) | Crisis: Normal | Domain: policy
|
| 43 |
+
|
| 44 |
+
# Access individual scores
|
| 45 |
+
print(result.macro_sentiment) # [-1, +1] composite score
|
| 46 |
+
print(result.policy_stance) # [-1 dovish, +1 hawkish]
|
| 47 |
+
print(result.crisis_signal) # [0, 1] crisis intensity
|
| 48 |
+
print(result.climate_exposure) # [0, 1] climate topic density
|
| 49 |
+
print(result.uncertainty) # [0, 1] uncertainty level
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
### Dictionary-Only Mode (no GPU required, instant)
|
| 53 |
+
```python
|
| 54 |
+
pipe = MacroSentimentPipeline(load_transformers=False)
|
| 55 |
+
result = pipe("Markets crashed amid recession fears.", mode="dict_only")
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
### Full Ensemble Mode (all heads)
|
| 59 |
+
```python
|
| 60 |
+
result = pipe.score("ECB signals patience on rate cuts.", mode="all")
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
## Output Fields
|
| 64 |
+
|
| 65 |
+
| Field | Range | Description |
|
| 66 |
+
|-------|-------|-------------|
|
| 67 |
+
| `macro_sentiment` | [-1, +1] | Composite sentiment score (weighted transformer + dictionary) |
|
| 68 |
+
| `policy_stance` | [-1, +1] | Dovish (-1) to Hawkish (+1) β 80% dictionary, 20% transformer |
|
| 69 |
+
| `financial_sentiment` | [-1, +1] | Financial news sentiment from active transformer head |
|
| 70 |
+
| `climate_sentiment` | [-1, +1] | Climate risk (-1) to opportunity (+1) |
|
| 71 |
+
| `crisis_signal` | [0, 1] | Crisis intensity (drives dynamic weight adjustment) |
|
| 72 |
+
| `uncertainty` | [0, 1] | Macroeconomic uncertainty level |
|
| 73 |
+
| `confidence` | [0, 1] | Model confidence (agreement + topic confidence + uncertainty) |
|
| 74 |
+
| `detected_domain` | str | `policy` / `climate` / `financial_news` / `social` |
|
| 75 |
+
| `topic` | str | Human-readable topic label |
|
| 76 |
+
| `head_used` | str | Which transformer head was activated |
|
| 77 |
+
| `lm_polarity` | [-1, +1] | Loughran-McDonald polarity |
|
| 78 |
+
| `henry_polarity` | [-1, +1] | Henry (2008) earnings tone |
|
| 79 |
+
| `climate_exposure` | [0, 1] | Sautner-style climate term density |
|
| 80 |
+
| `raw_features` | dict | All 24+ dictionary + transformer features |
|
| 81 |
+
|
| 82 |
+
## Evaluation Results
|
| 83 |
+
|
| 84 |
+
Evaluated on a combined test set of **4,333 samples** from 5 financial NLP datasets:
|
| 85 |
+
|
| 86 |
+
| Method | Accuracy | F1 Macro | F1 Weighted | N Samples |
|
| 87 |
+
|--------|----------|----------|-------------|-----------|
|
| 88 |
+
| Dictionary Composite (LM+Henry) | 0.568 | 0.528 | 0.578 | 4,333 |
|
| 89 |
+
| **Meta-Classifier (Dict features)** | **0.669** | **0.578** | **0.650** | 4,333 |
|
| 90 |
+
| **Full Pipeline (TF + Dict)** | **0.620** | **0.601** | **0.635** | 100 |
|
| 91 |
+
|
| 92 |
+
### Per-Class Performance (Meta-Classifier)
|
| 93 |
+
```
|
| 94 |
+
precision recall f1-score support
|
| 95 |
+
negative 0.64 0.47 0.54 711
|
| 96 |
+
neutral 0.70 0.85 0.77 2613
|
| 97 |
+
positive 0.55 0.35 0.42 1009
|
| 98 |
+
macro avg 0.63 0.56 0.58 4333
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
### Top Dictionary Features (by GradientBoosting importance)
|
| 102 |
+
```
|
| 103 |
+
henry_subjectivity: 0.2328
|
| 104 |
+
henry_negative_ratio: 0.2100
|
| 105 |
+
henry_polarity: 0.1184
|
| 106 |
+
lm_word_count: 0.0952
|
| 107 |
+
henry_positive_ratio: 0.0652
|
| 108 |
+
lm_negative_ratio: 0.0615
|
| 109 |
+
lm_subjectivity: 0.0519
|
| 110 |
+
lm_positive_ratio: 0.0433
|
| 111 |
+
lm_polarity: 0.0379
|
| 112 |
+
climate_opp_density: 0.0180
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### Qualitative Evaluation (8 Macro Scenarios)
|
| 116 |
+
|
| 117 |
+
| Scenario | Sentiment | Policy Stance | Crisis | Domain |
|
| 118 |
+
|----------|-----------|---------------|--------|--------|
|
| 119 |
+
| Fed Hawkish 75bps | +0.47 Positive β | +1.00 Very Hawkish β | Normal β | policy β |
|
| 120 |
+
| Lehman Bankruptcy | -0.61 Very Negative β | Neutral | HIGH CRISIS β | financial β |
|
| 121 |
+
| Renewable Energy | +0.03 Neutral | Neutral | Normal β | financial | Climate: Opportunity β |
|
| 122 |
+
| ECB Dovish Patience | +0.65 Very Positive β | -0.60 Very Dovish β | Normal β | policy β |
|
| 123 |
+
| COVID Market Crash | -0.62 Very Negative β | -1.00 Very Dovish β | HIGH CRISIS β | policy β |
|
| 124 |
+
| Tesla Surge | +0.75 Very Positive β | Neutral β | Normal β | financial β |
|
| 125 |
+
| Bullish Tweet $AAPL | +0.73 Very Positive β | Neutral β | Normal β | financial β |
|
| 126 |
+
| Mixed Signals/Uncertainty | -0.32 Negative | Neutral | Normal | financial |
|
| 127 |
+
|
| 128 |
+
## Dictionaries
|
| 129 |
+
|
| 130 |
+
| Dictionary | Paper | Captures | Features |
|
| 131 |
+
|-----------|-------|----------|----------|
|
| 132 |
+
| **Loughran-McDonald** | [LM (2011)](https://doi.org/10.1111/j.1540-6261.2010.01625.x) | Financial negative/positive/uncertainty/litigious | 5 features |
|
| 133 |
+
| **Henry** | [Henry (2008)](https://doi.org/10.1177/0021943608319388) | Earnings press release tone (116 pos + 144 neg words) | 4 features |
|
| 134 |
+
| **Climate Exposure** | [Sautner et al. (2023)](https://doi.org/10.1093/rfs/hhad097) style | Climate risk/opportunity/regulatory term density | 8 features |
|
| 135 |
+
| **Macro Policy** | Custom | Hawkish/dovish stance, crisis intensity, uncertainty | 7 features |
|
| 136 |
+
|
| 137 |
+
Total: **24 dictionary features** per text input.
|
| 138 |
+
|
| 139 |
+
## Transformer Models
|
| 140 |
+
|
| 141 |
+
| Head | Model | Domain | Parameters |
|
| 142 |
+
|------|-------|--------|------------|
|
| 143 |
+
| **FinBERT** | [`ProsusAI/finbert`](https://huggingface.co/ProsusAI/finbert) | Financial news | 110M |
|
| 144 |
+
| **Financial-RoBERTa** | [`soleimanian/financial-roberta-large-sentiment`](https://huggingface.co/soleimanian/financial-roberta-large-sentiment) | Policy/formal text | 355M |
|
| 145 |
+
| **ClimateBERT** | [`climatebert/distilroberta-base-climate-sentiment`](https://huggingface.co/climatebert/distilroberta-base-climate-sentiment) | Climate/ESG | 82M |
|
| 146 |
+
|
| 147 |
+
## Training Data
|
| 148 |
+
|
| 149 |
+
~20K train / ~4.3K test samples from 5 financial NLP datasets:
|
| 150 |
+
|
| 151 |
+
| Dataset | HF ID | Train | Test | Domain |
|
| 152 |
+
|---------|-------|-------|------|--------|
|
| 153 |
+
| Financial PhraseBank | [`nickmuchi/financial-classification`](https://huggingface.co/datasets/nickmuchi/financial-classification) | 4,551 | 506 | News headlines |
|
| 154 |
+
| Twitter Financial News | [`zeroshot/twitter-financial-news-sentiment`](https://huggingface.co/datasets/zeroshot/twitter-financial-news-sentiment) | 9,543 | 2,388 | Social/tweets |
|
| 155 |
+
| Auditor Sentiment | [`FinanceInc/auditor_sentiment`](https://huggingface.co/datasets/FinanceInc/auditor_sentiment) | 3,877 | 969 | Audit reports |
|
| 156 |
+
| FiQA | [`pauri32/fiqa-2018`](https://huggingface.co/datasets/pauri32/fiqa-2018) | 1,063 | 150 | Financial Q&A |
|
| 157 |
+
| Climate Sentiment | [`climatebert/climate_sentiment`](https://huggingface.co/datasets/climatebert/climate_sentiment) | 1,000 | 320 | Climate/ESG |
|
| 158 |
+
|
| 159 |
+
**Label distribution (train):** 15.9% negative, 58.4% neutral, 25.7% positive
|
| 160 |
+
|
| 161 |
+
## File Structure
|
| 162 |
+
|
| 163 |
+
```
|
| 164 |
+
macro_sentiment/
|
| 165 |
+
βββ __init__.py # Package exports
|
| 166 |
+
βββ dictionaries.py # LM, Henry, Climate, Macro dictionary scorers
|
| 167 |
+
βββ transformers_ensemble.py # FinBERT, RoBERTa, ClimateBERT heads + router
|
| 168 |
+
βββ pipeline.py # Unified MacroSentimentPipeline
|
| 169 |
+
βββ data_prep.py # Dataset loading and combination
|
| 170 |
+
βββ train_meta.py # Meta-classifier training script
|
| 171 |
+
eval_results.json # Evaluation metrics
|
| 172 |
+
requirements.txt # Dependencies
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
## Fine-Tuning Guide
|
| 176 |
+
|
| 177 |
+
To fine-tune FinBERT on the combined dataset:
|
| 178 |
+
|
| 179 |
+
```python
|
| 180 |
+
# Use the included data_prep module
|
| 181 |
+
from macro_sentiment.data_prep import load_combined_dataset
|
| 182 |
+
ds = load_combined_dataset() # Returns DatasetDict with train/test splits
|
| 183 |
+
|
| 184 |
+
# Fine-tune with standard HuggingFace Trainer
|
| 185 |
+
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
|
| 186 |
+
|
| 187 |
+
model = AutoModelForSequenceClassification.from_pretrained("ProsusAI/finbert", num_labels=3)
|
| 188 |
+
tokenizer = AutoTokenizer.from_pretrained("ProsusAI/finbert")
|
| 189 |
+
|
| 190 |
+
# Then use the fine-tuned model in the pipeline:
|
| 191 |
+
pipe = MacroSentimentPipeline(device="cpu")
|
| 192 |
+
# The FinBERTHead accepts a custom model_name parameter
|
| 193 |
+
```
|
| 194 |
+
|
| 195 |
+
## Literature
|
| 196 |
+
|
| 197 |
+
- Loughran & McDonald (2011). "When Is a Liability Not a Liability?" *Journal of Finance*
|
| 198 |
+
- Henry (2008). "Are Investors Influenced by How Earnings Press Releases Are Written?" *Journal of Business Communication*
|
| 199 |
+
- Sautner et al. (2023). "Firm-Level Climate Change Exposure." *Review of Financial Studies*
|
| 200 |
+
- Araci (2019). [FinBERT: Financial Sentiment Analysis with Pre-Trained Language Models](https://arxiv.org/abs/1908.10063)
|
| 201 |
+
- Huang et al. (2023). [ClimateBERT](https://arxiv.org/abs/2110.12010)
|
| 202 |
+
|
| 203 |
+
## License
|
| 204 |
+
Apache 2.0
|