190 lines
6.1 KiB
Python
190 lines
6.1 KiB
Python
import os
|
|
import numpy as np
|
|
import pandas as pd
|
|
from sklearn.model_selection import train_test_split
|
|
from sklearn.neighbors import KNeighborsClassifier
|
|
from sklearn.preprocessing import StandardScaler, LabelEncoder
|
|
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
|
|
import joblib
|
|
|
|
from utils.helpers import prepare_dataset, save_model, analyze_features
|
|
from utils.feature_extraction import FeatureExtractor
|
|
|
|
def train_knn_model(data_dir='dataset', test_size=0.2, random_state=42):
|
|
"""
|
|
Train KNN model for PMK detection
|
|
"""
|
|
print("=" * 50)
|
|
print("TRAINING MODEL DETEKSI PMK PADA SAPI")
|
|
print("=" * 50)
|
|
|
|
# 1. Prepare dataset
|
|
print("\n1. MENYIAPKAN DATASET...")
|
|
features, labels, image_paths = prepare_dataset(data_dir)
|
|
|
|
print(f"\nJumlah total sampel: {len(features)}")
|
|
print("Distribusi kelas:")
|
|
unique, counts = np.unique(labels, return_counts=True)
|
|
for cls, count in zip(unique, counts):
|
|
print(f" {cls}: {count} gambar")
|
|
|
|
# 2. Encode labels
|
|
print("\n2. ENCODING LABELS...")
|
|
label_encoder = LabelEncoder()
|
|
labels_encoded = label_encoder.fit_transform(labels)
|
|
|
|
# 3. Split dataset
|
|
print("\n3. MEMBAGI DATASET...")
|
|
X_train, X_test, y_train, y_test = train_test_split(
|
|
features, labels_encoded,
|
|
test_size=test_size,
|
|
random_state=random_state,
|
|
stratify=labels_encoded
|
|
)
|
|
|
|
print(f"Training samples: {X_train.shape[0]}")
|
|
print(f"Testing samples: {X_test.shape[0]}")
|
|
|
|
# 4. Feature scaling
|
|
print("\n4. SCALING FEATURES...")
|
|
scaler = StandardScaler()
|
|
X_train_scaled = scaler.fit_transform(X_train)
|
|
X_test_scaled = scaler.transform(X_test)
|
|
|
|
# 5. Train KNN model
|
|
print("\n5. TRAINING KNN MODEL...")
|
|
knn = KNeighborsClassifier(
|
|
n_neighbors=5,
|
|
weights='distance',
|
|
metric='euclidean',
|
|
n_jobs=-1
|
|
)
|
|
|
|
knn.fit(X_train_scaled, y_train)
|
|
|
|
# 6. Evaluate model
|
|
print("\n6. EVALUASI MODEL...")
|
|
y_pred = knn.predict(X_test_scaled)
|
|
accuracy = accuracy_score(y_test, y_pred)
|
|
|
|
print("\n" + "=" * 50)
|
|
print("HASIL EVALUASI")
|
|
print("=" * 50)
|
|
print(f"\nAkurasi Model: {accuracy:.2%}")
|
|
|
|
print("\nClassification Report:")
|
|
print(classification_report(y_test, y_pred,
|
|
target_names=label_encoder.classes_))
|
|
|
|
print("Confusion Matrix:")
|
|
cm = confusion_matrix(y_test, y_pred)
|
|
print(cm)
|
|
|
|
# Calculate precision, recall, F1-score
|
|
tn, fp, fn, tp = cm.ravel()
|
|
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
|
|
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
|
|
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0
|
|
|
|
print(f"\nPrecision: {precision:.2%}")
|
|
print(f"Recall: {recall:.2%}")
|
|
print(f"F1-Score: {f1:.2%}")
|
|
|
|
# 7. Save model
|
|
print("\n7. MENYIMPAN MODEL...")
|
|
save_model(knn, scaler, label_encoder)
|
|
|
|
# 8. Save features to separate CSV files
|
|
print("\n8. MENYIMPAN FITUR KE CSV...")
|
|
extractor = FeatureExtractor()
|
|
os.makedirs('features', exist_ok=True)
|
|
|
|
# Separate features by class
|
|
healthy_features = []
|
|
sick_features = []
|
|
|
|
for feat, label in zip(features, labels):
|
|
if label == 'sehat':
|
|
healthy_features.append(feat)
|
|
else:
|
|
sick_features.append(feat)
|
|
|
|
# Save to CSV
|
|
if healthy_features:
|
|
df_healthy = extractor.save_features_to_csv(
|
|
healthy_features,
|
|
['sehat'] * len(healthy_features),
|
|
'features/features_healthy.csv'
|
|
)
|
|
print(f" Fitur sehat: {len(df_healthy)} sampel")
|
|
|
|
if sick_features:
|
|
df_sick = extractor.save_features_to_csv(
|
|
sick_features,
|
|
['sakit'] * len(sick_features),
|
|
'features/features_sick.csv'
|
|
)
|
|
print(f" Fitur sakit: {len(df_sick)} sampel")
|
|
|
|
# Save all features
|
|
all_features_df = pd.DataFrame(features, columns=extractor.feature_names)
|
|
all_features_df['label'] = labels
|
|
all_features_df.to_csv('features/all_features.csv', index=False)
|
|
|
|
# 9. Analyze features
|
|
print("\n9. ANALISIS FITUR...")
|
|
analyze_features()
|
|
|
|
# Calculate feature statistics
|
|
print("\nRATA-RATA FITUR PER KELAS:")
|
|
stats = all_features_df.groupby('label').mean()
|
|
print(stats)
|
|
|
|
# Save model performance
|
|
performance = {
|
|
'accuracy': accuracy,
|
|
'precision': precision,
|
|
'recall': recall,
|
|
'f1_score': f1,
|
|
'training_samples': X_train.shape[0],
|
|
'testing_samples': X_test.shape[0]
|
|
}
|
|
|
|
perf_df = pd.DataFrame([performance])
|
|
perf_df.to_csv('results/model_performance.csv', index=False)
|
|
|
|
print("\n" + "=" * 50)
|
|
print("TRAINING SELESAI!")
|
|
print("=" * 50)
|
|
print(f"\nAkurasi model: {accuracy:.2%}")
|
|
print("Model disimpan di: models/knn_model.pkl")
|
|
print("Fitur disimpan di: features/")
|
|
print("Hasil analisis di: results/")
|
|
|
|
return knn, scaler, label_encoder, accuracy
|
|
|
|
if __name__ == "__main__":
|
|
# Check dataset structure
|
|
if not os.path.exists('dataset'):
|
|
print("ERROR: Folder 'dataset' tidak ditemukan!")
|
|
print("\nBuat struktur folder berikut:")
|
|
print("pmk_detection_desktop/")
|
|
print("├── dataset/")
|
|
print("│ ├── healthy/ (isi dengan gambar sapi sehat)")
|
|
print("│ └── sick/ (isi dengan gambar sapi sakit)")
|
|
print("└── ...")
|
|
|
|
# Create directories
|
|
os.makedirs('dataset/healthy', exist_ok=True)
|
|
os.makedirs('dataset/sick', exist_ok=True)
|
|
os.makedirs('features', exist_ok=True)
|
|
os.makedirs('models', exist_ok=True)
|
|
os.makedirs('results', exist_ok=True)
|
|
|
|
print("\nFolder telah dibuat. Silakan tambahkan gambar ke:")
|
|
print(" - dataset/healthy/ untuk gambar sapi sehat")
|
|
print(" - dataset/sick/ untuk gambar sapi sakit")
|
|
print("\nKemudian jalankan script ini kembali.")
|
|
else:
|
|
# Train model
|
|
model, scaler, label_encoder, accuracy = train_knn_model() |