ahadalii/Predictive_Maintenance_System
0
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 