ML Learning Hub
الأسسمبتدئ

الجبر الخطي لتعلم الآلة

الهندسة وراء كل نموذج — الضرب النقطي وتحويلات المصفوفات والتحليل الطيفي

المتجهات والضرب النقطي وضرب المصفوفات والتحليل الطيفي وSVD — مع حدس بصري لكيفية تحويل المصفوفات للفضاء. اللغة التي تُكتب بها كل شبكة عصبية.

45 min
10 مخططات
8 المفاهيم المغطاة

المتطلبات الأساسية

Python ML Stack

المفاهيم المغطاة

Dot ProductMatrix MultiplyEigenvaluesEigenvectorsSVDRankDeterminantPCA Connection

الصيغ الرئيسية

الضرب النقطي

يقيس مدى توافق متجهين — صفر يعني عمودية، أقصى قيمة عند التوازي

ضرب المصفوفات

تركيب تحويلين خطيين — تطبيق B أولاً ثم A

التحليل الطيفي

المتجهات الذاتية v تبقى على امتدادها تحت A؛ λ هو عامل التكبير

تحليل القيم المفردة (SVD)

أي مصفوفة تتحلل إلى دوران × مقياس × دوران — يُستخدم في ACP وLSA وأنظمة التوصية

محاكاة تفاعلية

Loading visualization…
🎯

لماذا الجبر الخطي هو تعلم الآلة

motivation

طبقة الشبكة العصبية هي y = Wx + b — ضرب مصفوفات. الانحدار التدرجي يتطلب حساب التدرج، وهو مصفوفة جاكوبية. ACP تجد المتجهات الذاتية الرئيسية لمصفوفة التباين. الانتباه في المحولات هو Q·Kᵀ·V — ثلاثة ضروب مصفوفات. كل تمرير أمامي وخلفي وكل خطوة تحسين هي جبر خطي.

الضرب النقطي a·b = ‖a‖‖b‖cos(θ) هو أساس تشابه جيب التمام (NLP) وحيلة النواة (SVM) وآليات الانتباه (المحولات).

💡

المصفوفات كمحولات للفضاء

intuition

كل مصفوفة A بحجم m×n تمثل تحويلاً خطياً من ℝⁿ إلى ℝᵐ. ضرب متجه v بـA يمده أو يدوره أو يعكسه أو يسقطه. المحدد يخبرك بعامل تضخيم الحجم: |det(A)| = 2 يعني مضاعفة كل منطقة. det = 0 يعني انهيار الفضاء إلى بُعد أقل.

تخيل أي مصفوفة 2×2 بمشاهدة إلى أين يذهب المربع الوحدوي [0,1]×[0,1]. الزوايا الأربع تذهب إلى (0,0) والعمود الأول والثاني ومجموعهما.

⚙️

التحلل الذاتي خطوة بخطوة

algorithm
1

إيجاد القيم الذاتية: حل det(A - λI) = 0 (كثيرة الحدود المميزة). للمصفوفات 2×2: λ = (tr(A) ± √(tr²-4det)) / 2.

2

لكل قيمة ذاتية λᵢ: حل (A - λᵢI)v = 0 لإيجاد المتجه الذاتي vᵢ. التطبيع: ‖vᵢ‖ = 1.

3

تكديس المتجهات الذاتية كأعمدة في Q: A = QΛQ⁻¹ حيث Λ = diag(λ₁, λ₂, …)

4

للمصفوفات المتماثلة (مصفوفات التباين): Q متعامدة (Q⁻¹ = Qᵀ)، والقيم الذاتية حقيقية.

5

Aⁿ = QΛⁿQ⁻¹ — القيم الذاتية الكبيرة تهيمن على التطبيق المتكرر (مثال: الضرب القوي).

6

ACP: احسب التباين C = XᵀX/n، حلل إلى قيم ذاتية، خذ أعلى k متجه كمصفوفة إسقاط.

</>

الجبر الخطي مع NumPy

code
python65 lines
import numpy as np

class="tok-comment"># ── Vectors and dot products ──────────────────────────────────────────────────
a = np.array([class="tok-num">3., class="tok-num">4.])
b = np.array([class="tok-num">1., class="tok-num">0.])

print(fclass="tok-str">"a·b = {np.dot(a, b):.2f}")             class="tok-comment"># class="tok-num">3.0
print(fclass="tok-str">"‖a‖ = {np.linalg.norm(a):.2f}")        class="tok-comment"># class="tok-num">5.0
print(fclass="tok-str">"cos(θ) = {np.dot(a,b)/(np.linalg.norm(a)*np.linalg.norm(b)):.3f}")  class="tok-comment"># class="tok-num">0.6

class="tok-comment"># Cosine similarity (NLP/recommendation)
def cosine_sim(u, v):
    return np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v))

