اذهب إلى المحتوى

Mustafa Suleiman

الأعضاء
  • المساهمات

    14490
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    384

كل منشورات العضو Mustafa Suleiman

  1. لا مشكلة، لكن مع بعض الخطوات الإضافية المطلوبة لجعل النموذج متوافقًا مع واجهة scikit-learn، حيث توفر Keras واجهة جاهزة KerasClassifier أو KerasRegressor لدمج النماذج مع أدوات scikit-learn مثل GridSearchCV. وتستطيع تحديد أي عدد من القيم لكل معامل فائق ليس فقط 3 أو 4، لكن تذكر أن زيادة عدد القيم يزيد الوقت الحسابي بشكل كبير، واستخدم GridSearchCV كما تفعل مع أي نموذج في scikit-learn.
  2. ذلك أسلوب مُنظم لضبط المعاملات الفائقة Hyperparameters في نماذج التعلم الآلي للعثور على أفضل مجموعة من المعاملات الفائقة التي تُحسّن أداء النموذج كالدقة، السرعة وغيرهم بمعنى تُحدد المعاملات الفائقة التي تريد ضبطها كمُعدل التعلم learning rate وعدد الأشجار في Random Forest والمعاملات الأخرى، وتُحدد القيم المُحتملة لكل معامل كالتالي learning_rate = [0.01, 0.1, 1]. ويُنشئ Grid Search جميع التركيبات الممكنة من القيم المُحددة، أي لو لديك معاملين عدد الأشجار = [50, 100] والعمق الأقصى = [3, 5]، فالشبكة ستكون (50,3), (50,5), (100,3), (100,5). ولكل تركيبة، يُدرّب النموذج ويُقيّم أداؤه باستخدام تقنية مثل k-fold cross-validation، وتُختار التركيبة التي تعطي أفضل أداء بناءًا على مقياس مثل الدقة أو الـF1-score. from sklearn.model_selection import GridSearchCV from sklearn.ensemble import RandomForestClassifier model = RandomForestClassifier() param_grid = { 'n_estimators': [50, 100, 200], 'max_depth': [None, 10, 20], 'min_samples_split': [2, 5] } grid_search = GridSearchCV(model, param_grid, cv=5) grid_search.fit(X_train, y_train) print(grid_search.best_params_) لكن ذلك غير فعّال في حال بعض المعاملات غير مؤثرة.
  3. ستحتاج إلى رأس Content-Disposition لفرض التحميل، وإرسال محتوى الملف مباشرةً إلى المتصفح ثم حذف الملف من الخادم بعد التحميل لو أردت وذلك اختياري. <?php $host = 'localhost'; $user = 'root'; $pass = ''; $dbname = 'database_name'; // اسم الملف المؤقت على الخادم $backupFile = 'backup_' . $dbname . '_' . date('Y-m-d_H-i-s') . '.sql'; $command = "mysqldump -h $host -u $user"; if (!empty($pass)) { $command .= " -p$pass"; } $command .= " $dbname > $backupFile"; $returnValue = system($command, $output, $returnCode); if ($returnCode === 0 && file_exists($backupFile)) { header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="' . basename($backupFile) . '"'); header('Content-Length: ' . filesize($backupFile)); readfile($backupFile); unlink($backupFile); exit; } else { echo "<b>حدث خطأ أثناء عمل النسخة الاحتياطية:</b><br><br>"; echo "<b>قيمة الخروج من الأمر (Return Code):</b> " . $returnCode . "<br><br>"; if (!empty($output)) { echo "<b>رسائل الخطأ (إن وجدت):</b><pre>"; foreach ($output as $line) { echo htmlspecialchars($line) . "<br>"; } echo "</pre>"; } else { echo "<b>لم يتم الحصول على أي رسائل خطأ تفصيلية من الأمر.</b><br>"; } } ?> unlink($backupFile) لحذف الملف المؤقت $backupFile من الخادم، وكما أشرت إجراء اختياري، ومن الأفضل فعل ذلك حيث لا داعي للاحتفاظ بنسخة احتياطية على الخادم بعد تحميلها للحفاظ على أمن قاعدة البيانات.
  4. في الجهاز الأول الذي تشارك منه عليك السماح لحركة مرور Samba في جدار الحماية: sudo ufw allow samba sudo ufw reload حاول مرة أخرى إلغاء مشاركة المجلد الحالي، ثم أعد مشاركته بنفس الطريقة، ثم أعد تشغيل samba: sudo systemctl restart smbd بخصوص كلمة المرور، هل قمت بالإتصال عن طريق الضغط على registered user وليس anonymous.
  5. عليك التفكير في هيكل البيانات المناسب للمشكلة قبل الحل، فكتابة الكود هي أخر خطوة، لو استخدمت الكائنات سيؤدي إلى فقدان الأرقام المكررة لأن المفاتيح في الكائنات يجب أن تكون فريدة، استخدم مصفوفة لتخزين كل رقم مع وزنه. وحساب الوزن باستخدام reduce، لحساب مجموع الأرقام لكل عدد بطريقة أكثر كفاءة، ثم الترتيب باستخدام الوزن والترتيب الأبجدي أي عند تساوي الوزن، نقارن الأرقام كسلاسل نصية باستخدام ميثود localeCompare. وعليك معالجة الفراغات من خلال ميثودز trim() و split(/\s+/) للتأكد من التعامل مع الفراغات الزائدة بشكل صحيح. function orderWeight(strng) { const numbers = strng.trim().split(/\s+/).filter(n => n !== ''); if (numbers.length === 0) return ''; return numbers .map(num => ({ num, weight: num.split('').reduce((sum, digit) => sum + parseInt(digit, 10), 0) })) .sort((a, b) => { if (a.weight === b.weight) { return a.num.localeCompare(b.num); } return a.weight - b.weight; }) .map(entry => entry.num) .join(' '); } console.log(orderWeight("56 65 74 100 99 68 86 180 90")); ما قمت به هو تقسيم السلسلة المدخلة إلى مصفوفة من الأرقام مع تجاهل الفراغات الزائدة، وحساب الوزن لكل عدد: بحساب مجموع أرقامه بمعنى 100 هي 1+0+0 = 1. ثم نرتب المصفوفة حسب الوزن، وفي حالة التساوي نرتب أبجديًا، ثم إعادة تجميع النتيجة باستخراج الأرقام المرتبة ونضمّنها في سلسلة واحدة.
  6. الشخص الذي يستأجر العقار لفترة زمنية محددة هو المُستأجر، وذلك بموجب عقد إيجار يبرم مع مالك العقار وهو المؤجر، وحقوق المستأجر مستمدة بشكل أساسي من عقد الإيجار والقوانين المنظمة للعلاقة الإيجارية في بلدك. وتلك الحقوق هي الحق في الانتفاع بالعقار، السكن الهادئ والآمن، صيانة العقار، الخصوصية، تجديد عقد الإيجار في بعض الحالات وبشروط معينة، الحماية من الإخلاء التعسفي، الحصول على نسخة من عقد الإيجار والحقوق الأخرى المنصوص عليها في عقد الإيجار والقوانين المحلية، أي له حقوق مؤقتة بالإنتفاع بالعقار لفترة محددة بموجب العقد. أما المستفيد من العقار فهو الشخص الذي يستفيد من العقار بشكل أو بآخر، ولكن ليس بالضرورة أن يكون هو المستأجر أو المالك المباشر، أي المستفيد مصطلح أوسع وأشمل، يشمل المستفيد من الوقف الخيري أو الأهلي، المستفيد من الوصية أو الميراث، المستفيد من حق الانتفاع والمستفيد من عقد التأمين على العقار، ونطاق الحقوق واسع ومتنوع ويعتمد بشكل كبير على نوع الاستفادة الممنوحة وظروفها وتتراوح بين مؤقتة ودائمة.
  7. الدورة بمثابة تأهيل لدخول مجال البرمجة، وستتعلم بها الأساسيات اللازمة لإختيار المجال البرمجي المناسب الذي تريده والذي يتم إختياره حسب المطلوب في سوق العمل المراد العمل به أي الذي تستهدفه. ستتعلم بها ما يلي: أساسيات البرمجة بتعلم المنطق البرمجي أولاً من خلال سكراتش ثم تعلم كتابة الكود من خلال لغة برمجية وهي بايثون وجافاسكريبت ثم تعلم الخوارزميات وهياكل البيانات ثم تعلم مفاهيم أخرى خاصة بعلوم الحاسوب، ستجد تفصيل هنا:
  8. ستحتاجين إلى الإتصال بقاعدة البيانات من خلال PDO، ثم استعلام SQL لترتيب النتائج حسب التخصص مع ORDER BY specialty لضمان ترتيب النتائج حسب التخصص. ثم إنشاء مصفوفة جديدة $groupedStudents وتكرار خلال جميع الطلاب وتجميعهم حسب التخصص. ولكل تخصص يتم إنشاء جدول منفصل، مع استخدام حلقتين متداخلتين الأولى للتخصصات والثانية لعرض بيانات الطلاب داخل كل تخصص. كالتالي: <?php $host = 'localhost'; $dbname = 'اسم_قاعدة_البيانات'; $username = 'اسم_المستخدم'; $password = 'كلمة_المرور'; try { $conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $conn->prepare("SELECT * FROM students ORDER BY specialty"); $stmt->execute(); $students = $stmt->fetchAll(PDO::FETCH_ASSOC); $groupedStudents = []; foreach ($students as $student) { $specialty = $student['specialty']; if (!isset($groupedStudents[$specialty])) { $groupedStudents[$specialty] = []; } $groupedStudents[$specialty][] = $student; } if (!empty($groupedStudents)) { foreach ($groupedStudents as $specialty => $students) { echo "<h2>تخصص: $specialty</h2>"; echo "<table border='1'>"; echo "<tr><th>ID</th><th>الاسم</th><th>البريد الإلكتروني</th><th>التاريخ</th></tr>"; foreach ($students as $student) { echo "<tr>"; echo "<td>{$student['id']}</td>"; echo "<td>{$student['name']}</td>"; echo "<td>{$student['email']}</td>"; echo "<td>{$student['date']}</td>"; echo "</tr>"; } echo "</table><br>"; } } else { echo "لا توجد بيانات لعرضها"; } } catch(PDOException $e) { echo "خطأ في الاتصال: " . $e->getMessage(); } $conn = null; ?> بالطبع عليكِ تعديل أسماء الجدول والحقول لتتناسب مع قاعدة البيانات لديكِ.
  9. من الأفضل دراسة المسارات كما هي بالترتيب، فالدورات في الأكاديمية ممنهجة والمسارات مرتبة بشكل متدرج، ولن يؤثر ذلك على الدراسة فالمسارات في البداية هي تطبيقات بسيطة ومقدمة للمسارات المتقدمة الأخرى بدءًا من مسار تعلم الآلة Machine Learning، أي لن تحتاج إلى استيعاب لمكتبة pandas في البداية. عامًة الترتيب الذي ذكرته لا مشكلة به وتستطيع الدراسة من خلاله كما يحلو لك.
  10. لا نستخدم ذلك بشكل مباشر هنا، لأن النموذج الحالي مبني باستخدام طبقات بسيطة Dense, BatchNormalization بدون ميزات skip connections في ResNet أو التوصيلات الكثيفة dense blocks في DenseNet. لو أردت دمج مفاهيم ResNet أو DenseNet في النموذج، يجب تعديل بنية الطبقات كالتالي، أولاً تُضاف Residual Connections بين الطبقات، حيث يُضاف إخراج طبقة سابقة إلى إخراج طبقة لاحقة. وستقوم بتعديل جزء من الكود باستخدام Functional API لأن Sequential لا يدعم التوصيلات المتفرعة Residual Connections. from tensorflow.keras.layers import Add input_layer = keras.layers.Input(shape=(input_shape,)) x = keras.layers.Dense(8)(input_layer) x = keras.layers.BatchNormalization()(x) x = keras.layers.Activation('tanh')(x) residual = x x = keras.layers.Dense(128)(x) x = keras.layers.BatchNormalization()(x) x = keras.layers.Activation('tanh')(x) x = Add()([x, residual]) # إضافة الوصلة المتبقية هنا from tensorflow.keras.layers import Add input_layer = keras.layers.Input(shape=(input_shape,)) x = keras.layers.Dense(8)(input_layer) x = keras.layers.BatchNormalization()(x) x = keras.layers.Activation('tanh')(x) residual = x x = keras.layers.Dense(128)(x) x = keras.layers.BatchNormalization()(x) x = keras.layers.Activation('tanh')(x) x = Add()([x, residual]) # إضافة الوصلة المتبقية هنا # باقي الطبقات ثم تُضاف Dense Connections حيث يُوصَل إخراج كل طبقة سابقة كمدخل لجميع الطبقات اللاحقة في الـblock. from tensorflow.keras.layers import Concatenate def dense_block(x): x1 = keras.layers.Dense(128)(x) x1 = keras.layers.BatchNormalization()(x1) x1 = keras.layers.Activation('tanh')(x1) x = Concatenate()([x, x1]) # دمج الإخراج مع المدخلات الأصلية x2 = keras.layers.Dense(64)(x) x2 = keras.layers.BatchNormalization()(x2) x2 = keras.layers.Activation('tanh')(x2) x = Concatenate()([x, x2]) return x input_layer = keras.layers.Input(shape=(input_shape,)) x = dense_block(input_layer) وللحفاظ على بنية Sequential، الأفضل استخدام حزم جاهزة مثل tensorflow.keras.applications.ResNet50، لكن ذلك غير عملي للشبكات الصغيرة.
  11. الأمر يعتمد على طبيعة البيانات والخوارزمية المستخدمة، فالحالات التي يُمكن فيها تحسين TP وTN معًا هي عند تحسين عام في النموذج أي لو قمت بتحسين جودة النموذج بشكل عام مثل استخدام خوارزمية أكثر تعقيدًا، تحسين الميزات، أو معالجة البيانات بشكل أفضل، فقد يزيد كل من TP وTN معًا. بمعنى استخدام نموذج مثل Gradient Boosting بدلًا من Logistic Regression في حال البيانات غير خطية، ومعالجة البيانات المفقودة أو إزالة الضوضاء. الحالة الأخرى هي تحسين توازن الفئات في البيانات غير المتوازنة، باستخدام تقنيات مثل Oversampling كـ SMOTE للفئة الأقل، وClass weighting في الخوارزميات كزيادة وزن الفئة النادرة. او تحسين مساحة الميزات من خلال تقنيات مثل PCA أو Feature Engineering لفصل الفئتين بشكل أفضل. ستفاضل بينهم في حالات معينة، وهي عند تغيير عتبة التصنيف Threshold فسيتم زيادة TN أي تصنيف سلبي أكثر دقة، وانخفاض TP فبعض الإيجابيات الحقيقية تُصنف خطأً كسلبية، وتخفيض العتبة Threshold يؤدي إلى العكس أيضًا. وفي البيانات المتداخلة، فلو هناك تداخل كبير بين توزيعات الفئتين، فتحسين TP يتطلب تخفيض TN والعكس صحيح. ولتحسين كلاهما، تفقد الدقة Accuracy، فلو تحسنت سيتحسن TP و/أو TN مع تقليل الأخطاء FP وFN. أيضًا منحنى ROC-AUC، والذي يقيس الأداء العام بغض النظر عن العتبة، تحسنه يعني قدرة النموذج على التمييز بين الفئتين بشكل أفضل، وذلك يعزز كل من TP وTN معًا. وتأكد من أن النموذج لا ينحاز لفئة معينة، مع استخدام مقياس مثل F1-Score (يجمع بين Precision وRecall) أو G-Mean، بالإضافة إلى Grid Search أو Bayesian Optimization لتحسين معلمات النموذج.
  12. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  13. ربما بسبب الـ Overfitting، ويحدث التدريب الزائد أو فرط التخصص في حال تعلم النموذج بيانات التدريب بشكل جيد جدًا، لدرجة أنه يبدأ في حفظ الضوضاء أو التفاصيل غير المهمة في بيانات التدريب، بالتالي يصبح النموذج جيدًا جدًا في التنبؤ ببيانات التدريب، ولكنه لا يؤدي أداءً جيدًا على البيانات الجديدة التي لم يرها من قبل أي بيانات التحقق، وارتفاع دقة التدريب مع ثبات دقة التحقق يعني مشكلة تدريب زائد. أو ربما مشكلة في بيانات التحقق ففي حال صغيرة جدًا، لن تكون ممثلة بشكل جيد للبيانات الحقيقية، وذلك يجعل دقة التحقق غير مستقرة أو لا تعكس الأداء الحقيقي للنموذج، وأيضًا لو مختلفة بشكل كبير عن بيانات التدريب من حيث التوزيع أو الخصائص، فلن يكون النموذج قادرًا على التعميم بشكل جيد عليها. أو معدل التعلم غير المناسب Learning Rate فعند إرتفاعه بشكل كبير مرتفعًا فسيتجاوز النموذج الحد الأمثل ولا يتمكن من الاستقرار على حل جيد لبيانات التحقق، ولو منخفضًا جدًا، فسيستغرق النموذج وقتًا طويلاً للتعلم على بيانات التحقق، أو لا يتعلم بشكل فعال على الإطلاق.
  14. آلية الإختبار هي كالتالي: إجراء محادثة صوتيّة لمدة 30 دقيقة يطرح المدرّب عليك أسئلة متعلّقة بالدورة والأمور التي نفّذتها خلالها. يحدد لك المدرّب مشروعًا مرتبطًا بما قمت به أثناء الدورة لتنفيذه خلال فترة محددة تتراوح بين أسبوع إلى أسبوعين. إجراء محادثة صوتيّة أخرى لمدّة 30 دقيقة يناقش بها مشروعك وما نفذته وتُطرح أسئلة خلالها. إن سارت على جميع الخطوات السابقة بشكل صحيح، تحصل على الشهادة أو يرشدك المدرّب لأماكن القصور ويطلب منك تداركها ثم التواصل معنا من جديد.
  15. بعد إنهاء 4 مسارات من الدورة على الأقل، أو الدورة بالكامل عليك رفع المشاريع التي قمت بها بالدورة على حسابك في github، ثم التحدث لمركز المساعدة وإخبارهم أنك تريد التقدم للإختبار وتوفير روابط المشاريع على github. ثم الإنتظار لبعض الوقت لحين مراجعة المشاريع وسيتم الرد عليك، وتحديد موعد لإجراء مقابلة.
  16. ليس بالضرورة، الأهم هو التوازن بين الدقتين، فارتفاع دقة التدريب مع ارتفاع دقة التحقق مع تقارب بينهما يعني أن النموذج يتعلم بشكل فعال ويُعمَّم جيدًا على البيانات الجديدة. ولو ارتفعت دقة التدريب كثيرًا بينما توقفت دقة التحقق أو انخفضت، فتدل على الإفراط في التخصيص حيث يحفظ النموذج بيانات التدريب بدلًا من تعلم الأنماط العامة. أيضًا استقرار دقة التحقق، فالهدف الرئيسي هو تحقيق دقة تحقق عالية ومستقرة، حتى لو توقفت دقة التدريب عن الزيادة، وأحيانًا تكون الزيادة المستمرة في دقة التدريب مع تراجع التحقق علامة سلبية على Overfitting. وعليك مراقبة الفرق بين الدقتين، الفرق الكبير بين دقة التدريب والتحقق مثل 98% تدريب مقابل 75% تحقق يشيران إلى مشكلة في التعميم، أما الفرق الصغير 90% تدريب مقابل 88% تحقق يُعتبر مؤشرًا جيدًا على توازن النموذج. وللعلم في مراحل التدريب أي في المراحل الأولى، من الطبيعي أن تزيد كلتا الدقتين معًا، ولاحقًا، ربما تستمر دقة التدريب في الزيادة بسبب تحسين النموذج لتفاصيل البيانات، لكن يجب ألا تتدهور دقة التحقق بشكل ملحوظ. ولا تعتمد فقط على الدقة، تتبع الخسارة Loss أثناء التدريب، فأحيانًا تتحسن الدقة مع زيادة الخسارة في بيانات التحقق، وذلك يعتبر مشكلة، واستخدم مقاييس أخرى مثل Precision، وRecall، أو منحنى ROC حسب طبيعة المهمة.
  17. عليك تثبيت Dart SDK من خلال الرابط التالي: https://docs.flutter.dev/get-started/install وربما المشكلة أن برنامج الحماية من الفيروسات لديك يقوم بحذف ملف dart.exe لذا بعد إعادة التثبيت من الرابط السابق، قم باستثناء مجلد D:\scr\flutter من برنامج الحماية لكي لا يقوم بعمل Scan على ملفاته.
  18. بالطبع، Batch Normalization تعمل على تثبيت التوزيع الإحصائي للمدخلات عن طريق تعديل المتوسط والتباين للدفعة batch أثناء التدريب، وDropout يغير التوزيع بشكل عشوائي عن طريق إسقاط بعض الوحدات neurons، وذلك يتعارض مع جهود BN لتوحيد المدخلات. بالتالي تقلبات أكبر في إحصائيات BN كالمتوسط والتباين، وصعوبة في تقارب النموذج بسبب عدم استقرار التوزيعات. الترتيب الأمثل هو طبقة Dense ثم Batch Normalization ثم وظيفة التنشيط Activation ثم Dropout، وفي حال تطبيق Dropout قبل BN، فإن إسقاط الوحدات العشوائي سيؤثر على إحصائيات الدفعة التي تعتمد عليها BN، وسيؤدي إلى نتائج غير متوقعة. عامًة جرب ترتيبات مختلفة، وخفِّض معدل الإسقاط مثل 0.2 بدلًا من 0.5 في حال تستخدم BN، ولو لاحظت تراجعًا في دقة التدريب underfitting أو تقلبات كبيرة، فقلل من استخدام Dropout أو BN.
  19. عليك تثبيت: sudo apt install nautilus-share
  20. أسهل طريقة هي بالضغط على المجلد بزر الفأرة الأيمن ثم اختر local network share ثم اضغط على share this folder وسيظهر لك رسالة تخبرك بأنك بحاجة إلى تثبيت service لمشاركة الملفات، اضغط على install وسيتم تثبيت samba. بعد الإنتهاء من التثبيت، اضغط على الخيار guest access وأيضًا allow others to create and delete ثم اضغط على create share: الآن عليك تفقد ما هو عنوان الـ IP الخاص بالحاسوب الذي تقوم بمشاركة الملفات منه، وذلك من خلال تنفيذ الأمر التالي: ip add ستجده بجانب كلمة inet انسخه وضعه في مكان لاستخدامه على الحاسوب الآخر. الآن افتح منفذ الأوامر terminal واكتب به التالي: sudo smbpasswd -a اسم المستخدم استبدل اسم المستخدم باسم المستخدم الذي تريده أيًا يكن وسيطلب منك كتابة الباسورد مرتين وتذكره جيدًا وذلك الباسورد سيكون خاص بذلك المستخدم على Samba أي ليس المقصود الباسورد الخاص بالمستخدم الخاص بك على ubuntu. ثم تنفيذ الأمر التالي أيضًا: sudo systemctl restart smbd توجه الآن للحاسوب الآخر ومن مدير الملفات اضغط على other locations وستجد بالأسفل حقل بجانبه connect to server اكتب به التالي: smb://120.20.30.60/ استبدل 120.20.30.60 بعنوان الـ IP الخاص بالحاسوب الآخر والذي حصلنا عليه منذ قليل. ثم اضغط على connect: ستجد المجلد الذي شاركته اضغط عليه ثم اختر registered user ثم اكتب اسم المستخدم الذي أنشأته منذ قليل وكلمة المرور ثم اضغط على connect.
  21. هناك أمر يجب توضيحه TanStack Query هي أدارة لإدارة حالة التطبيق لكن هي async أي بيانات لا تصل إليها مباشرًة بل من الخادم، بينما لو لديك بيانات non-async فلا حاجة إليها استخدم Zustand، وللعلم تستطيع استخدام كلاهما لا مشكلة. أيضًا لما لا تستخدم RTK Query معRedux Toolkit. createContext مع localStorage حل مقبول للمشاريع الصغيرة إلى المتوسطة، خاصةً لو البيانات محدودة ولا تحتاج إلى تحديثات متكررة، أي لا يتطلب إضافة مكتبات خارجية ويدعم تحديث الواجهة تلقائيًا عند تغيير الحالة ويناسب الحالات البسيطة مثل تخزين بيانات المستخدم الأساسية. لكن هناك سلبيات منها إعادة التصيير Re-renders، حيث أي تغيير في الحالة يؤدي إلى إعادة تصيير جميع المكونات المشتركة في الـ contextK ,يحتاج إلى تعليمات يدوية لمزامنة الحالة مع localStorage مثل useEffect. أيضًا localStorage غير مشفر، وذلك يعرض البيانات الحساسة للاختراق ويفضل استخدام HTTP-only Cookies للـ Tokens. بالتالي الأفضل استخدام Zustand مع Middleware للتخزين المحلي وهو الأنسب للمشاريع المتوسطة والكبيرة. import { create } from 'zustand'; import { persist } from 'zustand/middleware'; const useAuthStore = create( persist( (set) => ({ user: null, login: (user) => set({ user }), logout: () => set({ user: null }), }), { name: 'auth-storage', getStorage: () => localStorage, } ) ); const user = useAuthStore((state) => state.user); أو دمج TanStack Query مع التخزين المحلي باستخدام onSuccess في mutation وستتمكن من تسجيل الدخول لحفظ البيانات مباشرة في localStorage، واستخدام QueryClient لقراءتها لاحقًا. const { mutate: login } = useMutation({ mutationFn: loginApi, onSuccess: (data) => { localStorage.setItem('user', JSON.stringify(data.user)); queryClient.setQueryData(['user'], data.user); }, }); const user = JSON.parse(localStorage.getItem('user') || 'null'); const queryClient = useQueryClient(); queryClient.setQueryData(['user'], user);
  22. ستجدين أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  23. الأمر يتم على مستودع المشروع على GitHub حيث ستقوم بكتابة وصف للمشروع وطريقة استخدامه في ملف readme.md. من الممكن اتباع منهجية CRISP-DM (Cross-Industry Standard Process for Data Mining) كإطار عمل رئيسي، مع تكييفها لتناسب المشروع، بمعنى سيتم سرد وصف المشروع من خلال مراحل دورة حياة المشروع كالتالي: 1- الهدف من المشروع Business Understanding أي تحديد المشكلة التي كنت تواجهها، وهي تحليل توزيع الزبائن الجغرافي لتحسين الحملات التسويقية أو التخصيص، ثم حدد كيف ستقيس نجاح المشروع، أي ما هي المقاييس التي ستعتمد عليها لتقييم أداء النموذج KPIs؟ كدقة تحليل التوزيع، الفائدة المتحققة من القرارات المبنية على التحليل، إلخ. 2- استيعاب البيانات وجمعها Data Understanding وذلك بجمع بيانات المتجر كعناوين الشحن، IP الزبائن، وسجلات الطلبات. ثم تحليل أولي للبيانات لاكتشاف الأنماط أو المشكلات مثل قيم مفقودة في حقول البلدان، وذلك يُعرف باسم Exploratory Data Analysis - EDA أي تحديد مصادر البيانات وأنواعها وجودتها أي وثق أي تحديات متوقعة في جودة البيانات وكيف ستتعامل معها (البيانات المفقودة، البيانات غير الدقيقة وخلافه). 3- تحضير البيانات Data Preparation من خلال تنظيف البيانات كتصحيح أسماء البلدان وحذف البيانات غير المكتملة، ثم دمج البيانات من مصادر مختلفة مثل CRM وسجلات المبيعات، ثم تحويل البيانات إلى تنسيق مناسب كترميز البلدان برموز ISO. أي تحديد مرحلة تنظيف البيانات وتحويلها وتنفيذ تكامل البيانات في حال تم جمعها من مصادر مختلفة وكيف قمت بدمجها. 4- النمذجة Modeling باستخدام خوارزميات التجميع Clustering مثل K-Means أو خوارزميات التصنيف Classification حسب الهدف، والأدوات التي استخدمتها في ذلك مثل Python (Pandas, Scikit-learn) أو منصات مثل Tableau. 5- التقييم Evaluation أي وضح كيف ستقيم النموذج أو التحليل الإحصائي، مثل مقاييس Silhouette Score للتجميع. 6- النشر Deployment بتوضيح كيف قمت بدمج ذلك في المتجر، وهل سيتم عرضها في لوحة معلومات للمديرين؟ هل ستستخدم لتخصيص حملات تسويقية؟ هل ستدمج مع نظام إدارة علاقات العملاء (CRM)؟ ولو أردت تستطيع وضع أقسام توضح بها الأداء والموثوقية وأيضًا حالات الاستخدام Use Cases. بخصوص متطلبات النظام، فتنقسم إلى متطلبات وظيفية Functional Requirements وغير وظيفية Non-Functional. الأولى يندرج أسفلها جمع البيانات كستيراد البيانات من قواعد بيانات المتجر مثل MySQL, PostgreSQL، ودمج بيانات من مصادر خارجية مثل APIs جغرافية لتحديد الموقع من IP. ثم معالجة البيانات بتصنيف الزبائن حسب البلدان بدقة عالية وتوفير إمكانية تصفية البيانات حسب الفترات الزمنية. ثم التصور والتحليل بعرض خرائط حرارية Heatmaps لتوزيع الزبائن، وتوليد تقارير تفصيلية (PDF/Excel) بنسب التوزيع. ثم التكامل مع أدوات التسويق كـ Mailchimp لإرسال حملات مخصصة حسب المنطقة. ثم الأمان لتأمين البيانات الحساسة كعناوين الزبائن وفقًا لـ GDPR في حال الاستخدام في منطقة أوروبا. أما الغير وظيفية فهي: الأداء ستحتاج إلى معالجة البيانات في وقت لا يتجاوز 10 دقائق لكل مليون سجل. القابلية للتوسع بدعم زيادة حجم البيانات بنسبة 20% سنويًا. سهولة الاستخدام من خلال واجهة مستخدم بسيطة مع إمكانية تصدير البيانات بنقرة واحدة. التوافق والعمل على أنظمة تشغيل مختلفة Windows, Linux.
  24. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  25. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
×
×
  • أضف...