الرئيسية قاعدة المعرفة الرياضيات الهندسية تحليل الانحدار: التنبؤ من البيانات
الرياضيات الهندسية

تحليل الانحدار: التنبؤ من البيانات

ما هو تحليل الانحدار ولماذا يحتاجه المهندس؟

تخيّل أنك تراقب محرك كهربائي في خط إنتاج. لديك بيانات حساسات: الحرارة، سرعة الدوران، التيار، الاهتزاز. هل يمكنك التنبؤ بعمر المحرك المتبقي من هذه القراءات؟ هل تستطيع معرفة أي عامل يؤثر أكثر على الأداء؟

تحليل الانحدار (Regression Analysis) هو الأداة الرياضية التي تجيب على هذه الأسئلة. يبني نموذجاً رياضياً يصف العلاقة بين متغيرات مستقلة (المدخلات: الحرارة، الحمل...) ومتغير تابع (المخرج: العمر المتبقي، استهلاك الطاقة...).

ببساطة: الانحدار يرسم أفضل خط (أو منحنى) يمر بين نقاط البيانات.

الانحدار الخطي البسيط: أبسط نموذج تنبؤي

الانحدار الخطي البسيط يصف علاقة بين متغير مستقل واحد x ومتغير تابع y:

y = β₀ + β₁x + ε

حيث:

  • β₀ = تقاطع المحور (Intercept) — قيمة y عندما x = 0
  • β₁ = الميل (Slope) — مقدار تغيّر y لكل وحدة تغيّر في x
  • ε = الخطأ العشوائي (Error) — ما لا يفسّره النموذج

مثال صناعي: العلاقة بين حمل المحرك (%) واستهلاك الطاقة (kW):

import numpy as np

# بيانات قياسية من محرك في مصنع
load_percent = np.array([20, 30, 40, 50, 60, 70, 80, 90, 100])
power_kw = np.array([4.2, 5.8, 7.1, 8.9, 10.5, 12.3, 13.8, 15.6, 17.2])

# حساب معاملات الانحدار بطريقة المربعات الصغرى
n = len(load_percent)
x_mean = np.mean(load_percent)
y_mean = np.mean(power_kw)

# الميل β₁
numerator = np.sum((load_percent - x_mean) * (power_kw - y_mean))
denominator = np.sum((load_percent - x_mean) ** 2)
beta_1 = numerator / denominator

# التقاطع β₀
beta_0 = y_mean - beta_1 * x_mean

print(f"المعادلة: الطاقة = {beta_0:.2f} + {beta_1:.4f} × الحمل")
print(f"تفسير: كل 1% زيادة في الحمل تزيد الاستهلاك {beta_1:.4f} kW")

# تنبؤ عند حمل 75%
load_new = 75
power_predicted = beta_0 + beta_1 * load_new
print(f"\nتنبؤ عند حمل {load_new}%: {power_predicted:.2f} kW")

طريقة المربعات الصغرى (Least Squares): كيف نجد أفضل خط؟

من بين ملايين الخطوط الممكنة، نريد الخط الذي يُقلّل مجموع مربعات الأخطاء (Sum of Squared Errors):

SSE = Σ (yi - ŷi)² = Σ (yi - β₀ - β₁xi)²

لماذا مربعات وليس قيم مطلقة؟

  1. المربعات تعاقب الأخطاء الكبيرة أكثر
  2. الدالة قابلة للاشتقاق — يمكن إيجاد الحد الأدنى تحليلياً
  3. مرتبطة بالتوزيع الطبيعي (Gaussian) للأخطاء
# حساب المربعات الصغرى خطوة بخطوة
y_predicted = beta_0 + beta_1 * load_percent
residuals = power_kw - y_predicted  # البواقي

SSE = np.sum(residuals ** 2)
SST = np.sum((power_kw - y_mean) ** 2)  # المجموع الكلي