class="tok-comment"># ── Matrix operations ─────────────────────────────────────────────────────────
A = np.array([[class="tok-num">2., class="tok-num">1.],
              [class="tok-num">0., class="tok-num">3.]])

B = np.array([[class="tok-num">1., class="tok-num">0.],
              [class="tok-num">2., class="tok-num">1.]])

print(class="tok-str">"A @ B =")
print(A @ B)                     class="tok-comment"># matrix multiply (composition)
print(fclass="tok-str">"det(A) = {np.linalg.det(A):.2f}")   class="tok-comment"># class="tok-num">6.0 — volume scaling
print(fclass="tok-str">"rank(A) = {np.linalg.matrix_rank(A)}")   class="tok-comment"># class="tok-num">2 — full rank

A_inv = np.linalg.inv(A)
print(class="tok-str">"A @ A_inv ≈ I:", np.allclose(A @ A_inv, np.eye(class="tok-num">2)))

class="tok-comment"># ── Eigendecomposition ────────────────────────────────────────────────────────
eigenvalues, eigenvectors = np.linalg.eig(A)
print(fclass="tok-str">"Eigenvalues: {eigenvalues}")          class="tok-comment"># [class="tok-num">2. class="tok-num">3.]
print(fclass="tok-str">"Eigenvectors (columns):\n{eigenvectors.round(class="tok-num">3)}")

class="tok-comment"># Verify: A @ v = λ * v
for i in range(len(eigenvalues)):
    v = eigenvectors[:, i]
    lam = eigenvalues[i]
    print(fclass="tok-str">"λ{i+class="tok-num">1}={lam:.2f}, Aclass="tok-dec">@v = {Aclass="tok-dec">@v.round(class="tok-num">3)}, λ*v = {(lam*v).round(class="tok-num">3)}")

class="tok-comment"># Reconstruct A from eigendecomposition
Q = eigenvectors
Lambda = np.diag(eigenvalues)
A_reconstructed = Q @ Lambda @ np.linalg.inv(Q)
print(class="tok-str">"Reconstruction error:", np.linalg.norm(A - A_reconstructed))

class="tok-comment"># ── SVD ───────────────────────────────────────────────────────────────────────
M = np.random.randn(class="tok-num">4, class="tok-num">3)               class="tok-comment"># class="tok-num">4×class="tok-num">3 rectangular matrix
U, S, Vt = np.linalg.svd(M, full_matrices=False)
print(fclass="tok-str">"U: {U.shape}, S: {S.shape}, Vt: {Vt.shape}")

class="tok-comment"># Low-rank approximation (keep top-k singular values)
k = class="tok-num">2
M_approx = U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]
print(fclass="tok-str">"Rank-{k} approx error: {np.linalg.norm(M - M_approx):.4f}")

class="tok-comment"># ── PCA from scratch ─────────────────────────────────────────────────────────
X = np.random.randn(class="tok-num">200, class="tok-num">5)
X -= X.mean(axis=class="tok-num">0)                     class="tok-comment"># center
C = (X.T @ X) / (len(X) - class="tok-num">1)           class="tok-comment"># covariance matrix
eigenvalues, eigenvectors = np.linalg.eigh(C)   class="tok-comment"># eigh for symmetric matrices
idx = np.argsort(eigenvalues)[::-class="tok-num">1]     class="tok-comment"># sort descending
PC = eigenvectors[:, idx[:class="tok-num">2]]           class="tok-comment"># top-class="tok-num">2 principal components
X_proj = X @ PC                         class="tok-comment"># project to 2D
print(fclass="tok-str">"Explained variance: {eigenvalues[idx[:class="tok-num">2]] / eigenvalues.sum() * class="tok-num">100}")
⚠️

الاستقرار العددي وسوء التكييف

pitfall

رقم الحالة κ(A) = σ_max/σ_min يقيس الحساسية للاضطرابات. رقم حالة مرتفع → سيئ التكييف → تتضخم الأخطاء العددية. الانحدار التدرجي يتقارب ببطء على أسطح الخسارة سيئة التكييف — لهذا يهم تحجيم الميزات. لا تعكس مصفوفة مباشرة بـnp.linalg.inv(A) إذا كنت تحل Ax=b — استخدم np.linalg.solve(A,b) الأسرع والأكثر استقراراً.

np.linalg.cond(A) يعطيك رقم الحالة. κ > 10⁶ يعني مشاكل — ستحتوي الحلول على ~6 أرقام دقيقة أقل مما تتوقع.

?اختبار المعرفة

يتم حفظ التقدم في متصفحك — لا حاجة لحساب.

تحتاج مهندس ذكاء اصطناعي أو عالم بيانات؟

أبني نماذج تعلم آلي مخصصة، ووكلاء ذكاء اصطناعي، ورؤية حاسوب، وأتمتة — من الفكرة إلى الإنتاج.