File size: 17,045 Bytes
0b794cc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | """
Comprehensive Exploratory Data Analysis (EDA) for AI4I 2020 Predictive Maintenance Dataset
This script performs 10-15 different analyses as required for the project.
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
# Set style for better visualizations
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = (12, 6)
class EDAAnalysis:
def __init__(self, data_path='ai4i2020.csv'):
"""Initialize the EDA analysis class"""
self.df = pd.read_csv(data_path)
self.prepare_data()
def prepare_data(self):
"""Prepare data for analysis"""
# Create a copy for analysis
self.df_clean = self.df.copy()
# Calculate temperature difference (important feature)
self.df_clean['Temperature difference [K]'] = (
self.df_clean['Process temperature [K]'] -
self.df_clean['Air temperature [K]']
)
# Calculate power (Rotational speed * Torque)
self.df_clean['Power [W]'] = (
self.df_clean['Rotational speed [rpm]'] *
self.df_clean['Torque [Nm]'] / 9.5488 # Conversion factor
)
# Failure type names
self.failure_types = {
'TWF': 'Tool Wear Failure',
'HDF': 'Heat Dissipation Failure',
'PWF': 'Power Failure',
'OSF': 'Overstrain Failure',
'RNF': 'Random Failure'
}
def analysis_1_summary_statistics(self):
"""Analysis 1: Summary statistics for numerical features"""
print("="*80)
print("ANALYSIS 1: SUMMARY STATISTICS")
print("="*80)
numerical_cols = [
'Air temperature [K]', 'Process temperature [K]',
'Rotational speed [rpm]', 'Torque [Nm]', 'Tool wear [min]',
'Temperature difference [K]', 'Power [W]'
]
summary = self.df_clean[numerical_cols].describe()
print(summary)
print("\n")
return summary
def analysis_2_missing_values(self):
"""Analysis 2: Missing value analysis"""
print("="*80)
print("ANALYSIS 2: MISSING VALUE ANALYSIS")
print("="*80)
missing = self.df_clean.isnull().sum()
missing_pct = (missing / len(self.df_clean)) * 100
missing_df = pd.DataFrame({
'Missing Count': missing,
'Missing Percentage': missing_pct
})
missing_df = missing_df[missing_df['Missing Count'] > 0]
if len(missing_df) == 0:
print("✓ No missing values found in the dataset!")
else:
print(missing_df)
print("\n")
return missing_df
def analysis_3_data_types(self):
"""Analysis 3: Data types and unique value counts"""
print("="*80)
print("ANALYSIS 3: DATA TYPES AND UNIQUE VALUES")
print("="*80)
info_df = pd.DataFrame({
'Column': self.df_clean.columns,
'Data Type': self.df_clean.dtypes,
'Unique Values': [self.df_clean[col].nunique() for col in self.df_clean.columns],
'Non-Null Count': self.df_clean.count().values
})
print(info_df.to_string(index=False))
print("\n")
# Categorical value counts
print("Type Distribution:")
print(self.df_clean['Type'].value_counts())
print("\n")
return info_df
def analysis_4_target_distribution(self):
"""Analysis 4: Target variable (Machine failure) distribution"""
print("="*80)
print("ANALYSIS 4: TARGET VARIABLE DISTRIBUTION")
print("="*80)
failure_counts = self.df_clean['Machine failure'].value_counts()
failure_pct = self.df_clean['Machine failure'].value_counts(normalize=True) * 100
print("Machine Failure Distribution:")
print(f" No Failure (0): {failure_counts[0]} ({failure_pct[0]:.2f}%)")
print(f" Failure (1): {failure_counts[1]} ({failure_pct[1]:.2f}%)")
print("\n")
# Failure types breakdown
print("Failure Types Breakdown:")
for ft in ['TWF', 'HDF', 'PWF', 'OSF', 'RNF']:
count = self.df_clean[ft].sum()
pct = (count / len(self.df_clean)) * 100
print(f" {self.failure_types[ft]}: {count} ({pct:.2f}%)")
print("\n")
return failure_counts
def analysis_5_correlation_analysis(self):
"""Analysis 5: Correlation analysis"""
print("="*80)
print("ANALYSIS 5: CORRELATION ANALYSIS")
print("="*80)
numerical_cols = [
'Air temperature [K]', 'Process temperature [K]',
'Rotational speed [rpm]', 'Torque [Nm]', 'Tool wear [min]',
'Temperature difference [K]', 'Power [W]', 'Machine failure'
]
corr_matrix = self.df_clean[numerical_cols].corr()
print("Correlation with Machine Failure:")
failure_corr = corr_matrix['Machine failure'].sort_values(ascending=False)
print(failure_corr)
print("\n")
return corr_matrix
def analysis_6_outlier_detection(self):
"""Analysis 6: Outlier detection using IQR method"""
print("="*80)
print("ANALYSIS 6: OUTLIER DETECTION (IQR METHOD)")
print("="*80)
numerical_cols = [
'Air temperature [K]', 'Process temperature [K]',
'Rotational speed [rpm]', 'Torque [Nm]', 'Tool wear [min]'
]
outlier_summary = {}
for col in numerical_cols:
Q1 = self.df_clean[col].quantile(0.25)
Q3 = self.df_clean[col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = self.df_clean[(self.df_clean[col] < lower_bound) |
(self.df_clean[col] > upper_bound)]
outlier_count = len(outliers)
outlier_pct = (outlier_count / len(self.df_clean)) * 100
outlier_summary[col] = {
'Lower Bound': lower_bound,
'Upper Bound': upper_bound,
'Outlier Count': outlier_count,
'Outlier Percentage': outlier_pct
}
print(f"{col}:")
print(f" Bounds: [{lower_bound:.2f}, {upper_bound:.2f}]")
print(f" Outliers: {outlier_count} ({outlier_pct:.2f}%)")
print("\n")
return outlier_summary
def analysis_7_feature_distributions(self):
"""Analysis 7: Feature distribution analysis"""
print("="*80)
print("ANALYSIS 7: FEATURE DISTRIBUTION ANALYSIS")
print("="*80)
numerical_cols = [
'Air temperature [K]', 'Process temperature [K]',
'Rotational speed [rpm]', 'Torque [Nm]', 'Tool wear [min]'
]
dist_stats = {}
for col in numerical_cols:
dist_stats[col] = {
'Mean': self.df_clean[col].mean(),
'Median': self.df_clean[col].median(),
'Mode': self.df_clean[col].mode()[0] if len(self.df_clean[col].mode()) > 0 else None,
'Std': self.df_clean[col].std(),
'Skewness': self.df_clean[col].skew(),
'Kurtosis': self.df_clean[col].kurtosis()
}
print(f"{col}:")
print(f" Mean: {dist_stats[col]['Mean']:.2f}")
print(f" Median: {dist_stats[col]['Median']:.2f}")
print(f" Std Dev: {dist_stats[col]['Std']:.2f}")
print(f" Skewness: {dist_stats[col]['Skewness']:.2f}")
print(f" Kurtosis: {dist_stats[col]['Kurtosis']:.2f}")
print()
print("\n")
return dist_stats
def analysis_8_failure_by_type(self):
"""Analysis 8: Failure analysis by machine type"""
print("="*80)
print("ANALYSIS 8: FAILURE ANALYSIS BY MACHINE TYPE")
print("="*80)
failure_by_type = self.df_clean.groupby('Type')['Machine failure'].agg([
'count', 'sum', 'mean'
]).round(4)
failure_by_type.columns = ['Total Machines', 'Failures', 'Failure Rate']
failure_by_type['Failure Rate'] = failure_by_type['Failure Rate'] * 100
print(failure_by_type)
print("\n")
return failure_by_type
def analysis_9_tool_wear_analysis(self):
"""Analysis 9: Tool wear analysis and relationship with failures"""
print("="*80)
print("ANALYSIS 9: TOOL WEAR ANALYSIS")
print("="*80)
print("Tool Wear Statistics:")
print(f" Mean: {self.df_clean['Tool wear [min]'].mean():.2f} minutes")
print(f" Median: {self.df_clean['Tool wear [min]'].median():.2f} minutes")
print(f" Max: {self.df_clean['Tool wear [min]'].max():.2f} minutes")
print(f" Min: {self.df_clean['Tool wear [min]'].min():.2f} minutes")
print()
# Tool wear vs failure
tool_wear_failure = self.df_clean.groupby('Machine failure')['Tool wear [min]'].agg([
'mean', 'median', 'std', 'min', 'max'
])
print("Tool Wear by Failure Status:")
print(tool_wear_failure)
print("\n")
return tool_wear_failure
def analysis_10_temperature_analysis(self):
"""Analysis 10: Temperature analysis"""
print("="*80)
print("ANALYSIS 10: TEMPERATURE ANALYSIS")
print("="*80)
temp_stats = self.df_clean.groupby('Machine failure')[
['Air temperature [K]', 'Process temperature [K]', 'Temperature difference [K]']
].agg(['mean', 'std'])
print("Temperature Statistics by Failure Status:")
print(temp_stats)
print("\n")
return temp_stats
def analysis_11_power_analysis(self):
"""Analysis 11: Power and rotational speed analysis"""
print("="*80)
print("ANALYSIS 11: POWER AND ROTATIONAL SPEED ANALYSIS")
print("="*80)
power_stats = self.df_clean.groupby('Machine failure')[
['Rotational speed [rpm]', 'Torque [Nm]', 'Power [W]']
].agg(['mean', 'std', 'min', 'max'])
print("Power Statistics by Failure Status:")
print(power_stats)
print("\n")
return power_stats
def analysis_12_pairwise_relationships(self):
"""Analysis 12: Pairwise feature relationships"""
print("="*80)
print("ANALYSIS 12: PAIRWISE FEATURE RELATIONSHIPS")
print("="*80)
key_features = [
'Tool wear [min]', 'Temperature difference [K]',
'Rotational speed [rpm]', 'Torque [Nm]', 'Machine failure'
]
pairwise_corr = self.df_clean[key_features].corr()
print("Pairwise Correlations:")
print(pairwise_corr)
print("\n")
return pairwise_corr
def analysis_13_failure_type_analysis(self):
"""Analysis 13: Detailed failure type analysis"""
print("="*80)
print("ANALYSIS 13: DETAILED FAILURE TYPE ANALYSIS")
print("="*80)
failure_types = ['TWF', 'HDF', 'PWF', 'OSF', 'RNF']
for ft in failure_types:
failed_machines = self.df_clean[self.df_clean[ft] == 1]
if len(failed_machines) > 0:
print(f"\n{self.failure_types[ft]} ({ft}):")
print(f" Count: {len(failed_machines)}")
print(f" Avg Tool Wear: {failed_machines['Tool wear [min]'].mean():.2f} min")
print(f" Avg Temp Diff: {failed_machines['Temperature difference [K]'].mean():.2f} K")
print(f" Avg Rotational Speed: {failed_machines['Rotational speed [rpm]'].mean():.2f} rpm")
print(f" Avg Torque: {failed_machines['Torque [Nm]'].mean():.2f} Nm")
print("\n")
def analysis_14_time_to_failure_estimation(self):
"""Analysis 14: Time to failure estimation based on tool wear"""
print("="*80)
print("ANALYSIS 14: TIME TO FAILURE ESTIMATION")
print("="*80)
# Analyze tool wear progression for machines that failed
failed_machines = self.df_clean[self.df_clean['Machine failure'] == 1]
if len(failed_machines) > 0:
avg_tool_wear_at_failure = failed_machines['Tool wear [min]'].mean()
median_tool_wear_at_failure = failed_machines['Tool wear [min]'].median()
print(f"Average Tool Wear at Failure: {avg_tool_wear_at_failure:.2f} minutes")
print(f"Median Tool Wear at Failure: {median_tool_wear_at_failure:.2f} minutes")
print()
# Estimate time remaining for machines not yet failed
non_failed = self.df_clean[self.df_clean['Machine failure'] == 0]
if len(non_failed) > 0:
non_failed['Estimated Time to Failure'] = (
avg_tool_wear_at_failure - non_failed['Tool wear [min]']
)
non_failed['Estimated Time to Failure'] = non_failed['Estimated Time to Failure'].clip(lower=0)
print("Time to Failure Estimates (for non-failed machines):")
print(f" Machines needing immediate maintenance (< 10 min): "
f"{(non_failed['Estimated Time to Failure'] < 10).sum()}")
print(f" Machines needing maintenance soon (10-50 min): "
f"{((non_failed['Estimated Time to Failure'] >= 10) & (non_failed['Estimated Time to Failure'] < 50)).sum()}")
print(f" Machines with time remaining (> 50 min): "
f"{(non_failed['Estimated Time to Failure'] >= 50).sum()}")
print("\n")
def analysis_15_grouped_aggregations(self):
"""Analysis 15: Grouped aggregations by type and failure status"""
print("="*80)
print("ANALYSIS 15: GROUPED AGGREGATIONS")
print("="*80)
grouped = self.df_clean.groupby(['Type', 'Machine failure']).agg({
'Tool wear [min]': ['mean', 'std', 'max'],
'Temperature difference [K]': ['mean', 'std'],
'Rotational speed [rpm]': ['mean', 'std'],
'Torque [Nm]': ['mean', 'std']
})
print("Grouped Statistics by Type and Failure Status:")
print(grouped)
print("\n")
return grouped
def run_all_analyses(self):
"""Run all EDA analyses"""
print("\n" + "="*80)
print("COMPREHENSIVE EXPLORATORY DATA ANALYSIS")
print("AI4I 2020 Predictive Maintenance Dataset")
print("="*80 + "\n")
results = {}
results['summary_stats'] = self.analysis_1_summary_statistics()
results['missing_values'] = self.analysis_2_missing_values()
results['data_types'] = self.analysis_3_data_types()
results['target_distribution'] = self.analysis_4_target_distribution()
results['correlation'] = self.analysis_5_correlation_analysis()
results['outliers'] = self.analysis_6_outlier_detection()
results['distributions'] = self.analysis_7_feature_distributions()
results['failure_by_type'] = self.analysis_8_failure_by_type()
results['tool_wear'] = self.analysis_9_tool_wear_analysis()
results['temperature'] = self.analysis_10_temperature_analysis()
results['power'] = self.analysis_11_power_analysis()
results['pairwise'] = self.analysis_12_pairwise_relationships()
self.analysis_13_failure_type_analysis()
self.analysis_14_time_to_failure_estimation()
results['grouped'] = self.analysis_15_grouped_aggregations()
print("="*80)
print("EDA ANALYSIS COMPLETE!")
print("="*80)
return results
if __name__ == "__main__":
# Run EDA analysis
eda = EDAAnalysis('ai4i2020.csv')
results = eda.run_all_analyses()
# Save processed data for modeling
eda.df_clean.to_csv('processed_data.csv', index=False)
print("\nProcessed data saved to 'processed_data.csv'") |