print("البواقي (الأخطاء):")
for i in range(n):
    print(f"  حمل {load_percent[i]}%: فعلي={power_kw[i]:.1f}, "
          f"متنبأ={y_predicted[i]:.2f}, خطأ={residuals[i]:+.2f} kW")

print(f"\nمجموع مربعات الأخطاء (SSE): {SSE:.4f}")
print(f"المجموع الكلي (SST): {SST:.4f}")

معامل التحديد R²: هل النموذج جيد؟

(R-squared) يقيس نسبة التباين في البيانات التي يفسّرها النموذج:

R² = 1 - (SSE / SST)
قيمة R² التفسير
0.95 - 1.00 ممتاز — النموذج يفسّر معظم التباين
0.80 - 0.95 جيد — مفيد للتنبؤ
0.50 - 0.80 متوسط — مفيد لفهم الاتجاه
< 0.50 ضعيف — يحتاج متغيرات إضافية
R_squared = 1 - (SSE / SST)
print(f"R² = {R_squared:.4f}")
print(f"النموذج يفسّر {R_squared*100:.1f}% من تباين استهلاك الطاقة")

if R_squared > 0.95:
    print("تقييم: ممتاز!")
elif R_squared > 0.80:
    print("تقييم: جيد")
else:
    print("تقييم: يحتاج تحسين")

تحذير مهم: R² عالي لا يعني بالضرورة أن النموذج صحيح. دائماً افحص البواقي (Residuals) بصرياً — إذا كانت عشوائية حول الصفر فالنموذج مناسب، وإذا ظهر فيها نمط فقد تحتاج نموذجاً غير خطي.

الانحدار المتعدد: أكثر من متغير مستقل

في الواقع الصناعي، نادراً ما يعتمد المخرج على متغير واحد. الانحدار المتعدد (Multiple Regression) يستخدم عدة متغيرات مستقلة:

y = β₀ + β₁x₁ + β₂x₂ + β₃x₃ + ... + ε

مثال صناعي: التنبؤ باستهلاك طاقة المحرك من الحمل والحرارة المحيطة والرطوبة:

import numpy as np

# بيانات من 12 قياساً
# [الحمل%, الحرارة°C, الرطوبة%]
X_data = np.array([
    [40, 25, 50], [50, 28, 55], [60, 30, 60],
    [70, 32, 45], [80, 35, 70], [45, 22, 40],
    [55, 27, 65], [65, 33, 55], [75, 36, 50],
    [85, 38, 75], [50, 24, 45], [90, 40, 60]
])
y_data = np.array([7.2, 8.8, 10.3, 12.1, 14.0, 7.8, 9.5, 11.5, 13.2, 15.1, 8.5, 16.0])

# إضافة عمود الواحدات لـ β₀
n = len(y_data)
X_matrix = np.column_stack([np.ones(n), X_data])

# حل المربعات الصغرى بالجبر الخطي
# β = (X^T X)^(-1) X^T y
XtX = X_matrix.T @ X_matrix
Xty = X_matrix.T @ y_data
beta = np.linalg.solve(XtX, Xty)

print("معاملات الانحدار المتعدد:")
print(f"  β₀ (التقاطع): {beta[0]:.4f}")
print(f"  β₁ (الحمل): {beta[1]:.4f} kW لكل 1%")
print(f"  β₂ (الحرارة): {beta[2]:.4f} kW لكل 1°C")
print(f"  β₃ (الرطوبة): {beta[3]:.4f} kW لكل 1%")

# حساب R²
y_pred = X_matrix @ beta
SSE = np.sum((y_data - y_pred) ** 2)
SST = np.sum((y_data - np.mean(y_data)) ** 2)
R2 = 1 - SSE / SST
print(f"\nR² = {R2:.4f}")

# تنبؤ: حمل 72%، حرارة 31°C، رطوبة 55%
new_input = np.array([1, 72, 31, 55])
prediction = new_input @ beta
print(f"\nتنبؤ (72%, 31°C, 55%): {prediction:.2f} kW")

