التجميع: اكتشاف أنماط مخفية في بيانات خط الإنتاج
ما هو التعلم غير المُشرف؟
في التعلم المُشرف، نعطي النموذج أمثلة مُصنَّفة مسبقاً (سليم/معيب). في التعلم غير المُشرف، لا توجد تصنيفات: النموذج يكتشف الأنماط بنفسه.
تطبيقات صناعية للتجميع
- اكتشاف أنماط تشغيل مختلفة للمعدات
- تقسيم المنتجات إلى فئات جودة تلقائياً
- تحديد مجموعات العملاء حسب أنماط الاستهلاك
- كشف حالات تشغيل غير معروفة مسبقاً
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# محاكاة بيانات تشغيل مضخة صناعية بثلاثة أنماط
np.random.seed(42)
# النمط 1: تشغيل عادي
normal = np.column_stack([
np.random.normal(50, 3, 200), # معدل تدفق
np.random.normal(30, 2, 200) # ضغط
])
# النمط 2: تشغيل بحمل عالي
high_load = np.column_stack([
np.random.normal(80, 4, 100),
np.random.normal(55, 3, 100)
])
# النمط 3: تشغيل غير طبيعي (بداية تلف)
degraded = np.column_stack([
np.random.normal(35, 5, 50),
np.random.normal(45, 4, 50)
])
data = np.vstack([normal, high_load, degraded])
df = pd.DataFrame(data, columns=['flow_rate', 'pressure'])
print(f"إجمالي القراءات: {len(df)}")
print(df.describe().round(2))
K-Means: تقسيم البيانات إلى مجموعات
K-Means هو أشهر خوارزميات التجميع. يقسم البيانات إلى K مجموعة بحيث تكون نقاط كل مجموعة أقرب ما يمكن لمركزها:
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# تطبيع البيانات (مهم جداً للتجميع)
scaler = StandardScaler()
data_scaled = scaler.fit_transform(df)
# تطبيق K-Means مع 3 مجموعات
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
df['cluster'] = kmeans.fit_predict(data_scaled)
# عرض مراكز المجموعات (بالقيم الأصلية)
centers = scaler.inverse_transform(kmeans.cluster_centers_)
centers_df = pd.DataFrame(centers, columns=['flow_rate', 'pressure'])
centers_df.index.name = 'cluster'
print("مراكز المجموعات:")
print(centers_df.round(2))
print(f"\nتوزيع النقاط:")
print(df['cluster'].value_counts().sort_index())
تصور المجموعات
plt.figure(figsize=(10, 6))
colors = ['#2196F3', '#FF5722', '#4CAF50']
for i in range(3):
mask = df['cluster'] == i
plt.scatter(df.loc[mask, 'flow_rate'], df.loc[mask, 'pressure'],
c=colors[i], alpha=0.6, label=f'المجموعة {i}')
plt.scatter(centers[:, 0], centers[:, 1],
c='black', marker='X', s=200, label='المراكز')
plt.xlabel('معدل التدفق (L/min)')
plt.ylabel('الضغط (bar)')
plt.title('أنماط تشغيل المضخة المكتشفة بـ K-Means')
plt.legend()
plt.tight_layout()
plt.savefig('kmeans_clusters.png', dpi=150)
plt.show()
اختيار عدد المجموعات: طريقة الكوع
كيف نحدد العدد الأمثل للمجموعات؟ طريقة الكوع تساعد في ذلك:
from sklearn.metrics import silhouette_score
inertias = []
silhouettes = []
K_range = range(2, 10)
for k in K_range:
km = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = km.fit_predict(data_scaled)
inertias.append(km.inertia_)
silhouettes.append(silhouette_score(data_scaled, labels))
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
# مخطط الكوع
ax1.plot(K_range, inertias, 'bo-')
ax1.set_xlabel('عدد المجموعات (K)')
ax1.set_ylabel('مجموع المسافات الداخلية')
ax1.set_title('طريقة الكوع')
# مقياس Silhouette
ax2.plot(K_range, silhouettes, 'ro-')
ax2.set_xlabel('عدد المجموعات (K)')
ax2.set_ylabel('معامل Silhouette')
ax2.set_title('معامل Silhouette لكل K')
plt.tight_layout()
plt.savefig('elbow_method.png', dpi=150)
plt.show()
best_k = list(K_range)[np.argmax(silhouettes)]
print(f"أفضل عدد مجموعات حسب Silhouette: {best_k}")
DBSCAN: اكتشاف مجموعات بأشكال غير منتظمة
DBSCAN لا يتطلب تحديد عدد المجموعات مسبقاً ويكتشف القيم الشاذة تلقائياً:
from sklearn.cluster import DBSCAN
# تطبيق DBSCAN
dbscan = DBSCAN(eps=0.4, min_samples=10)
df['dbscan_cluster'] = dbscan.fit_predict(data_scaled)
n_clusters = len(set(df['dbscan_cluster'])) - (1 if -1 in df['dbscan_cluster'].values else 0)
n_noise = (df['dbscan_cluster'] == -1).sum()
print(f"عدد المجموعات المكتشفة: {n_clusters}")
print(f"نقاط الضوضاء (شاذة): {n_noise}")
print(f"\nتوزيع المجموعات:")
print(df['dbscan_cluster'].value_counts().sort_index())
# تصور DBSCAN
plt.figure(figsize=(10, 6))
unique_labels = sorted(df['dbscan_cluster'].unique())
for label in unique_labels:
mask = df['dbscan_cluster'] == label
if label == -1:
plt.scatter(df.loc[mask, 'flow_rate'], df.loc[mask, 'pressure'],
c='gray', marker='x', alpha=0.5, label='ضوضاء')
else:
plt.scatter(df.loc[mask, 'flow_rate'], df.loc[mask, 'pressure'],
alpha=0.6, label=f'المجموعة {label}')
plt.xlabel('معدل التدفق (L/min)')
plt.ylabel('الضغط (bar)')
plt.title('أنماط التشغيل المكتشفة بـ DBSCAN')
plt.legend()
plt.tight_layout()
plt.savefig('dbscan_clusters.png', dpi=150)
plt.show()
مقارنة بين K-Means و DBSCAN
| المعيار | K-Means | DBSCAN |
|---|---|---|
| عدد المجموعات | يجب تحديده مسبقاً | يُكتشف تلقائياً |
| شكل المجموعات | كروية فقط | أي شكل |
| القيم الشاذة | لا يكتشفها | يكتشفها تلقائياً |
| المعلمات | K فقط | eps و min_samples |
| الأفضل لـ | بيانات منتظمة | بيانات معقدة الشكل |
مثال عملي: اكتشاف أنماط تشغيل مختلفة لمضخة
سنبني نظاماً متكاملاً يراقب مضخة ويكتشف أنماط تشغيلها:
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# بيانات أسبوع من مضخة صناعية (قراءة كل دقيقة)
np.random.seed(42)
n = 10080 # 7 أيام × 24 ساعة × 60 دقيقة
timestamps = pd.date_range('2025-03-01', periods=n, freq='min')
pump_data = pd.DataFrame({
'timestamp': timestamps,
'flow': np.random.normal(60, 5, n),
'pressure': np.random.normal(35, 3, n),
'current': np.random.normal(15, 1.5, n),
'vibration': np.random.normal(2.0, 0.3, n)
})
# إضافة أنماط واقعية: إيقاف ليلي
night_mask = pump_data['timestamp'].dt.hour.isin(range(0, 6))
pump_data.loc[night_mask, ['flow', 'pressure', 'current']] *= 0.3
pump_data.loc[night_mask, 'vibration'] *= 0.5
# تطبيق التجميع
features = ['flow', 'pressure', 'current', 'vibration']
scaler = StandardScaler()
scaled = scaler.fit_transform(pump_data[features])
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
pump_data['mode'] = kmeans.fit_predict(scaled)
# تسمية الأنماط المكتشفة
mode_summary = pump_data.groupby('mode')[features].mean().round(2)
print("الأنماط المكتشفة:")
print(mode_summary)
mode_names = {0: 'تشغيل عادي', 1: 'خمول ليلي', 2: 'حمل عالي'}
pump_data['mode_name'] = pump_data['mode'].map(mode_names)
print(f"\nتوزيع ساعات التشغيل لكل نمط:")
print(pump_data['mode_name'].value_counts())
الخلاصة
التجميع أداة قوية لاكتشاف الأنماط المخفية في البيانات الصناعية بدون الحاجة لتصنيفات مسبقة. K-Means مناسب للمجموعات المنتظمة وDBSCAN للأشكال المعقدة. في الدرس القادم سنتعلم كشف الشذوذ، وهو تطبيق مباشر وحيوي في الصيانة التنبؤية ومراقبة المعدات.