استكشاف البيانات الصناعية: قراءة وتنظيف وفهم بيانات المستشعرات
قراءة بيانات المستشعرات من CSV
في البيئة الصناعية، تُخزَّن بيانات المستشعرات عادةً في ملفات CSV أو قواعد بيانات. Pandas يجعل قراءة هذه الملفات بسيطة للغاية:
import pandas as pd
import numpy as np
# قراءة بيانات خط إنتاج من ملف CSV
df = pd.read_csv('production_line_sensors.csv',
parse_dates=['timestamp'],
index_col='timestamp')
# عرض أول 5 صفوف
print(df.head())
print(f"\nعدد الصفوف: {len(df)}")
print(f"عدد الأعمدة: {len(df.columns)}")
print(f"الأعمدة: {list(df.columns)}")
أنواع الملفات الشائعة في الصناعة
# قراءة من Excel (تقارير الجودة)
df_quality = pd.read_excel('quality_report.xlsx', sheet_name='Sheet1')
# قراءة من ملف مفصول بعلامة تبويب (أجهزة قديمة)
df_legacy = pd.read_csv('old_plc_data.tsv', sep='\t')
# قراءة من JSON (واجهات API حديثة)
df_api = pd.read_json('sensor_api_response.json')
استكشاف البيانات: describe و info
قبل أي تحليل، يجب فهم طبيعة البيانات. هاتان الأداتان هما نقطة البداية:
# معلومات هيكلية عن البيانات
print(df.info())
# يعرض: أسماء الأعمدة، أنواع البيانات، القيم غير الفارغة، استهلاك الذاكرة
# إحصائيات وصفية
print(df.describe())
# يعرض: المتوسط، الانحراف المعياري، الحد الأدنى/الأقصى، الأرباع
أسئلة استكشافية أساسية
# ما الفترة الزمنية المغطاة؟
print(f"من: {df.index.min()}")
print(f"إلى: {df.index.max()}")
# هل توجد قيم مفقودة؟
print(f"\nالقيم المفقودة لكل عمود:")
print(df.isnull().sum())
# ما نسبة القيم المفقودة؟
print(f"\nنسبة القيم المفقودة:")
print((df.isnull().sum() / len(df) * 100).round(2))
التعامل مع القيم المفقودة
القيم المفقودة شائعة في البيانات الصناعية بسبب انقطاع الاتصال أو تعطل المستشعرات:
# محاكاة بيانات بها قيم مفقودة
np.random.seed(42)
n = 1000
data = {
'temperature': np.random.normal(75, 2, n),
'pressure': np.random.normal(101, 0.5, n),
'flow_rate': np.random.normal(50, 5, n)
}
df = pd.DataFrame(data)
# إدخال قيم مفقودة عشوائياً (محاكاة انقطاع المستشعر)
for col in df.columns:
mask = np.random.random(n) < 0.05 # 5% قيم مفقودة
df.loc[mask, col] = np.nan
# استراتيجية 1: الملء بالمتوسط (مناسب للثبات)
df_mean = df.fillna(df.mean())
# استراتيجية 2: الملء الأمامي (مناسب للسلاسل الزمنية)
df_ffill = df.fillna(method='ffill')
# استراتيجية 3: الاستيفاء الخطي (الأفضل لبيانات المستشعرات)
df_interp = df.interpolate(method='linear')
# استراتيجية 4: حذف الصفوف (فقط إذا كانت النسبة صغيرة جداً)
df_dropped = df.dropna()
print(f"بعد الحذف: {len(df_dropped)} من {len(df)} صف")
كشف القيم الشاذة وتنظيفها
القيم الشاذة قد تكون أعطالاً حقيقية أو أخطاء في القراءة. كلا الحالتين يجب التعامل معهما:
# طريقة IQR (المدى الربيعي)
def detect_outliers_iqr(series, factor=1.5):
Q1 = series.quantile(0.25)
Q3 = series.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - factor * IQR
upper = Q3 + factor * IQR
return (series < lower) | (series > upper)
# تطبيق على عمود الحرارة
outliers = detect_outliers_iqr(df_interp['temperature'])
print(f"عدد القيم الشاذة: {outliers.sum()}")
# طريقة Z-Score
from scipy import stats
z_scores = np.abs(stats.zscore(df_interp['temperature'].dropna()))
outliers_z = z_scores > 3 # أبعد من 3 انحرافات معيارية
print(f"قيم شاذة بطريقة Z-Score: {outliers_z.sum()}")
# استبدال القيم الشاذة بالحد الأقصى/الأدنى المقبول
Q1 = df_interp['temperature'].quantile(0.25)
Q3 = df_interp['temperature'].quantile(0.75)
IQR = Q3 - Q1
df_interp['temperature'] = df_interp['temperature'].clip(
lower=Q1 - 1.5 * IQR,
upper=Q3 + 1.5 * IQR
)
التصور بالرسوم البيانية: matplotlib و seaborn
الرسوم البيانية تكشف أنماطاً لا تظهر في الأرقام:
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 1. مخطط خطي: تطور الحرارة مع الزمن
axes[0, 0].plot(df_interp['temperature'].values[:200], linewidth=0.7)
axes[0, 0].set_title('درجة الحرارة مع الزمن')
axes[0, 0].set_ylabel('°C')
# 2. المدرج التكراري: توزيع الضغط
axes[0, 1].hist(df_interp['pressure'], bins=30, edgecolor='black', alpha=0.7)
axes[0, 1].set_title('توزيع قراءات الضغط')
# 3. مخطط الصندوق: مقارنة المتغيرات
df_interp.boxplot(ax=axes[1, 0])
axes[1, 0].set_title('مخطط الصندوق للمتغيرات')
# 4. مخطط الارتباط الحراري
corr = df_interp.corr()
sns.heatmap(corr, annot=True, cmap='coolwarm', ax=axes[1, 1])
axes[1, 1].set_title('مصفوفة الارتباط')
plt.tight_layout()
plt.savefig('data_exploration.png', dpi=150)
plt.show()
مثال عملي: تنظيف بيانات خط إنتاج شهر كامل
لنطبق كل ما تعلمناه على سيناريو واقعي متكامل:
import pandas as pd
import numpy as np
# محاكاة بيانات شهر كامل (قراءة كل 10 دقائق)
np.random.seed(42)
n = 4320 # 30 يوم × 24 ساعة × 6 قراءات/ساعة
timestamps = pd.date_range('2025-03-01', periods=n, freq='10min')
raw_data = pd.DataFrame({
'timestamp': timestamps,
'motor_temp': np.random.normal(72, 3, n),
'oil_pressure': np.random.normal(45, 2, n),
'vibration_rms': np.random.normal(2.5, 0.4, n),
'production_rate': np.random.normal(100, 8, n)
})
# إدخال مشاكل واقعية
raw_data.loc[500:520, 'motor_temp'] = np.nan # انقطاع مستشعر
raw_data.loc[1000, 'oil_pressure'] = 200 # قراءة خاطئة
raw_data.loc[2000:2010, 'vibration_rms'] *= 3 # اهتزاز حقيقي مرتفع
# خط أنابيب التنظيف
clean = raw_data.copy()
clean['motor_temp'] = clean['motor_temp'].interpolate(method='linear')
for col in ['oil_pressure', 'vibration_rms', 'production_rate']:
outliers = detect_outliers_iqr(clean[col])
clean.loc[outliers, col] = np.nan
clean[col] = clean[col].interpolate(method='linear')
print("قبل التنظيف:")
print(raw_data.describe().round(2))
print("\nبعد التنظيف:")
print(clean.describe().round(2))
print(f"\nالبيانات جاهزة للتحليل: {len(clean)} سجل نظيف")
الخلاصة
تنظيف البيانات واستكشافها يستهلك عادةً 60-80% من وقت أي مشروع تعلم آلي. تعلمنا قراءة الملفات، واكتشاف القيم المفقودة والشاذة، وتقنيات التنظيف المناسبة للبيئة الصناعية. البيانات النظيفة هي أساس أي نموذج ناجح، وفي الدرس القادم سنتعمق في الإحصاء الوصفي لفهم البيانات بشكل أعمق.