أي متغير الأهم؟ انظر لحجم المعاملات بعد توحيد المقياس (Standardization) — المعامل الأكبر يشير إلى المتغير الأكثر تأثيراً.

الانحدار متعدد الحدود: عندما تكون العلاقة منحنية

ليست كل العلاقات خطية. الانحدار متعدد الحدود (Polynomial Regression) يلائم منحنيات:

y = β₀ + β₁x + β₂x² + β₃x³ + ...

مثال صناعي: كفاءة مضخة مقابل معدل التدفق — العلاقة دائماً منحنية (قوس):

import numpy as np

# بيانات كفاءة مضخة طرد مركزي
flow_rate = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])  # m³/h
efficiency = np.array([45, 62, 74, 82, 87, 89, 88, 84, 77, 65])   # %

# انحدار خطي (للمقارنة)
X_lin = np.column_stack([np.ones(10), flow_rate])
beta_lin = np.linalg.lstsq(X_lin, efficiency, rcond=None)[0]
y_lin = X_lin @ beta_lin
R2_lin = 1 - np.sum((efficiency - y_lin)**2) / np.sum((efficiency - np.mean(efficiency))**2)

# انحدار متعدد الحدود من الدرجة 2
X_poly = np.column_stack([np.ones(10), flow_rate, flow_rate**2])
beta_poly = np.linalg.lstsq(X_poly, efficiency, rcond=None)[0]
y_poly = X_poly @ beta_poly
R2_poly = 1 - np.sum((efficiency - y_poly)**2) / np.sum((efficiency - np.mean(efficiency))**2)

print(f"الانحدار الخطي: R² = {R2_lin:.4f}")
print(f"الانحدار التربيعي: R² = {R2_poly:.4f}")
print(f"\nمعادلة الكفاءة: η = {beta_poly[0]:.2f} + {beta_poly[1]:.4f}Q + {beta_poly[2]:.6f}Q²")

# نقطة الكفاءة القصوى (أين المشتقة = صفر)
Q_optimal = -beta_poly[1] / (2 * beta_poly[2])
eta_max = beta_poly[0] + beta_poly[1]*Q_optimal + beta_poly[2]*Q_optimal**2
print(f"\nمعدل التدفق الأمثل: {Q_optimal:.1f} m³/h")
print(f"الكفاءة القصوى: {eta_max:.1f}%")

تحذير: لا تزد درجة كثير الحدود أكثر من اللازم — درجة عالية جداً تسبب فرط التخصيص (Overfitting) حيث يتبع النموذج الضجيج بدلاً من الاتجاه الحقيقي.

تحليل البواقي: التحقق من صحة النموذج

البواقي (Residuals) هي الفرق بين القيم الفعلية والمتنبأ بها. تحليلها يكشف مشاكل النموذج:

import numpy as np

# بواقي النموذج التربيعي للمضخة
residuals = efficiency - y_poly

print("تحليل البواقي:")
print(f"  المتوسط: {np.mean(residuals):.4f} (يجب أن يقارب الصفر)")
print(f"  الانحراف المعياري: {np.std(residuals):.4f}")
print(f"  الحد الأقصى: {np.max(np.abs(residuals)):.4f}")

# اختبار الطبيعية (تقريبي)
skewness = np.mean(((residuals - np.mean(residuals)) / np.std(residuals)) ** 3)
print(f"  الالتواء (Skewness): {skewness:.4f} (يجب أن يقارب الصفر)")

# فحص النمط
print("\nالبواقي لكل نقطة:")
for i in range(len(residuals)):
    bar = "+" * int(abs(residuals[i]) * 5)
    sign = "+" if residuals[i] > 0 else "-"
    print(f"  Q={flow_rate[i]:3d}: {residuals[i]:+.2f} {sign}{bar}")

