CoolFace
Apppublic

ahadalii/Predictive_Maintenance_System

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
app.py990 linesDownload Raw Back to root
1"""2Streamlit Application for Predictive Maintenance Project3Interactive web app for EDA, model visualization, and runtime predictions4"""5 6import streamlit as st7import pandas as pd8import numpy as np9import plotly.express as px10import plotly.graph_objects as go11from plotly.subplots import make_subplots12import pickle13import warnings14warnings.filterwarnings('ignore')15 16# Import custom modules17from preprocessing import DataPreprocessor18from model import PredictiveMaintenanceModel19 20# Page configuration21st.set_page_config(22    page_title="Predictive Maintenance System",23    page_icon="๐Ÿ”ง",24    layout="wide",25    initial_sidebar_state="expanded"26)27 28# Custom CSS29st.markdown("""30    <style>31    .main-header {32        font-size: 3rem;33        font-weight: bold;34        color: #1f77b4;35        text-align: center;36        margin-bottom: 2rem;37    }38    .sub-header {39        font-size: 1.5rem;40        color: #ff7f0e;41        margin-top: 2rem;42        margin-bottom: 1rem;43    }44    .metric-card {45        background-color: #f0f2f6;46        padding: 1rem;47        border-radius: 0.5rem;48        margin: 0.5rem 0;49    }50    </style>51""", unsafe_allow_html=True)52 53# Initialize session state54if 'model' not in st.session_state:55    st.session_state.model = None56if 'preprocessor' not in st.session_state:57    st.session_state.preprocessor = None58if 'data' not in st.session_state:59    st.session_state.data = None60 61@st.cache_data62def load_data():63    """Load and cache the dataset"""64    df = pd.read_csv('ai4i2020.csv')65    # Create additional features66    df['Temperature difference [K]'] = (67        df['Process temperature [K]'] - df['Air temperature [K]']68    )69    df['Power [W]'] = (70        df['Rotational speed [rpm]'] * df['Torque [Nm]'] / 9.548871    )72    return df73 74def train_model():75    """Train the model and preprocessor"""76    with st.spinner("Training model... This may take a moment."):77        preprocessor = DataPreprocessor('ai4i2020.csv')78        X_train, X_test, y_train, y_test, feature_columns = preprocessor.prepare_data()79        80        model = PredictiveMaintenanceModel()81        model.train(X_train, y_train)82        83        # Evaluate model84        results = model.evaluate(X_test, y_test)85        86        st.session_state.model = model87        st.session_state.preprocessor = preprocessor88        st.session_state.feature_columns = feature_columns89        90        return results91 92# Main App93def main():94    # Header95    st.markdown('<h1 class="main-header">๐Ÿ”ง Predictive Maintenance System</h1>', unsafe_allow_html=True)96    st.markdown("---")97    98    # Sidebar Navigation99    st.sidebar.title("Navigation")100    page = st.sidebar.radio(101        "Select Page",102        ["Introduction", "Exploratory Data Analysis", "Model & Predictions", "Conclusion"]103    )104    105    # Load data106    df = load_data()107    st.session_state.data = df108    109    if page == "Introduction":110        show_introduction(df)111    elif page == "Exploratory Data Analysis":112        show_eda(df)113    elif page == "Model & Predictions":114        show_model_predictions(df)115    elif page == "Conclusion":116        show_conclusion()117 118def show_introduction(df):119    """Introduction page"""120    st.markdown('<h2 class="sub-header">๐Ÿ“‹ Project Introduction</h2>', unsafe_allow_html=True)121    122    col1, col2 = st.columns([2, 1])123    124    with col1:125        st.markdown("""126        ### About the Dataset127        128        This project uses the **AI4I 2020 Predictive Maintenance Dataset**, which contains 129        synthetic data simulating predictive maintenance scenarios for industrial machinery.130        131        #### Dataset Overview:132        - **Total Records**: 10,000 machines133        - **Features**: 14 attributes including temperature, rotational speed, torque, and tool wear134        - **Target**: Machine failure prediction (binary classification)135        - **Failure Types**: Tool Wear Failure (TWF), Heat Dissipation Failure (HDF), 136          Power Failure (PWF), Overstrain Failure (OSF), and Random Failure (RNF)137        138        #### Project Goals:139        1. **Exploratory Data Analysis**: Understand patterns and relationships in the data140        2. **Predictive Modeling**: Build a machine learning model to predict machine failures141        3. **Maintenance Scheduling**: Estimate when maintenance is needed and how urgent it is142        4. **Interactive Visualization**: Present findings through an interactive web application143        144        #### Key Features:145        - Comprehensive EDA with 15+ different analyses146        - Random Forest Classifier for failure prediction147        - Real-time predictions based on user input148        - Maintenance urgency assessment149        - Time-to-failure estimation150        """)151    152    with col2:153        st.markdown("### Dataset Statistics")154        st.metric("Total Machines", f"{len(df):,}")155        st.metric("Features", len(df.columns))156        st.metric("Machine Failures", f"{df['Machine failure'].sum():,}")157        st.metric("Failure Rate", f"{(df['Machine failure'].mean()*100):.2f}%")158        159        st.markdown("### Machine Types")160        type_counts = df['Type'].value_counts()161        type_meanings = {'L': 'Low Quality/Load', 'M': 'Medium Quality/Load', 'H': 'High Quality/Load'}162        for machine_type, count in type_counts.items():163            meaning = type_meanings.get(machine_type, '')164            st.metric(f"Type {machine_type} ({meaning})", f"{count:,}")165    166    st.markdown("---")167    st.markdown("### Dataset Preview")168    preview_mode = st.radio(169        "Preview mode",170        options=["First 20 rows", "Show all (10,000 rows)"],171        index=0,172        horizontal=True,173    )174    if preview_mode == "First 20 rows":175        st.dataframe(df.head(20), use_container_width=True)176    else:177        st.dataframe(df, use_container_width=True)178    179    st.markdown("### Dataset Information")180    with st.expander("View Column Descriptions"):181        st.markdown("""182        - **UDI**: Unique identifier for each machine183        - **Product ID**: Product identifier184        - **Type**: Machine type (L = Low Quality/Load, M = Medium Quality/Load, H = High Quality/Load)185        - **Air temperature [K]**: Air temperature in Kelvin186        - **Process temperature [K]**: Process temperature in Kelvin187        - **Rotational speed [rpm]**: Rotational speed in revolutions per minute188        - **Torque [Nm]**: Torque in Newton meters189        - **Tool wear [min]**: Tool wear in minutes190        - **Machine failure**: Binary target (0 = no failure, 1 = failure)191        - **TWF, HDF, PWF, OSF, RNF**: Different failure type indicators192        """)193 194def show_eda(df):195    """EDA page"""196    st.markdown('<h2 class="sub-header">๐Ÿ“Š Exploratory Data Analysis</h2>', unsafe_allow_html=True)197    198    # Analysis selection199    analysis_type = st.selectbox(200        "Select Analysis Type",201        [202            "Summary Statistics",203            "Data Types & Unique Values",204            "Target Distribution",205            "Feature Distributions",206            "Correlation Analysis",207            "Failure Analysis by Type",208            "Tool Wear Analysis",209            "Temperature Analysis",210            "Power & Rotational Speed Analysis",211            "Outlier Detection",212            "Pairwise Relationships",213            "Failure Type Breakdown",214            "Time to Failure Estimation",215            "Grouped Aggregations"216        ]217    )218    219    st.markdown("---")220    221    if analysis_type == "Summary Statistics":222        st.subheader("Summary Statistics")223        st.dataframe(df.describe(), use_container_width=True)224        225        # Key metrics226        col1, col2, col3, col4 = st.columns(4)227        with col1:228            st.metric("Mean Air Temp", f"{df['Air temperature [K]'].mean():.2f} K")229        with col2:230            st.metric("Mean Process Temp", f"{df['Process temperature [K]'].mean():.2f} K")231        with col3:232            st.metric("Mean Rotational Speed", f"{df['Rotational speed [rpm]'].mean():.0f} rpm")233        with col4:234            st.metric("Mean Torque", f"{df['Torque [Nm]'].mean():.2f} Nm")235    236    elif analysis_type == "Data Types & Unique Values":237        st.subheader("Data Types and Unique Values")238        239        info_df = pd.DataFrame({240            'Column': df.columns,241            'Data Type': df.dtypes.astype(str),242            'Unique Values': [df[col].nunique() for col in df.columns],243            'Non-Null Count': df.count().values244        })245        246        st.dataframe(info_df, use_container_width=True)247        248        st.subheader("Machine Type Distribution")249        type_counts = df['Type'].value_counts()250        type_meanings = {'L': 'Low Quality/Load', 'M': 'Medium Quality/Load', 'H': 'High Quality/Load'}251        252        col1, col2 = st.columns(2)253        with col1:254            fig = px.bar(255                x=type_counts.index,256                y=type_counts.values,257                title="Machine Type Distribution",258                labels={'x': 'Machine Type', 'y': 'Count'},259                color=type_counts.index,260                color_discrete_sequence=['#e74c3c', '#3498db', '#2ecc71']261            )262            st.plotly_chart(fig, use_container_width=True)263        264        with col2:265            for machine_type, count in type_counts.items():266                meaning = type_meanings.get(machine_type, '')267                st.metric(f"Type {machine_type} ({meaning})", f"{count:,}")268    269    elif analysis_type == "Target Distribution":270        st.subheader("Machine Failure Distribution")271        272        col1, col2 = st.columns(2)273        274        with col1:275            failure_counts = df['Machine failure'].value_counts()276            fig = px.pie(277                values=failure_counts.values,278                names=['No Failure', 'Failure'],279                title="Failure Distribution",280                color_discrete_sequence=['#2ecc71', '#e74c3c']281            )282            st.plotly_chart(fig, use_container_width=True)283        284        with col2:285            st.metric("No Failure", f"{failure_counts[0]:,} ({(failure_counts[0]/len(df)*100):.2f}%)")286            st.metric("Failure", f"{failure_counts[1]:,} ({(failure_counts[1]/len(df)*100):.2f}%)")287            288            # Failure types289            st.subheader("Failure Types Breakdown")290            failure_types = {291                'TWF': 'Tool Wear Failure',292                'HDF': 'Heat Dissipation Failure',293                'PWF': 'Power Failure',294                'OSF': 'Overstrain Failure',295                'RNF': 'Random Failure'296            }297            for ft_code, ft_name in failure_types.items():298                count = df[ft_code].sum()299                st.metric(ft_name, f"{count} ({(count/len(df)*100):.2f}%)")300    301    elif analysis_type == "Feature Distributions":302        st.subheader("Feature Distributions")303        304        feature = st.selectbox(305            "Select Feature",306            ['Air temperature [K]', 'Process temperature [K]', 'Rotational speed [rpm]', 307             'Torque [Nm]', 'Tool wear [min]', 'Temperature difference [K]', 'Power [W]']308        )309        310        col1, col2 = st.columns(2)311        312        with col1:313            fig = px.histogram(314                df, x=feature, nbins=50,315                title=f"Distribution of {feature}",316                color_discrete_sequence=['#3498db']317            )318            st.plotly_chart(fig, use_container_width=True)319        320        with col2:321            fig = px.box(322                df, y=feature,323                title=f"Box Plot of {feature}",324                color_discrete_sequence=['#9b59b6']325            )326            st.plotly_chart(fig, use_container_width=True)327        328        # Statistics329        st.subheader("Statistics")330        col1, col2, col3, col4 = st.columns(4)331        with col1:332            st.metric("Mean", f"{df[feature].mean():.2f}")333        with col2:334            st.metric("Median", f"{df[feature].median():.2f}")335        with col3:336            st.metric("Std Dev", f"{df[feature].std():.2f}")337        with col4:338            st.metric("Skewness", f"{df[feature].skew():.2f}")339    340    elif analysis_type == "Correlation Analysis":341        st.subheader("Correlation Analysis")342        343        numerical_cols = [344            'Air temperature [K]', 'Process temperature [K]',345            'Rotational speed [rpm]', 'Torque [Nm]', 'Tool wear [min]',346            'Temperature difference [K]', 'Power [W]', 'Machine failure'347        ]348        349        corr_matrix = df[numerical_cols].corr()350        351        fig = px.imshow(352            corr_matrix,353            text_auto=True,354            aspect="auto",355            title="Correlation Heatmap",356            color_continuous_scale="RdBu"357        )358        st.plotly_chart(fig, use_container_width=True)359        360        st.subheader("Correlation with Machine Failure")361        failure_corr = corr_matrix['Machine failure'].sort_values(ascending=False)362        fig = px.bar(363            x=failure_corr.index,364            y=failure_corr.values,365            title="Feature Correlation with Machine Failure",366            labels={'x': 'Feature', 'y': 'Correlation'},367            color=failure_corr.values,368            color_continuous_scale="RdYlGn"369        )370        st.plotly_chart(fig, use_container_width=True)371    372    elif analysis_type == "Failure Analysis by Type":373        st.subheader("Failure Analysis by Machine Type")374        st.info("**Machine Type Meanings**: L = Low Quality/Load, M = Medium Quality/Load, H = High Quality/Load")375        376        failure_by_type = df.groupby('Type')['Machine failure'].agg(['count', 'sum', 'mean']).reset_index()377        failure_by_type.columns = ['Type', 'Total Machines', 'Failures', 'Failure Rate']378        failure_by_type['Failure Rate'] = failure_by_type['Failure Rate'] * 100379        failure_by_type['Type_Label'] = failure_by_type['Type'].map({380            'L': 'L (Low Quality/Load)',381            'M': 'M (Medium Quality/Load)',382            'H': 'H (High Quality/Load)'383        })384        385        st.dataframe(failure_by_type[['Type', 'Total Machines', 'Failures', 'Failure Rate']], use_container_width=True)386        387        fig = px.bar(388            failure_by_type,389            x='Type_Label',390            y='Failure Rate',391            title="Failure Rate by Machine Type",392            color='Type',393            color_discrete_sequence=['#e74c3c', '#3498db', '#2ecc71'],394            labels={'Type_Label': 'Machine Type'}395        )396        st.plotly_chart(fig, use_container_width=True)397    398    elif analysis_type == "Tool Wear Analysis":399        st.subheader("Tool Wear Analysis")400        401        col1, col2 = st.columns(2)402        403        with col1:404            fig = px.scatter(405                df,406                x='Tool wear [min]',407                y='Machine failure',408                color='Machine failure',409                title="Tool Wear vs Machine Failure",410                color_discrete_sequence=['#2ecc71', '#e74c3c']411            )412            st.plotly_chart(fig, use_container_width=True)413        414        with col2:415            tool_wear_by_failure = df.groupby('Machine failure')['Tool wear [min]'].agg(['mean', 'median', 'std'])416            st.dataframe(tool_wear_by_failure, use_container_width=True)417        418        # Tool wear distribution by failure status419        fig = px.histogram(420            df,421            x='Tool wear [min]',422            color='Machine failure',423            nbins=50,424            title="Tool Wear Distribution by Failure Status",425            barmode='overlay',426            color_discrete_sequence=['#2ecc71', '#e74c3c']427        )428        st.plotly_chart(fig, use_container_width=True)429    430    elif analysis_type == "Temperature Analysis":431        st.subheader("Temperature Analysis")432        433        col1, col2 = st.columns(2)434        435        with col1:436            fig = px.scatter(437                df,438                x='Air temperature [K]',439                y='Process temperature [K]',440                color='Machine failure',441                title="Temperature Relationship",442                color_discrete_sequence=['#2ecc71', '#e74c3c']443            )444            st.plotly_chart(fig, use_container_width=True)445        446        with col2:447            temp_by_failure = df.groupby('Machine failure')[448                ['Air temperature [K]', 'Process temperature [K]', 'Temperature difference [K]']449            ].mean()450            st.dataframe(temp_by_failure, use_container_width=True)451    452    elif analysis_type == "Power & Rotational Speed Analysis":453        st.subheader("Power and Rotational Speed Analysis")454        455        power_stats = df.groupby('Machine failure')[456            ['Rotational speed [rpm]', 'Torque [Nm]', 'Power [W]']457        ].agg(['mean', 'std', 'min', 'max'])458        459        st.dataframe(power_stats, use_container_width=True)460        461        col1, col2 = st.columns(2)462        463        with col1:464            fig = px.box(465                df,466                x='Machine failure',467                y='Rotational speed [rpm]',468                title="Rotational Speed by Failure Status",469                color='Machine failure',470                color_discrete_sequence=['#2ecc71', '#e74c3c']471            )472            st.plotly_chart(fig, use_container_width=True)473        474        with col2:475            fig = px.box(476                df,477                x='Machine failure',478                y='Power [W]',479                title="Power by Failure Status",480                color='Machine failure',481                color_discrete_sequence=['#2ecc71', '#e74c3c']482            )483            st.plotly_chart(fig, use_container_width=True)484        485        # Scatter plot: Power vs Rotational Speed486        fig = px.scatter(487            df,488            x='Rotational speed [rpm]',489            y='Power [W]',490            color='Machine failure',491            title="Power vs Rotational Speed",492            color_discrete_sequence=['#2ecc71', '#e74c3c']493        )494        st.plotly_chart(fig, use_container_width=True)495    496    elif analysis_type == "Outlier Detection":497        st.subheader("Outlier Detection")498        499        feature = st.selectbox(500            "Select Feature for Outlier Detection",501            ['Air temperature [K]', 'Process temperature [K]', 'Rotational speed [rpm]', 502             'Torque [Nm]', 'Tool wear [min]']503        )504        505        method = st.radio(506            "Detection method",507            options=["IQR (robust, default)", "Z-score"],508            index=0,509            horizontal=True,510            help="IQR is robust to skew; Z-score highlights extreme standardized values."511        )512        513        if method == "IQR (robust, default)":514            iqr_mult = st.slider("IQR multiplier", 0.5, 3.0, 1.5, 0.1,515                                 help="Lower the multiplier to surface milder outliers.")516            Q1 = df[feature].quantile(0.25)517            Q3 = df[feature].quantile(0.75)518            IQR = Q3 - Q1519            lower_bound = Q1 - iqr_mult * IQR520            upper_bound = Q3 + iqr_mult * IQR521            522            outliers = df[(df[feature] < lower_bound) | (df[feature] > upper_bound)]523            524            col1, col2 = st.columns(2)525            with col1:526                st.metric("Lower Bound", f"{lower_bound:.2f}")527                st.metric("Upper Bound", f"{upper_bound:.2f}")528            with col2:529                st.metric("Outlier Count", len(outliers))530                st.metric("Outlier Percentage", f"{(len(outliers)/len(df)*100):.2f}%")531            532            fig = px.box(df, y=feature, title=f"Box Plot with Outliers - {feature}")533            st.plotly_chart(fig, use_container_width=True)534        535        else:536            z_thresh = st.slider("Z-score threshold", 2.0, 5.0, 3.0, 0.1,537                                 help="Lower threshold to surface more anomalies.")538            mean = df[feature].mean()539            std = df[feature].std()540            if std == 0:541                outliers = df.iloc[0:0]542                zscores = pd.Series([0]*len(df), index=df.index)543            else:544                zscores = (df[feature] - mean) / std545                outliers = df[zscores.abs() > z_thresh]546            547            col1, col2 = st.columns(2)548            with col1:549                st.metric("Mean", f"{mean:.2f}")550                st.metric("Std Dev", f"{std:.2f}")551            with col2:552                st.metric("Outlier Count", len(outliers))553                st.metric("Outlier Percentage", f"{(len(outliers)/len(df)*100):.2f}%")554            555            fig = px.histogram(df, x=feature, nbins=60, opacity=0.7,556                               title=f"{feature} with Z-score Threshold (>|{z_thresh}|)")557            # Overlay threshold lines558            fig.add_vline(x=mean + z_thresh*std, line_dash="dash", line_color="red")559            fig.add_vline(x=mean - z_thresh*std, line_dash="dash", line_color="red")560            st.plotly_chart(fig, use_container_width=True)561    562    elif analysis_type == "Pairwise Relationships":563        st.subheader("Pairwise Feature Relationships")564        565        feature1 = st.selectbox("Select First Feature", 566                               ['Tool wear [min]', 'Temperature difference [K]', 567                                'Rotational speed [rpm]', 'Torque [Nm]'])568        feature2 = st.selectbox("Select Second Feature",569                               ['Tool wear [min]', 'Temperature difference [K]',570                                'Rotational speed [rpm]', 'Torque [Nm]'])571        572        if feature1 != feature2:573            fig = px.scatter(574                df,575                x=feature1,576                y=feature2,577                color='Machine failure',578                title=f"{feature1} vs {feature2}",579                color_discrete_sequence=['#2ecc71', '#e74c3c']580            )581            st.plotly_chart(fig, use_container_width=True)582            583            correlation = df[feature1].corr(df[feature2])584            st.metric("Correlation", f"{correlation:.4f}")585    586    elif analysis_type == "Failure Type Breakdown":587        st.subheader("Detailed Failure Type Analysis")588        589        failure_types = {590            'TWF': 'Tool Wear Failure',591            'HDF': 'Heat Dissipation Failure',592            'PWF': 'Power Failure',593            'OSF': 'Overstrain Failure',594            'RNF': 'Random Failure'595        }596        597        for ft_code, ft_name in failure_types.items():598            with st.expander(f"{ft_name} ({ft_code})"):599                failed_machines = df[df[ft_code] == 1]600                if len(failed_machines) > 0:601                    st.metric("Count", len(failed_machines))602                    col1, col2, col3 = st.columns(3)603                    with col1:604                        st.metric("Avg Tool Wear", f"{failed_machines['Tool wear [min]'].mean():.2f} min")605                    with col2:606                        st.metric("Avg Temp Diff", f"{failed_machines['Temperature difference [K]'].mean():.2f} K")607                    with col3:608                        st.metric("Avg Rotational Speed", f"{failed_machines['Rotational speed [rpm]'].mean():.0f} rpm")609    610    elif analysis_type == "Time to Failure Estimation":611        st.subheader("Time to Failure Estimation")612        613        # Analyze tool wear progression for machines that failed614        failed_machines = df[df['Machine failure'] == 1]615        616        if len(failed_machines) > 0:617            avg_tool_wear_at_failure = failed_machines['Tool wear [min]'].mean()618            median_tool_wear_at_failure = failed_machines['Tool wear [min]'].median()619            620            col1, col2 = st.columns(2)621            with col1:622                st.metric("Average Tool Wear at Failure", f"{avg_tool_wear_at_failure:.2f} minutes")623            with col2:624                st.metric("Median Tool Wear at Failure", f"{median_tool_wear_at_failure:.2f} minutes")625            626            # Estimate time remaining for machines not yet failed627            non_failed = df[df['Machine failure'] == 0].copy()628            if len(non_failed) > 0:629                non_failed['Estimated Time to Failure'] = (630                    avg_tool_wear_at_failure - non_failed['Tool wear [min]']631                )632                non_failed['Estimated Time to Failure'] = non_failed['Estimated Time to Failure'].clip(lower=0)633                634                st.subheader("Time to Failure Estimates (for non-failed machines)")635                636                immediate = (non_failed['Estimated Time to Failure'] < 10).sum()637                soon = ((non_failed['Estimated Time to Failure'] >= 10) & 638                       (non_failed['Estimated Time to Failure'] < 50)).sum()639                remaining = (non_failed['Estimated Time to Failure'] >= 50).sum()640                641                col1, col2, col3 = st.columns(3)642                with col1:643                    st.metric("Immediate Maintenance (< 10 min)", f"{immediate:,}")644                with col2:645                    st.metric("Maintenance Soon (10-50 min)", f"{soon:,}")646                with col3:647                    st.metric("Time Remaining (> 50 min)", f"{remaining:,}")648                649                # Distribution chart650                fig = px.histogram(651                    non_failed,652                    x='Estimated Time to Failure',653                    nbins=50,654                    title="Distribution of Estimated Time to Failure",655                    color_discrete_sequence=['#3498db']656                )657                st.plotly_chart(fig, use_container_width=True)658    659    elif analysis_type == "Grouped Aggregations":660        st.subheader("Grouped Aggregations by Type and Failure Status")661        662        grouped = df.groupby(['Type', 'Machine failure']).agg({663            'Tool wear [min]': ['mean', 'std', 'max'],664            'Temperature difference [K]': ['mean', 'std'],665            'Rotational speed [rpm]': ['mean', 'std'],666            'Torque [Nm]': ['mean', 'std']667        })668        669        st.dataframe(grouped, use_container_width=True)670        671        # Visualizations672        st.subheader("Tool Wear by Type and Failure Status")673        fig = px.box(674            df,675            x='Type',676            y='Tool wear [min]',677            color='Machine failure',678            title="Tool Wear Distribution by Type and Failure Status",679            color_discrete_sequence=['#2ecc71', '#e74c3c']680        )681        st.plotly_chart(fig, use_container_width=True)682        683        st.subheader("Temperature Difference by Type and Failure Status")684        fig = px.box(685            df,686            x='Type',687            y='Temperature difference [K]',688            color='Machine failure',689            title="Temperature Difference by Type and Failure Status",690            color_discrete_sequence=['#2ecc71', '#e74c3c']691        )692        st.plotly_chart(fig, use_container_width=True)693 694def show_model_predictions(df):695    """Model and predictions page"""696    st.markdown('<h2 class="sub-header">๐Ÿค– Machine Learning Model & Predictions</h2>', unsafe_allow_html=True)697    698    # Train model section699    if st.session_state.model is None:700        st.info("โš ๏ธ Model not trained yet. Click the button below to train the model.")701        if st.button("Train Model", type="primary"):702            results = train_model()703            st.success("โœ… Model trained successfully!")704            st.session_state.model_results = results705    706    if st.session_state.model is not None:707        model = st.session_state.model708        preprocessor = st.session_state.preprocessor709        710        # Model performance section711        st.subheader("Model Performance")712        713        if 'model_results' in st.session_state:714            results = st.session_state.model_results715            col1, col2, col3, col4 = st.columns(4)716            with col1:717                st.metric("Accuracy", f"{results['accuracy']:.4f}")718            with col2:719                st.metric("Precision", f"{results['precision']:.4f}")720            with col3:721                st.metric("Recall", f"{results['recall']:.4f}")722            with col4:723                st.metric("F1-Score", f"{results['f1_score']:.4f}")724        725        # Feature importance726        st.subheader("Feature Importance")727        feature_importance = model.get_feature_importance()728        fig = px.bar(729            feature_importance,730            x='importance',731            y='feature',732            orientation='h',733            title="Feature Importance",734            color='importance',735            color_continuous_scale="Viridis"736        )737        st.plotly_chart(fig, use_container_width=True)738        739        st.markdown("---")740        741        # Runtime prediction section742        st.subheader("๐Ÿ”ฎ Runtime Prediction - Predict Maintenance Needs")743        st.markdown("Enter machine parameters below to predict if maintenance is needed:")744        745        col1, col2 = st.columns(2)746        747        with col1:748            machine_type = st.selectbox(749                "Machine Type", 750                ['L', 'M', 'H'],751                format_func=lambda x: f"{x} ({'Low Quality/Load' if x == 'L' else 'Medium Quality/Load' if x == 'M' else 'High Quality/Load'})"752            )753            air_temp = st.slider("Air Temperature (K)", 754                                min_value=295.0, max_value=305.0, value=298.0, step=0.1)755            process_temp = st.slider("Process Temperature (K)",756                                    min_value=305.0, max_value=315.0, value=309.0, step=0.1)757        758        with col2:759            rotational_speed = st.slider("Rotational Speed (rpm)",760                                        min_value=1000, max_value=3000, value=1500, step=10)761            torque = st.slider("Torque (Nm)",762                             min_value=10.0, max_value=80.0, value=40.0, step=0.1)763            tool_wear = st.slider("Tool Wear (minutes)",764                                min_value=0, max_value=300, value=50, step=1)765        766        if st.button("Predict Maintenance Status", type="primary"):767            # Create input data768            input_data = pd.DataFrame({769                'Type': [machine_type],770                'Air temperature [K]': [air_temp],771                'Process temperature [K]': [process_temp],772                'Rotational speed [rpm]': [rotational_speed],773                'Torque [Nm]': [torque],774                'Tool wear [min]': [tool_wear]775            })776            777            # Preprocess778            X_new = preprocessor.preprocess_new_data(input_data)779            780            # Predict781            maintenance_pred = model.predict_maintenance(X_new, tool_wear_values=[tool_wear])782            783            # Display results784            st.markdown("### Prediction Results")785            786            failure_prob = maintenance_pred['Failure_Probability'].iloc[0]787            time_to_failure = maintenance_pred['Time_to_Failure_Minutes'].iloc[0]788            status = maintenance_pred['Maintenance_Status'].iloc[0]789            urgency = maintenance_pred['Maintenance_Urgency'].iloc[0]790            791            # Color coding792            if urgency == "CRITICAL":793                st.error(f"๐Ÿšจ **{status}**")794            elif urgency == "HIGH":795                st.warning(f"โš ๏ธ **{status}**")796            elif urgency == "MEDIUM":797                st.info(f"โ„น๏ธ **{status}**")798            else:799                st.success(f"โœ… **{status}**")800            801            col1, col2, col3 = st.columns(3)802            with col1:803                st.metric("Failure Probability", f"{failure_prob:.2%}")804            with col2:805                st.metric("Estimated Time to Maintenance", f"{time_to_failure:.1f} minutes")806                if time_to_failure > 0:807                    st.caption(f"Based on historical data: avg failure at 120 min tool wear")808                else:809                    st.caption("Tool wear exceeded average failure threshold (120 min)")810            with col3:811                st.metric("Maintenance Urgency", urgency)812            813            # Detailed information814            with st.expander("View Detailed Information"):815                st.markdown(f"""816                **Machine Parameters:**817                - Type: {machine_type} ({'Low Quality/Load' if machine_type == 'L' else 'Medium Quality/Load' if machine_type == 'M' else 'High Quality/Load'})818                - Air Temperature: {air_temp} K819                - Process Temperature: {process_temp} K820                - Rotational Speed: {rotational_speed} rpm821                - Torque: {torque} Nm822                - Tool Wear: {tool_wear} minutes823                824                **Prediction Details:**825                - Failure Predicted: {'Yes' if maintenance_pred['Failure_Predicted'].iloc[0] == 1 else 'No'}826                - Failure Probability: {failure_prob:.2%}827                - Estimated Time to Maintenance: {time_to_failure:.1f} minutes828                  *Based on historical analysis: Machines in this dataset typically require maintenance when tool wear reaches approximately 120 minutes. 829                  This estimate projects when your machine will reach that threshold based on current tool wear level.*830                - Maintenance Status: {status}831                - Urgency Level: {urgency}832                833                **Recommendation:**834                {get_maintenance_recommendation(urgency, time_to_failure, failure_prob)}835                """)836        837        st.markdown("---")838        839        # Batch prediction section840        st.subheader("Batch Prediction")841        st.markdown("Upload a CSV file with machine data for batch predictions:")842        843        uploaded_file = st.file_uploader("Choose a CSV file", type="csv")844        845        if uploaded_file is not None:846            try:847                batch_data = pd.read_csv(uploaded_file)848                st.dataframe(batch_data.head(), use_container_width=True)849                850                if st.button("Predict for Batch", type="primary"):851                    # Check required columns852                    required_cols = ['Type', 'Air temperature [K]', 'Process temperature [K]',853                                    'Rotational speed [rpm]', 'Torque [Nm]', 'Tool wear [min]']854                    855                    if all(col in batch_data.columns for col in required_cols):856                        X_batch = preprocessor.preprocess_new_data(batch_data)857                        tool_wear_batch = batch_data['Tool wear [min]'].values858                        batch_predictions = model.predict_maintenance(X_batch, tool_wear_batch)859                        860                        # Combine with original data861                        results_df = pd.concat([batch_data, batch_predictions], axis=1)862                        863                        st.success("โœ… Batch prediction complete!")864                        st.dataframe(results_df, use_container_width=True)865                        866                        # Summary statistics867                        st.subheader("Batch Prediction Summary")868                        col1, col2, col3, col4 = st.columns(4)869                        with col1:870                            st.metric("Total Machines", len(batch_data))871                        with col2:872                            st.metric("Critical Maintenance", 873                                    (batch_predictions['Maintenance_Urgency'] == 'CRITICAL').sum())874                        with col3:875                            st.metric("High Priority", 876                                    (batch_predictions['Maintenance_Urgency'] == 'HIGH').sum())877                        with col4:878                            st.metric("Average Time to Failure", 879                                    f"{batch_predictions['Time_to_Failure_Minutes'].mean():.1f} min")880                    else:881                        st.error(f"CSV must contain these columns: {', '.join(required_cols)}")882            except Exception as e:883                st.error(f"Error processing file: {str(e)}")884 885def get_maintenance_recommendation(urgency, time_to_failure, failure_prob):886    """Get maintenance recommendation based on prediction"""887    if urgency == "CRITICAL":888        return "**IMMEDIATE ACTION REQUIRED**: Stop the machine immediately and perform maintenance. Failure is imminent."889    elif urgency == "HIGH":890        if time_to_failure < 60:891            return f"**URGENT**: Schedule maintenance within {int(time_to_failure/60)} hour(s) or immediately if possible. The machine shows high risk of failure."892        else:893            return f"**Schedule maintenance within {int(time_to_failure/60)} hours**. The machine shows high risk of failure."894    elif urgency == "MEDIUM":895        if time_to_failure < 20:896            return f"**Schedule maintenance within the next 20-30 minutes**. Monitor the machine very closely. Estimated time to maintenance: {time_to_failure:.0f} minutes."897        elif time_to_failure < 60:898            return f"**Schedule maintenance within the next hour**. Monitor the machine closely. Estimated time to maintenance: {time_to_failure:.0f} minutes."899        elif time_to_failure < 120:900            return f"**Plan maintenance within the next 2 hours**. Monitor the machine closely. Estimated time to maintenance: {int(time_to_failure/60)} hours."901        else:902            return f"**Plan maintenance within the next few days**. Monitor the machine regularly. Estimated time to maintenance: {int(time_to_failure/60)} hours."903    else:904        if time_to_failure < 120:905            return f"**Monitor regularly**. No immediate action needed, but plan maintenance soon. Estimated time to maintenance: {int(time_to_failure/60)} hours."906        else:907            return f"**No immediate action needed**. Continue regular monitoring. Estimated time to maintenance: {int(time_to_failure/60)} hours."908 909def show_conclusion():910    """Conclusion page"""911    st.markdown('<h2 class="sub-header">๐Ÿ“ Conclusion & Key Takeaways</h2>', unsafe_allow_html=True)912    913    st.markdown("""914    ### Project Summary915    916    This predictive maintenance project successfully analyzed the AI4I 2020 dataset and built 917    a machine learning model to predict machine failures and estimate maintenance needs.918    919    ### Key Findings920    921    1. **Dataset Characteristics**:922       - The dataset contains 10,000 machine records with 14 features923       - Machine failure rate is approximately 3.39% (imbalanced dataset)924       - Five different failure types were identified: TWF, HDF, PWF, OSF, and RNF925    926    2. **Important Features**:927       - Tool wear is a critical indicator of machine health928       - Temperature difference between process and air temperature correlates with failures929       - Machine type (L = Low Quality/Load, M = Medium Quality/Load, H = High Quality/Load) affects failure rates differently930       - Rotational speed and torque relationships are important predictors931    932    3. **Model Performance**:933       - Random Forest Classifier achieved good performance on the imbalanced dataset934       - The model can effectively predict machine failures935       - Feature importance analysis revealed tool wear and temperature as key predictors936    937    4. **Maintenance Insights**:938       - Machines with tool wear > 100 minutes are at higher risk939       - Temperature differences > 10K indicate potential heat dissipation issues940       - Early detection can prevent costly downtime941    942    ### Applications943    944    This system can be used in real-world industrial settings to:945    - **Prevent unexpected failures** by predicting maintenance needs946    - **Optimize maintenance schedules** based on actual machine conditions947    - **Reduce downtime** through proactive maintenance948    - **Save costs** by avoiding catastrophic failures949    950    ### Future Improvements951    952    1. **Model Enhancement**:953       - Try ensemble methods (XGBoost, LightGBM)954       - Implement time-series analysis for sequential data955       - Add anomaly detection algorithms956    957    2. **Feature Engineering**:958       - Create more domain-specific features959       - Include historical maintenance records960       - Add environmental factors961    962    3. **System Integration**:963       - Real-time data streaming964       - Integration with IoT sensors965       - Automated alert system966    967    ### Technical Stack968    969    - **Data Analysis**: Pandas, NumPy970    - **Visualization**: Matplotlib, Seaborn, Plotly971    - **Machine Learning**: Scikit-learn (Random Forest)972    - **Web Application**: Streamlit973    - **Preprocessing**: StandardScaler, LabelEncoder974    975    ### Acknowledgments976    977    Dataset: AI4I 2020 Predictive Maintenance Dataset978    979    ---980    981    **Project completed for Introduction to Data Science Course (IDS F24)**982    """)983    984    st.markdown("---")985    st.markdown("### Thank you for using the Predictive Maintenance System! ๐Ÿ”ง")986 987if __name__ == "__main__":988    main()989 990