الجبر الخطي لتعلم الآلة
“الهندسة وراء كل نموذج — الضرب النقطي وتحويلات المصفوفات والتحليل الطيفي”
المتجهات والضرب النقطي وضرب المصفوفات والتحليل الطيفي وSVD — مع حدس بصري لكيفية تحويل المصفوفات للفضاء. اللغة التي تُكتب بها كل شبكة عصبية.
المتطلبات الأساسية
المفاهيم المغطاة
∑الصيغ الرئيسية
الضرب النقطي
يقيس مدى توافق متجهين — صفر يعني عمودية، أقصى قيمة عند التوازي
ضرب المصفوفات
تركيب تحويلين خطيين — تطبيق B أولاً ثم A
التحليل الطيفي
المتجهات الذاتية v تبقى على امتدادها تحت A؛ λ هو عامل التكبير
تحليل القيم المفردة (SVD)
أي مصفوفة تتحلل إلى دوران × مقياس × دوران — يُستخدم في ACP وLSA وأنظمة التوصية
▶محاكاة تفاعلية
لماذا الجبر الخطي هو تعلم الآلة
طبقة الشبكة العصبية هي y = Wx + b — ضرب مصفوفات. الانحدار التدرجي يتطلب حساب التدرج، وهو مصفوفة جاكوبية. ACP تجد المتجهات الذاتية الرئيسية لمصفوفة التباين. الانتباه في المحولات هو Q·Kᵀ·V — ثلاثة ضروب مصفوفات. كل تمرير أمامي وخلفي وكل خطوة تحسين هي جبر خطي.
الضرب النقطي a·b = ‖a‖‖b‖cos(θ) هو أساس تشابه جيب التمام (NLP) وحيلة النواة (SVM) وآليات الانتباه (المحولات).
المصفوفات كمحولات للفضاء
كل مصفوفة A بحجم m×n تمثل تحويلاً خطياً من ℝⁿ إلى ℝᵐ. ضرب متجه v بـA يمده أو يدوره أو يعكسه أو يسقطه. المحدد يخبرك بعامل تضخيم الحجم: |det(A)| = 2 يعني مضاعفة كل منطقة. det = 0 يعني انهيار الفضاء إلى بُعد أقل.
تخيل أي مصفوفة 2×2 بمشاهدة إلى أين يذهب المربع الوحدوي [0,1]×[0,1]. الزوايا الأربع تذهب إلى (0,0) والعمود الأول والثاني ومجموعهما.
التحلل الذاتي خطوة بخطوة
إيجاد القيم الذاتية: حل det(A - λI) = 0 (كثيرة الحدود المميزة). للمصفوفات 2×2: λ = (tr(A) ± √(tr²-4det)) / 2.
لكل قيمة ذاتية λᵢ: حل (A - λᵢI)v = 0 لإيجاد المتجه الذاتي vᵢ. التطبيع: ‖vᵢ‖ = 1.
تكديس المتجهات الذاتية كأعمدة في Q: A = QΛQ⁻¹ حيث Λ = diag(λ₁, λ₂, …)
للمصفوفات المتماثلة (مصفوفات التباين): Q متعامدة (Q⁻¹ = Qᵀ)، والقيم الذاتية حقيقية.
Aⁿ = QΛⁿQ⁻¹ — القيم الذاتية الكبيرة تهيمن على التطبيق المتكرر (مثال: الضرب القوي).
ACP: احسب التباين C = XᵀX/n، حلل إلى قيم ذاتية، خذ أعلى k متجه كمصفوفة إسقاط.
الجبر الخطي مع NumPy
import numpy as np # ── Vectors and dot products ────────────────────────────────────────────────── a = np.array([3., 4.]) b = np.array([1., 0.]) print(f"a·b = {np.dot(a, b):.2f}") # 3.0 print(f"‖a‖ = {np.linalg.norm(a):.2f}") # 5.0 print(f"cos(θ) = {np.dot(a,b)/(np.linalg.norm(a)*np.linalg.norm(b)):.3f}") # 0.6 # Cosine similarity (NLP/recommendation) def cosine_sim(u, v): return np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v)) # ── Matrix operations ───────────────────────────────────────────────────────── A = np.array([[2., 1.], [0., 3.]]) B = np.array([[1., 0.], [2., 1.]]) print("A @ B =") print(A @ B) # matrix multiply (composition) print(f"det(A) = {np.linalg.det(A):.2f}") # 6.0 — volume scaling print(f"rank(A) = {np.linalg.matrix_rank(A)}") # 2 — full rank A_inv = np.linalg.inv(A) print("A @ A_inv ≈ I:", np.allclose(A @ A_inv, np.eye(2))) # ── Eigendecomposition ──────────────────────────────────────────────────────── eigenvalues, eigenvectors = np.linalg.eig(A) print(f"Eigenvalues: {eigenvalues}") # [2. 3.] print(f"Eigenvectors (columns):\n{eigenvectors.round(3)}") # Verify: A @ v = λ * v for i in range(len(eigenvalues)): v = eigenvectors[:, i] lam = eigenvalues[i] print(f"λ{i+1}={lam:.2f}, A@v = {A@v.round(3)}, λ*v = {(lam*v).round(3)}") # Reconstruct A from eigendecomposition Q = eigenvectors Lambda = np.diag(eigenvalues) A_reconstructed = Q @ Lambda @ np.linalg.inv(Q) print("Reconstruction error:", np.linalg.norm(A - A_reconstructed)) # ── SVD ─────────────────────────────────────────────────────────────────────── M = np.random.randn(4, 3) # 4×3 rectangular matrix U, S, Vt = np.linalg.svd(M, full_matrices=False) print(f"U: {U.shape}, S: {S.shape}, Vt: {Vt.shape}") # Low-rank approximation (keep top-k singular values) k = 2 M_approx = U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :] print(f"Rank-{k} approx error: {np.linalg.norm(M - M_approx):.4f}") # ── PCA from scratch ───────────────────────────────────────────────────────── X = np.random.randn(200, 5) X -= X.mean(axis=0) # center C = (X.T @ X) / (len(X) - 1) # covariance matrix eigenvalues, eigenvectors = np.linalg.eigh(C) # eigh for symmetric matrices idx = np.argsort(eigenvalues)[::-1] # sort descending PC = eigenvectors[:, idx[:2]] # top-2 principal components X_proj = X @ PC # project to 2D print(f"Explained variance: {eigenvalues[idx[:2]] / eigenvalues.sum() * 100}")
الاستقرار العددي وسوء التكييف
رقم الحالة κ(A) = σ_max/σ_min يقيس الحساسية للاضطرابات. رقم حالة مرتفع → سيئ التكييف → تتضخم الأخطاء العددية. الانحدار التدرجي يتقارب ببطء على أسطح الخسارة سيئة التكييف — لهذا يهم تحجيم الميزات. لا تعكس مصفوفة مباشرة بـnp.linalg.inv(A) إذا كنت تحل Ax=b — استخدم np.linalg.solve(A,b) الأسرع والأكثر استقراراً.
np.linalg.cond(A) يعطيك رقم الحالة. κ > 10⁶ يعني مشاكل — ستحتوي الحلول على ~6 أرقام دقيقة أقل مما تتوقع.
?اختبار المعرفة
يتم حفظ التقدم في متصفحك — لا حاجة لحساب.
Need a Data Scientist or AI Engineer?
I build custom ML models, RAG chatbots, data pipelines, and production APIs — from analysis to deployment.