قواعد البواقي الصحية:

  1. متوسطها قريب من الصفر
  2. لا يوجد نمط واضح (عشوائية)
  3. تباينها ثابت تقريباً (Homoscedasticity)
  4. لا توجد نقاط شاذة كبيرة (Outliers)

تطبيق صناعي: بناء نموذج صيانة تنبؤية

الهدف النهائي: التنبؤ بمتى يحتاج المحرك صيانة بناءً على بيانات الحساسات:

import numpy as np

# بيانات تدريب: 20 محركاً مع أعمار مختلفة
np.random.seed(42)
n_motors = 20

# متغيرات مستقلة
vibration_rms = np.random.uniform(1.5, 8.0, n_motors)    # mm/s
temperature = np.random.uniform(60, 120, n_motors)        # °C
current_deviation = np.random.uniform(0, 15, n_motors)    # % عن القيمة المرجعية
hours_running = np.random.uniform(1000, 15000, n_motors)  # ساعات تشغيل

# المتغير التابع: الأيام حتى العطل (معادلة حقيقية + ضجيج)
days_to_failure = (500
    - 30 * vibration_rms
    - 1.5 * temperature
    + 0.01 * hours_running
    - 5 * current_deviation
    + np.random.normal(0, 20, n_motors))
days_to_failure = np.maximum(days_to_failure, 1)  # لا يمكن أن يكون سالباً

# بناء النموذج
X = np.column_stack([
    np.ones(n_motors),
    vibration_rms,
    temperature,
    current_deviation,
    hours_running
])

beta = np.linalg.lstsq(X, days_to_failure, rcond=None)[0]

# تقييم النموذج
y_pred = X @ beta
SSE = np.sum((days_to_failure - y_pred)**2)
SST = np.sum((days_to_failure - np.mean(days_to_failure))**2)
R2 = 1 - SSE/SST

print("نموذج الصيانة التنبؤية:")
print(f"  الأيام = {beta[0]:.1f}")
print(f"         {beta[1]:+.2f} × الاهتزاز (mm/s)")
print(f"         {beta[2]:+.2f} × الحرارة (°C)")
print(f"         {beta[3]:+.2f} × انحراف التيار (%)")
print(f"         {beta[4]:+.4f} × ساعات التشغيل")
print(f"  R² = {R2:.4f}")

# تنبؤ لمحرك جديد
new_motor = np.array([1, 4.5, 85, 8, 6000])
prediction = new_motor @ beta
print(f"\nتنبؤ لمحرك (اهتزاز=4.5, حرارة=85, انحراف=8%, ساعات=6000):")
print(f"  الأيام المتبقية: {prediction:.0f} يوم")

if prediction < 30:
    print("  حالة: صيانة عاجلة مطلوبة!")
elif prediction < 90:
    print("  حالة: جدولة صيانة خلال شهر")
else:
    print("  حالة: مستقر — المراقبة كافية")

ملخص وقواعد عملية

النوع المعادلة متى تستخدمه
خطي بسيط y = β₀ + β₁x متغير واحد، علاقة خطية
متعدد y = β₀ + β₁x₁ + β₂x₂ + ... عدة متغيرات، علاقة خطية
متعدد الحدود y = β₀ + β₁x + β₂x² + ... علاقة منحنية
المقياس المعنى القيمة الجيدة
نسبة التباين المفسّر > 0.80
البواقي أخطاء النموذج عشوائية، متوسط صفري
RMSE جذر متوسط مربع الخطأ أصغر ما يمكن

نصيحة عملية: في بيئة المصنع، النموذج البسيط الذي يُفهم ويُشرح أفضل من نموذج معقد بدقة أعلى قليلاً. المشغّل يحتاج أن يثق بالنموذج — والثقة تأتي من الفهم. ابدأ بانحدار خطي، وعقّد فقط عندما تحتاج فعلاً.

regression linear-regression prediction R-squared least-squares curve-fitting الانحدار الانحدار الخطي التنبؤ معامل التحديد المربعات الصغرى ملاءمة المنحنى