CoolFace
Apppublic

pavlyhalim/Text_Readability_Classifier

sourceHugging Faceapache-2.0updated 2y agoView on Hugging Face
0likes
app.py245 linesDownload Raw Back to root
1import streamlit as st2import pandas as pd3import numpy as np4import joblib5import plotly.graph_objects as go6from sklearn.base import BaseEstimator, ClassifierMixin7from sklearn.preprocessing import RobustScaler, LabelEncoder8from sklearn.feature_selection import SelectFromModel9from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier10import xgboost as xgb11from sklearn.linear_model import LogisticRegression12import time13from datetime import datetime14 15class OptimizedStackedClassifier(BaseEstimator, ClassifierMixin):16    def __init__(self):17        self.scaler = RobustScaler()18        self.label_encoder = LabelEncoder()19        self.feature_selector = None20        self.base_models = None21        self.meta_model = None22        self.selected_features = None23        self.start_time = time.time()24 25    def predict(self, X):26        """Make predictions using optimized pipeline"""27        # Scale and select features28        X_scaled = pd.DataFrame(29            self.scaler.transform(X),30            columns=X.columns31        )32        X_selected = X_scaled[self.selected_features]33        34        # Generate meta-features35        meta_features = np.zeros((X_selected.shape[0], len(self.base_models) * 6))36        for i, (name, model) in enumerate(self.base_models):37            predictions = model.predict_proba(X_selected)38            meta_features[:, i*6:(i+1)*6] = predictions39        40        # Make final predictions41        predictions = self.meta_model.predict(meta_features)42        return self.label_encoder.inverse_transform(predictions)43 44    def predict_proba(self, X):45        """Get prediction probabilities"""46        # Scale and select features47        X_scaled = pd.DataFrame(48            self.scaler.transform(X),49            columns=X.columns50        )51        X_selected = X_scaled[self.selected_features]52        53        # Generate meta-features54        meta_features = np.zeros((X_selected.shape[0], len(self.base_models) * 6))55        for i, (name, model) in enumerate(self.base_models):56            predictions = model.predict_proba(X_selected)57            meta_features[:, i*6:(i+1)*6] = predictions58        59        return self.meta_model.predict_proba(meta_features)60 61def load_model(model_path):62    """Load the saved model"""63    try:64        return joblib.load(model_path)65    except Exception as e:66        st.error(f"Error loading model: {str(e)}")67        return None68 69def create_features(input_data):70    """Create features matching the model's exact feature names"""71    features = {72        'chars_original': input_data['chars_original'],73        'chars_tokenized': input_data['chars_tokenized'],74        'num_words': input_data['num_words'],75        'num_tokens': input_data['num_tokens'],76        'unique_tokens': input_data['unique_tokens'],77        'type_token_ratio': input_data['type_token_ratio'],78        'fertility': input_data['fertility'],79        'token_std': input_data['token_std'],80        'avg_token_len': input_data['avg_token_len']81    }82    83    # Add derived features84    eps = 1e-1085    features['chars_per_word'] = features['chars_original'] / (features['num_words'] + eps)86    features['chars_per_token'] = features['chars_tokenized'] / (features['num_tokens'] + eps)87    features['tokens_per_word'] = features['num_tokens'] / (features['num_words'] + eps)88    features['token_complexity'] = features['token_std'] * features['avg_token_len']89    features['lexical_density'] = features['unique_tokens'] / (features['num_words'] + eps)90    features['log_chars'] = np.log1p(features['chars_original'])91    features['complexity_score'] = (92        features['token_complexity'] * 93        features['lexical_density'] * 94        features['type_token_ratio']95    )96    97    return pd.DataFrame([features])98 99def plot_probabilities(probabilities):100    """Create a bar plot of prediction probabilities"""101    fig = go.Figure(data=[102        go.Bar(103            x=[f'Level {i+1}' for i in range(len(probabilities))],104            y=probabilities,105            text=np.round(probabilities, 3),106            textposition='auto'107        )108    ])109    fig.update_layout(110        title='Probability Distribution Across Readability Levels',111        xaxis_title='Readability Level',112        yaxis_title='Probability',113        yaxis_range=[0, 1],114        height=400115    )116    return fig117 118def plot_feature_values(features_df):119    """Create a bar plot of feature values"""120    fig = go.Figure(data=[121        go.Bar(122            x=features_df.columns,123            y=features_df.values[0],124            text=np.round(features_df.values[0], 2),125            textposition='auto'126        )127    ])128    fig.update_layout(129        title='Feature Values',130        xaxis_title='Features',131        yaxis_title='Value',132        xaxis_tickangle=-45,133        height=500134    )135    return fig136 137def main():138    st.set_page_config(page_title="Text Readability Classifier", layout="wide")139    140    st.title("Text Readability Classifier")141    st.write("This app predicts the readability level based on text characteristics.")142    143    # Load the model144    model_path = "model.joblib"145    model = load_model(model_path)146    147    if model is None:148        st.error("Could not load the model. Please check if the model file exists.")149        return150    151    # Create two columns for layout152    col1, col2 = st.columns([2, 1])153    154    with col1:155        # Input form for text characteristics156        st.subheader("Enter Text Characteristics")157        158        # Basic features input159        input_data = {}160        input_data['chars_original'] = st.number_input('Number of Characters (Original)', value=0)161        input_data['chars_tokenized'] = st.number_input('Number of Characters (Tokenized)', value=0)162        input_data['num_words'] = st.number_input('Number of Words', value=0)163        input_data['num_tokens'] = st.number_input('Number of Tokens', value=0)164        input_data['unique_tokens'] = st.number_input('Number of Unique Tokens', value=0)165        input_data['type_token_ratio'] = st.number_input('Type-Token Ratio', value=0.0, min_value=0.0, max_value=1.0)166        input_data['fertility'] = st.number_input('Fertility', value=0.0)167        input_data['token_std'] = st.number_input('Token Standard Deviation', value=0.0)168        input_data['avg_token_len'] = st.number_input('Average Token Length', value=0.0)169        170        analyze_button = st.button("Analyze", type="primary")171        172        if analyze_button:173            with st.spinner("Analyzing..."):174                try:175                    # Create features dataframe with all required features176                    features_df = create_features(input_data)177                    178                    # Make prediction179                    prediction = model.predict(features_df)[0]180                    probabilities = model.predict_proba(features_df)[0]181                    182                    # Display results183                    st.subheader("Analysis Results")184                    185                    # Create metrics row186                    metrics_cols = st.columns(2)187                    with metrics_cols[0]:188                        st.metric("Readability Level", f"Level {prediction}")189                    with metrics_cols[1]:190                        highest_prob = max(probabilities)191                        st.metric("Confidence", f"{highest_prob:.2%}")192                    193                    # Show probability distribution194                    st.plotly_chart(plot_probabilities(probabilities), 195                                  use_container_width=True)196                    197                    # Show all feature values including derived features198                    st.subheader("All Features (Including Derived)")199                    st.plotly_chart(plot_feature_values(features_df),200                                  use_container_width=True)201                    202                except Exception as e:203                    st.error(f"Error during analysis: {str(e)}")204    205    with col2:206        # Information sidebar207        with st.container():208            st.subheader("About Readability Levels")209            st.write("""210            The model predicts readability on a scale from 1 to 6:211            - **Level 1**: Very Easy212            - **Level 2**: Easy213            - **Level 3**: Moderately Easy214            - **Level 4**: Moderate215            - **Level 5**: Moderately Difficult216            - **Level 6**: Difficult217            """)218            219            st.subheader("Feature Explanations")220            st.write("""221            **Basic Features:**222            - Character counts (original and tokenized)223            - Word and token counts224            - Type-token ratio (vocabulary diversity)225            - Token length statistics226            227            **Derived Features:**228            - Characters per word/token229            - Token complexity230            - Lexical density231            - Overall complexity score232            """)233            234            st.subheader("Model Performance")235            st.write("""236            This model achieves:237            - **Accuracy**: 73.86%238            - **Macro Avg F1**: 0.75239            - **Weighted Avg F1**: 0.74240            241            *Note: Results should be used as guidance rather than absolute measures.*242            """)243 244if __name__ == "__main__":245    main()