Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import numpy as np | |
| from sklearn.naive_bayes import MultinomialNB, ComplementNB | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.svm import LinearSVC | |
| from sklearn.calibration import CalibratedClassifierCV | |
| from sklearn.ensemble import ( | |
| VotingClassifier, RandomForestClassifier, StackingClassifier, | |
| GradientBoostingClassifier, HistGradientBoostingClassifier | |
| ) | |
| from sklearn.feature_selection import SelectKBest, f_classif | |
| from sklearn.pipeline import Pipeline | |
| from sklearn.compose import ColumnTransformer | |
| from sklearn.preprocessing import MinMaxScaler | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from dl_model import DeepNewsClassifier # §3.3.2 Deep Learning Module | |
| class FakeNewsModels: | |
| def __init__(self): | |
| # All hand-crafted numeric columns (original + new deception features) | |
| num_cols = [ | |
| # Original features | |
| 'lexical_density', 'capital_ratio', 'noun_ratio', 'speaker_reliability', | |
| 'sentiment_score', 'complexity_score', 'subjectivity_score', | |
| 'verb_ratio', 'adj_ratio', 'adv_ratio', 'punctuation_aggression', | |
| 'entity_density', 'formal_cadence', 'official_marker', | |
| # Hedging & Certainty | |
| 'hedge_ratio', 'certainty_ratio', 'hedge_certainty_diff', | |
| # Emotional | |
| 'emotional_intensity', 'sentiment_extremity', | |
| 'negativity_score', 'positivity_score', | |
| # Numerical | |
| 'number_density', 'has_percentage', 'has_dollar_amount', 'number_count', | |
| # Source / Attribution | |
| 'attribution_ratio', 'has_source_citation', | |
| # Readability | |
| 'ari_score', 'gunning_fog', 'avg_sentence_length', | |
| # Pronoun & Modality | |
| 'first_person_ratio', 'modal_ratio', 'negation_ratio', | |
| # Comparison | |
| 'comparative_ratio', 'superlative_ratio', | |
| # Voice | |
| 'passive_ratio', | |
| # Urgency / Style | |
| 'caps_word_ratio', 'ellipsis_count', | |
| 'exclamation_marks', 'question_marks', 'quotes_count', | |
| 'total_words', 'avg_word_length', | |
| # Social context history | |
| 'false_history_ratio', 'true_history_ratio', 'history_volume', | |
| 'is_republican', 'is_democrat', | |
| ] | |
| preprocessor = ColumnTransformer( | |
| transformers=[ | |
| ('text', TfidfVectorizer( | |
| ngram_range=(1, 3), | |
| max_features=12000, | |
| min_df=3, | |
| max_df=0.75, | |
| sublinear_tf=True, | |
| stop_words='english' | |
| ), 'statement'), | |
| ('meta', MinMaxScaler(), num_cols), | |
| ], | |
| remainder='drop' | |
| ) | |
| # Feature selection: keep top 5000 features | |
| selector = SelectKBest(f_classif, k=5000) | |
| # Individual classifiers — tuned for better performance and calibrated uncertainty | |
| nb_clf = CalibratedClassifierCV(ComplementNB(alpha=0.1)) | |
| lr_clf = LogisticRegression( | |
| C=0.8, max_iter=3000, solver='lbfgs', | |
| class_weight='balanced', l1_ratio=0 | |
| ) | |
| svm_clf = CalibratedClassifierCV( | |
| LinearSVC(C=0.5, max_iter=5000, class_weight='balanced', dual='auto') | |
| ) | |
| rf_clf = CalibratedClassifierCV( | |
| RandomForestClassifier( | |
| n_estimators=600, max_depth=22, min_samples_leaf=3, | |
| class_weight='balanced', random_state=42, n_jobs=-1 | |
| ) | |
| ) | |
| self.models = { | |
| 'nb': Pipeline([('pre', preprocessor), ('sel', selector), ('clf', nb_clf)]), | |
| 'lr': Pipeline([('pre', preprocessor), ('sel', selector), ('clf', lr_clf)]), | |
| 'svm': Pipeline([('pre', preprocessor), ('sel', selector), ('clf', svm_clf)]), | |
| 'rf': Pipeline([('pre', preprocessor), ('sel', selector), ('clf', rf_clf)]), | |
| # §3.3.2 Deep Learning Module — BiLSTM-approximating dual encoder | |
| 'dl': DeepNewsClassifier(), | |
| } | |
| # STACKING ENSEMBLE with LogisticRegression meta-learner (§3.3) | |
| # Includes Deep Learning module as 5th base estimator | |
| self.models['ensemble'] = StackingClassifier( | |
| estimators=[ | |
| ('nb', self.models['nb']), | |
| ('lr', self.models['lr']), | |
| ('svm', self.models['svm']), | |
| ('rf', self.models['rf']), | |
| ('dl', self.models['dl']), # §3.3.2 | |
| ], | |
| final_estimator=LogisticRegression( | |
| C=0.5, class_weight='balanced', max_iter=1000 | |
| ), | |
| stack_method='predict_proba', | |
| cv=5, | |
| n_jobs=-1 | |
| ) | |
| def get_model(self, name): | |
| return self.models.get(name) | |
| def get_all_models(self): | |
| return self.models | |