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
| """ | |
| Meta-classifier: trains a GradientBoosting model on dictionary + (optionally) transformer features | |
| to predict 3-class sentiment labels (negative/neutral/positive). | |
| Two modes: | |
| 1. Dict-only: 24 dictionary features → fast baseline (F1=0.58) | |
| 2. Combined: 24 dict + transformer ensemble features → best accuracy | |
| Usage: | |
| python -m macro_sentiment.train_meta [--use-transformers] [--output PATH] | |
| """ | |
| import os | |
| import sys | |
| import time | |
| import json | |
| import pickle | |
| import numpy as np | |
| from collections import Counter | |
| from sklearn.ensemble import GradientBoostingClassifier | |
| from sklearn.metrics import classification_report, f1_score, accuracy_score | |
| from sklearn.model_selection import cross_val_score | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from macro_sentiment.dictionaries import CombinedDictionaryScorer | |
| def load_data(): | |
| """Load combined dataset.""" | |
| from macro_sentiment.data_prep import load_combined_dataset | |
| ds = load_combined_dataset() | |
| return ds["train"], ds["test"] | |
| def extract_dict_features(texts, scorer): | |
| """Extract dictionary features for a list of texts.""" | |
| features = [] | |
| for i, text in enumerate(texts): | |
| if i % 500 == 0: | |
| print(f" Scoring {i}/{len(texts)}...") | |
| sys.stdout.flush() | |
| feat = scorer.score(text) | |
| features.append(feat) | |
| keys = sorted(features[0].keys()) | |
| X = np.array([[f[k] for k in keys] for f in features]) | |
| return X, keys | |
| def train_meta_classifier(use_transformers=False, output_path="meta_classifier.pkl"): | |
| print(f"[{time.strftime('%H:%M:%S')}] Training meta-classifier (transformers={use_transformers})") | |
| train_ds, test_ds = load_data() | |
| train_texts = train_ds["text"] | |
| test_texts = test_ds["text"] | |
| y_train = np.array(train_ds["label"]) | |
| y_test = np.array(test_ds["label"]) | |
| print(f"\n[{time.strftime('%H:%M:%S')}] Extracting dictionary features...") | |
| sys.stdout.flush() | |
| scorer = CombinedDictionaryScorer() | |
| X_train_dict, feature_names = extract_dict_features(train_texts, scorer) | |
| X_test_dict, _ = extract_dict_features(test_texts, scorer) | |
| X_train = X_train_dict | |
| X_test = X_test_dict | |
| all_feature_names = feature_names | |
| if use_transformers: | |
| print(f"\n[{time.strftime('%H:%M:%S')}] Extracting transformer features...") | |
| sys.stdout.flush() | |
| from macro_sentiment.transformers_ensemble import TransformerEnsemble | |
| ensemble = TransformerEnsemble(device="cpu", use_router=True) | |
| ensemble.load_all() | |
| tf_features_train = [] | |
| for i, text in enumerate(train_texts): | |
| if i % 100 == 0: | |
| print(f" Transformer scoring {i}/{len(train_texts)}...") | |
| sys.stdout.flush() | |
| try: | |
| scores = ensemble.score_all(text) | |
| tf_features_train.append(scores) | |
| except Exception as e: | |
| print(f" Error on sample {i}: {e}") | |
| tf_features_train.append({}) | |
| tf_keys = sorted(set().union(*(f.keys() for f in tf_features_train if f))) | |
| tf_keys = [k for k in tf_keys if isinstance(tf_features_train[0].get(k, 0), (int, float))] | |
| X_train_tf = np.array([[f.get(k, 0.0) for k in tf_keys] for f in tf_features_train]) | |
| X_train = np.hstack([X_train_dict, X_train_tf]) | |
| tf_features_test = [] | |
| for i, text in enumerate(test_texts): | |
| if i % 100 == 0: | |
| print(f" Transformer scoring test {i}/{len(test_texts)}...") | |
| sys.stdout.flush() | |
| try: | |
| scores = ensemble.score_all(text) | |
| tf_features_test.append(scores) | |
| except Exception as e: | |
| tf_features_test.append({}) | |
| X_test_tf = np.array([[f.get(k, 0.0) for k in tf_keys] for f in tf_features_test]) | |
| X_test = np.hstack([X_test_dict, X_test_tf]) | |
| all_feature_names = feature_names + [f"tf_{k}" for k in tf_keys] | |
| print(f"\n[{time.strftime('%H:%M:%S')}] Training GradientBoosting...") | |
| print(f" Features: {X_train.shape[1]}") | |
| print(f" Train samples: {X_train.shape[0]}") | |
| sys.stdout.flush() | |
| clf = GradientBoostingClassifier( | |
| n_estimators=200, | |
| max_depth=5, | |
| learning_rate=0.1, | |
| subsample=0.8, | |
| random_state=42, | |
| ) | |
| clf.fit(X_train, y_train) | |
| y_pred = clf.predict(X_test) | |
| acc = accuracy_score(y_test, y_pred) | |
| f1 = f1_score(y_test, y_pred, average="macro") | |
| report = classification_report(y_test, y_pred, target_names=["negative", "neutral", "positive"]) | |
| print(f"\n[{time.strftime('%H:%M:%S')}] Results:") | |
| print(f" Accuracy: {acc:.4f}") | |
| print(f" F1 macro: {f1:.4f}") | |
| print(f"\n{report}") | |
| sys.stdout.flush() | |
| importances = sorted(zip(all_feature_names, clf.feature_importances_), key=lambda x: -x[1]) | |
| print("\nTop 10 Features:") | |
| for name, imp in importances[:10]: | |
| print(f" {name}: {imp:.4f}") | |
| artifact = { | |
| "model": clf, | |
| "feature_names": all_feature_names, | |
| "accuracy": acc, | |
| "f1_macro": f1, | |
| "use_transformers": use_transformers, | |
| "report": report, | |
| "feature_importances": importances, | |
| } | |
| with open(output_path, "wb") as f: | |
| pickle.dump(artifact, f) | |
| print(f"\n[{time.strftime('%H:%M:%S')}] Saved to {output_path}") | |
| return artifact | |
| if __name__ == "__main__": | |
| import argparse | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--use-transformers", action="store_true") | |
| parser.add_argument("--output", default="meta_classifier.pkl") | |
| args = parser.parse_args() | |
| train_meta_classifier(use_transformers=args.use_transformers, output_path=args.output) | |