-
المساهمات
35 -
تاريخ الانضمام
-
تاريخ آخر زيارة
آخر الزوار
لوحة آخر الزوار معطلة ولن تظهر للأعضاء
إنجازات Bassel Alkhatib
عضو مساهم (2/3)
9
السمعة بالموقع
-
تُناسب بايثون الكثير من التطبيقات البرمجية نظرًا لتمتعها بالعديد من المزايا المهمة كالمرونة العالية وتوفير المكتبات الجاهزة فيها للقيام بعمليات الأتمتة وتحليل البيانات ومعالجة مسائل تعلم الآلة والتطوير الخلفي back-end وغيرها من المهام البرمجية بسرعة وسهولة. ظهرت النسخة الأولى منها في عام 1991 وسُميت تيمنًا بالفرقة الكوميدية البريطانية Monty Python هادفة جعل كتابة الكود فيها أمرًا ممتعًا، ويعد الإصدار الثالث أحدث نسخة وهو المستقبل الواعد لبايثون. يعرض هذا المقال خطوات تثبيت بيئة بايثون على الحاسوب المحلي أو الخادم البعيد لتطبيق المشاريع العملية اللاحقة في الكتاب، أما إذا كان بايثون مع أدواته pip و venv جاهزًا على حاسوبك فيُمكنك الانتقال مباشرة إلى الفصل التالي. المتطلبات الرئيسية نعمل في بيئة لينكس Linux أو الشبيهة بيونكس Unix-like ونستخدم ضمن نظام التشغيل ماكنتوش macOS سطر الأوامر command line أو بيئة الطرفية terminal environment، أما في نظام ويندوز، فيمكن استعمال بورشيل PowerShell لتحقيق نفس النتائج عمليًا. الخطوة الأولى: تثبيت بايثون يثبت بايثون على العديد من أنظمة التشغيل بشكل افتراضي. للتأكد من وجود الإصدار 3 من بايثون مثبتًا على جهازك قم بفتح نافذة طرفية واكتب فيها ما يلي: python3 -V سيظهر، في حال كون الإصدار 3 من بايثون مثبتًا، رقم الإصدار والذي يُمكن بالطبع أن يختلف حسب النسخة المُنصبة، وفي جميع الأحوال، يكون الخرج مشابهًا لما يلي: Python 3.7.2 في حال لم تحصل على الإظهار السابق، فعليك أولًا تنزيل النسخة من موقع بايثون python.org ومن ثم اتباع خطوات التثبيت المُحدّدة. بعد انتهائك من تثبيت بايثون وتأكدك من ذلك بمعاينة رقم الإصدار باتباع التعليمة السابقة يُمكنك الانتقال للخطوة التالية. الخطوة الثانية: تثبيت pip يجب تثبيت الأداة pip والتي تسمح بتثبيت وإدارة حزم البرمجيات المساندة لبايثون. ستكون هذه الأداة جاهزة فيما لو قمت بتثبيت بايثون من الموقع python.org، أما إذ كنت على خادم أو حاسوب بتوزيعة أبنتو Ubuntu أو ديبيان Debian فيُمكنك تنزيل pip بكتابة ما يلي: sudo apt install -y python3-pip من الآن فصاعدًا، يُمكنك تنزيل أي حزمة برمجيات بكتابة: pip3 install package_name حيث package_name هي اسم أي مكتبة أو حزمة برمجية لبايثون مثل جانغو Django لتطوير مواقع الويب والحزمة NumPy للحسابات العلمية، فإذا كنت مثلًا تريد استخدام المكتبة NumPy فعليك تنزيلها بكتابة الأمر التالي: install numpy يوجد بعض الحزم البرمجية الأساسية الواجب تحميلها للحصول على بيئة عمل مريحة ومرنة: sudo apt install build-essential libssl-dev libffi-dev python3-dev يُمكن الآن بعد الانتهاء من المراحل السابقة إعداد بيئة عمل افتراضية. الخطوة الثالثة: إعداد بيئة عمل افتراضية تسمح بيئة العمل الافتراضية بعزل كل مشروع مع حزمه البرمجية التابعة له عن بقية المشاريع الأخرى وذلك عن طريق تخصيص مساحة خاصة له على الخادم، مما يسمح أيضًا بتنظيم الإصدارات المختلفة للمشروع. وهو أمر ضروري لاسيما عند استخدامنا لحزم برمجية خارجية. يُمكن إنشاء بيئة عمل افتراضية لكل مشروع وهي عمليًا عبارة عن مجلد معين على الخادم مع بعض الشيفرات البرمجية ضمنه. نستخدم عادةً الأداة venv لإنشاء بيئة عمل افتراضية والتي هي جزء من مكتبة بايثون وتُثبت تلقائيًا خلال تثبيت بايثون. إذ كنت على خادم أو حاسوب Ubuntu أو Debian فيُمكنك تحميل venv بكتابة ما يلي: sudo apt install -y python3-venv انتقل لمجلد معين على حاسوبك لوضع بيئة العمل فيه أو قم بإنشاء مجلد جديد باستخدام تعليمة إنشاء مجلد mkdir ثم انتقل له باستخدام تعليمة الانتقال لمجلد cd كما يلي: mkdir environments cd environments يُمكنك الآن إنشاء بيئة العمل ضمن المجلد الذي انتقلت له وذلك بكتابة ما يلي: python3.6 -m venv my_env حيث my_env هو اسم بيئة العمل الذي تريده، مع ملاحظة كتابة القسم الأول من رقم الإصدار الذي حصلت عليه سابقًا باستخدام python -V (المثال أعلاه يستخدم الإصدار Python 3.6.3). لو كُنت مثلًا تستخدم الإصدار Python 3.7.3 فعليك كتابة: python3.7 -m venv my_env يسمح لك ويندوز بتجاهل رقم الإصدار كليةً وكتابة ما يلي: python -m venv my_env بعد تنفيذ الأمر المناسب لإنشاء بيئة العمل، يُمكن التأكد من إتمام العملية بالاستمرار في الخطوات التالية والتي من أولها معاينة الملفات التي قام venv بإنشائها في المجلد الموافق والتي يُمكن إظهارها باستخدام أمر استعراض محتوى مجلد ls: ls my_env ليكون الخرج: bin include lib lib64 pyvenv.cfg share تعمل هذه الملفات على التأكد من العزل الكامل لملفات مشروعك عن باقي ملفات حاسوبك وبذا فلن تختلط ملفاتك مع ملفات نظام التشغيل أبدًا. تسمح هذه الممارسة الجيدة في التحكم بالإصدارات المختلفة للمشروع والتأكد من أن مشروعك يستخدم الحزم البرمجية التي يحتاج إليها. يُمكن استخدام الحزمة البرمجية الجاهزة Python Wheels التي تسمح بتسريع عملية تطوير البرمجيات وتنفيذ المشروع والموجودة في المجلد share في Ubuntu 18.04، ويجب تفعيل هذه الحزمة قبل بدء استخدامها بكتابة الأمر التالي والذي يقوم باستدعاء السكربت activate: source my_env/bin/activate من الآن فصاعدًا، ستبدأ أوامرك باسم بيئة العمل (المدعوة في أمثلتنا my_env). يُمكن للبادئة أن تظهر أحيانًا بشكل مختلف وذلك حسب الإصدار المستخدم من لينكس ديبيان Debian Linux إلا أنه، وفي جميع الأحوال، يجب أن تبدأ أوامرك باسم بيئة العمل ضمن قوسين: (my_env) sammy@sammy:~/environments$ تُحدّد هذه البادئة بأن بيئة العمل my_env هي البيئة النشطة الحالية مما يعني أنه عندما نُنشئ برامج هنا فستستخدم إعدادات ومكتبات هذه البيئة. لاحظ أنه يُمكنك ضمن بيئة العمل الافتراضية استخدام python عوضًا عن python3 و pip عوضًا عن pip3 إن وجدت ذلك مناسبًا. أما خارج بيئة العمل الافتراضية فلا يُمكنك القيام بذلك بل عليك استخدام python3 و pip3. الخطوة الرابعة: إنشاء البرنامج الأول يُمكنك الآن إنشاء البرنامج التقليدي الترحيبي الأول "Hello, World" مما يسمح لك بالتأكد من جاهزية بيئة العمل. افتح مثلًا محرر النصوص nano وأنشئ ملفًا جديدًا: (my_env) sammy@sammy:~/environments$ nano hello.py ثم اكتب في نافذة المحرر المفتوحة أول برنامج بسيط في بايثون: print("Hello, World!") أغلق المحرر nano بالضغط على الاختصار Ctrl+X ولا تنسَ حفظ الملف بالإجابة بنعم y عندما تُسأل عن حفظ الملف. بعد إغلاق nano والعودة لصدفة shell النظام، يُمكنك تنفيذ البرنامج السابق hello.py: (my_env) sammy@sammy:~/environments$ python hello.py والذي سيُظهر على المحطة الطرفية: Hello, World! للخروج من بيئة العمل والعودة للمجلد الأساسي، نفذّ الأمر: deactivate النتائج لقد حصلت نتيجة تطبيقك للخطوات السابقة على بيئة بايثون جاهزة لاحتضان المشاريع البرمجية على حاسوبك ويُمكنك الآن الانطلاق في تطبيق المشاريع البرمجية في الفصول التالية! إن أردت التعرف أكثر على بايثون، فيمكنك الرجوع إلى كتاب البرمجة بلغة بايثون. اقرأ أيضًا المرجع الشامل إلى تعلم لغة بايثون التواصل مع نظام التشغيل عبر بايثون النسخة الكاملة من كتاب البرمجة بلغة بايثون
-
تُعدّ مسألة تقييم نماذج تعلم الآلة، أي حساب مجموعة من مقاييس تقييم الأداء والتي تُبرهن على وصول النموذج المُتعلم إلى درجة جيدة من التعلم وبحيث يُمكن الاعتماد عليه واستخدامه في مسألة ما، أمرًا أساسيًا في مسائل تعلم الآلة. تسمح هذه المقاييس، في نهاية المطاف، بالمقارنة بين مختلف نماذج التعلم المُمكن استخدامها (والتي يولد كل منها باستخدام خوارزمية ما معينة)، مما يسمح باختيار الأنسب منها. نعرض في هذه المقالة مجموعة المقاييس الأكثر استخدامًا لتقييم نماذج تعلم التصنيف classification وتقييم نماذج الانحدار regression ومن ثم نعرض كيفية المقارنة بين عدة نماذج تعلم ممكنة واختيار الأفضل منها. مقاييس تقييم نماذج تعلم التصنيف تهدف نماذج تعلم التصنيف إلى بناء مُصنف يُمكن استخدامه لتصنيف غرض ما إلى صف مُعين مثلًا ليكن لدينا مسألة تعلم تصنيف صورة إلى كلب أو قط، وبفرض أن لدينا عشرة صور لها قيم الصفوف التالية (كلب أم قط): Actual values = ['cat', 'dog', 'cat', 'dog', 'cat', 'cat', 'dog', 'cat, 'dog', 'cat'] وبفرض أن نموذج تصنيف أعطى التصنيفات التالية لنفس الصور (ندعوها عادًة تنبؤ نموذج التعلم): Predicted values = ['cat', 'cat', 'cat', 'dog', 'cat', 'cat', 'dog', 'dog', 'dog', 'dog'] من الواضح أن نموذج التصنيف أصاب في بعض الحالات وأخطأ في البعض الآخر. والسؤال المطروح هنا بشكل أساسي: ما كفاءة (تقييم) هذا النموذج؟ مصفوفة الارتباك confusion matrix وهي عبارة عن جدول يُستخدم لبيان كفاءة نموذج تعلم التصنيف، إذ يعرض عدد حالات الصواب والخطأ المُمكنة المختلفة. يُبين الجدول التالي مثلًا الحالات المختلفة في المثال السابق (ندعو، للتبسيط، صف الكلب بالموجب وصف القط بالسالب): table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } تنبؤ نموذج التصنيف القيمة الحقيقية: كلب (موجب) القيمة الحقيقية: قط (سالب) كلب (موجب) 3 1 قط (سالب) 2 4 يُبين الجدول السابق أن نموذج التعلم أصاب في 3 حالات (الحقيقة: كلب / التنبؤ: كلب) + 4 حالات (الحقيقة: قط / التنبؤ: قط) = 7 حالات. وأخطأ في حالتين (الحقيقة: كلب / التنبؤ: قط) + حالة (الحقيقة: قط / التنبؤ: كلب) = 3 حالات. تنبؤ نموذج التصنيف القيمة الحقيقية: (موجب) القيمة الحقيقية: (سالب) موجب عدد الحالات الصحيحة الموجبة عدد الحالات الخاطئة الموجبة سالب عدد الحالات الخاطئة السالبة عدد الحالات الصحيحة السالبة الحالات الصحيحة الموجبة True Positive الحالات الصحيحة الموجبة True Positive وتختصر إلى TP وهي الحالات التي يكون من أجلها تنبؤ النموذج موجب والقيمة الحقيقة موجب (تنبؤ صحيح). الحالات الصحيحة السالبة True Negative الحالات الصحيحة السالبة True Negative وتختصر إلى TN وهي الحالات التي يكون من أجلها تنبؤ النموذج سالب والقيمة الحقيقة سالب (تنبؤ صحيح). الحالات الخاطئة الموجبة False Positive (FP) الحالات الخاطئة الموجبة False Positive وتختصر إلى FP وهي الحالات التي يكون من أجلها تنبؤ النموذج موجب والقيمة الحقيقة سالب (تنبؤ خاطئ). الحالات الخاطئة السالبة False Negative (FN) الحالات الخاطئة السالبة False Negative وتختصر إلى FN وهي الحالات التي يكون من أجلها تنبؤ النموذج سالب والقيمة الحقيقة موجب (تنبؤ خاطئ). مقياس الصحة Accuracy مقياس الصحة Accuracy وهو نسبة التصنيفات الصحيحة من العدد الكلي للأمثلة: ????????= (??+??)/(??+??+??+??) * 100 تكون الصحة في مثالنا السابق: ????????= (3+4)/10 * 100 = 70% مقياس الدقة Precision مقياس الدقة Precision هو نسبة التصنيفات الصحيحة للأمثلة الموجبة على العدد الكلي للأمثلة التي صُنّفت موجبة: ?????????= ??/(??+??) * 100 تكون الدقة في مثالنا السابق: ?????????= 3/(3+1) * 100 = 75% مقياس الاستذكار Recall مقياس الاستذكار Recall هو نسبة التصنيفات الصحيحة للأمثلة الموجبة على العدد الكلي للأمثلة الموجبة (يُدعى هذا المقياس أيضًا بالحساسية Sensitivity أو نسبة الموجب الصحيح True Positive Rate): ??????= ??/(??+??) * 100 يكون الاستذكار في مثالنا السابق: ??????= 3/(3+2) * 100 = 60% المقياس F1 المقياس F1 وهو مقياس يوازن بين الدقة والاستذكار في قيمة واحدة: ?1−?????= (2∗?????????∗??????)/(?????????+??????) يكون F1 في مثالنا السابق: ?1−?????= (2∗75∗60)/(75+60) = 66.66% الخصوصية Specificity الخصوصية Specificity هو نسبة التصنيفات الخاطئة للأمثلة الموجبة على العدد الكلي للأمثلة السالبة (يُدعى هذا المقياس أيضًا بنسبة الموجب الخاطئ False Positive Rate): ???= ??/(??+??) * 100 تكون الخصوصية في مثالنا السابق: ???= 1/(1+4) * 100 = 20% حساب مقاييس الأداء في بايثون توفر المكتبة sklearn.metrics في بايثون إمكانية حساب كل المقاييس السابقة، كما تُبين الشيفرة البرمجية التالية: # تقييم نماذج التصنيف from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score from sklearn.metrics import precision_score from sklearn.metrics import recall_score from sklearn.metrics import f1_score # الصفوف actual = ['cat', 'dog', 'cat', 'dog', 'cat', 'cat', 'dog', 'cat', 'dog', 'cat'] # التنيؤ predicted = ['cat', 'cat', 'cat', 'dog', 'cat', 'cat', 'dog', 'dog', 'dog', 'dog'] # مصفوفة الارتباك cf_matrix = confusion_matrix(actual , predicted, labels=["dog", "cat"] ) print ('Confusion Matrix :') print (cf_matrix) # مقاييس الأداء print ('Accuracy Score :{:.2f}'.format(accuracy_score(actual, predicted)*100)) print ('Precision Score :{:.2f}'.format(precision_score(actual, predicted, pos_label='dog')*100)) print ('Recall Score :{:.2f}'.format(recall_score(actual, predicted, pos_label='dog')*100)) print ('F1 Score :{:.2f}'.format(f1_score(actual, predicted, pos_label='dog')*100)) print ('Specificity :{:.2f}'.format(cf_matrix[0,1]/(cf_matrix[0,1]+cf_matrix[1,1])*100)) نستخدم في الشيفرة السابقة كل من الدوال التالية والتي يكون لها معاملين هما قائمة القيم الحقيقية وقائمة قيم التنبؤ: الوصف الدالة حساب مصفوفة الارتباك confusion_matrix حساب الصحة accuracy_score حساب الدقة precision_score حساب الاستذكار recall_score حساب F1 f1_score تكون نتائج مثالنا: Confusion Matrix : [[3 1] [2 4]] Accuracy Score :70.00 Precision Score :60.00 Recall Score :75.00 F1 Score :66.67 يُمكن أيضًا رسم مصفوفة الارتباك باستخدام المكتبة seaborn كما يلي: import seaborn as sns sns.heatmap(cf_matrix, annot=True) مما يُظهر الشكل التالي: خصائص المُستقبل التشغيلية ROC خصائص المُستقبل التشغيلية ROC -اختصار Receiver Operating Characteristic- هو منحني يُبين كفاءة نموذج التصنيف في قدرته على الفصل بين الصفوف الموجبة والسالبة. كي يكون نموذج تصنيف ممتازًا، يجب أن يصل إلى الزاوية العليا اليسارية أي أن تكون نسبة الصفوف الموجبة الصحيحة (الاستذكار) TPR أقرب للواحد، ونسبة الصفوف الموجبة الخاطئة (الخصوصية) FPR أقرب للصفر. يُبين الشكل التالي منحنيات ROC مختلفة ممكنة. كلما اقتربنا من أعلى اليسار كان المُصنّف أفضل: المساحة تحت المنحني AUC كلما كانت المساحة AUC -اختصار Area Under the Curve- تحت منحني ROC أكبر (أقرب من الواحد)، كان المُصنّف أفضل (لأن ذلك يعني أن المنحني أقرب للأعلى يسارًا). يُمكن رسم منحني ROC في بايثون وحساب المساحة تحت المنحني AUC كما تُبين الشيفرة البرمجية التالية لمثالنا السابق: # مكتبة الترميز from sklearn.preprocessing import LabelEncoder # الصفوف actual = ['cat', 'dog', 'cat', 'dog', 'cat', 'cat', 'dog', 'cat', 'dog', 'cat'] # التنيؤ predicted = ['cat', 'cat', 'cat', 'dog', 'cat', 'cat', 'dog', 'dog', 'dog', 'dog'] # ترميز الصفوف le = LabelEncoder() # ترميز الصفوف كأرقام actual=le.fit_transform(actual) # ترميز التنبؤ كأرقام predicted = le.fit_transform(predicted) # مكتبة المقاييس اللازمة from sklearn import metrics # مكتبة الرسم import matplotlib.pyplot as plt # حساب المقاييس fpr, tpr, _ = metrics.roc_curve(actual, predicted) auc = metrics.roc_auc_score(actual, predicted) # رسم المنحني plt.plot(fpr,tpr,label="AUC="+str(auc)) plt.ylabel('True Positive Rate') plt.xlabel('False Positive Rate') plt.legend(loc=4) plt.show() لاحظ استخدام الصف LabelEncoder من المكتبة sklearn.preprocessing لترميز الصفوف كأرقام. يكون الإظهار: لاحظ أن المساحة تحت المنحني تُساوي إلى 0.75 مما يعني أن المُصنف جيد نسبيًا. تقييم نماذج الانحدار نُذكّر أولًا بأن الهدف من نماذج الانحدار هو التنبؤ بقيمة رقمية y انطلاقًا من قيمة (أو مجموعة من القيم) x. ليكن لدينا مثلًا جدول بيانات التدريب التالي والذي يُعطي عدد الأعطال لآلة وفق عمر الآلة بالسنوات: Failures Age 15 10 30 20 40 40 55 50 75 70 90 90 يُبين الشكل التالي هذه النقاط على محور العمر Age والأعطال Failures: يُعدّ الانحدار الخطي linear regression من أكثر أنواع الانحدار استخدامًا نظرًا لبساطته في كل من التعلم والتنبؤ، فيُمكن مثلًا أن يتلائم fit الانحدار الخطي مع البيانات السابقة ليولد المستقيم التالي: يُمكن حساب التنبؤ Predictions لكل من قيم الجدول السابق باستخدام معادلة المستقيم الناتجة عن نموذج الانحدار، مما يُعطي: Failures Age Predictions 15 10 26 30 20 32 40 40 44 55 50 50 75 70 62 90 90 74 يُمكن الآن قياس مدى ملائمة المستقيم للبيانات بحساب المسافة بين النقاط الأساسية والمستقيم، وذلك بحساب الأخطاء Errors الحاصلة أي الفروقات بين القيم الأساسية و قيم التنبؤ، كما يُبين الجدول التالي: Errors Predictions Failures Age 11 26 15 10 2 32 30 20 4 44 40 40 -5 50 55 50 -13 62 75 70 -16 74 90 90 يُبين الشكل التالي هذه الفروقات أيضًا: تُستخدم المقاييس التالية لتقييم أداء الانحدار: الجذر التربيعي لمتوسطات مربعات الأخطاء Root Mean Square Error (ويختصر إلى RMSE) متوسط الأخطاء بالقيمة المطلقة Mean Absolute Error (ويختصر إلى MAE) الجذر التربيعي لمتوسطات مربعات الأخطاء RMSE تُستخدم عملية التربيع أولًا للتخلص من الإشارة السالبة للأخطاء: Errors2 Errors Predictions Failutres Age 121 11 26 15 10 4 2 32 30 20 16 4 44 40 40 25 -5 50 55 50 169 -13 62 75 70 256 -16 74 90 90 ومن ثم نحسب متوسط مربعات الأخطاء، مما يُعطي 89.5. وأخيًرا نجذر المتوسط السابق فيكون الناتج 9.9 قيمة المقياس RMSE أي الجذر التربيعي لمتوسطات مربعات الأخطاء Root Mean Square Error. بالطبع، كلما كان هذا العدد صغيرًا فهذا يعني أن الملائمة أفضل (الحالة المثالية هي الصفر). متوسط الأخطاء بالقيمة المطلقة MAE \Errors\ Errors Predictions Failutres Age 11 11 26 15 10 2 2 32 30 20 4 4 44 40 40 5 -5 50 55 50 13 -13 62 75 70 16 -16 74 90 90 ومن ثم نحسب المتوسط الحسابي لها، مما يُعطي: 8.5 في مثالنا وهو مقياس MAE أي متوسط الأخطاء بالقيمة المطلقة Mean Absolute Error. يُمكن حساب هذه المقاييس في بايثون باستخدام الدوال الموافقة من المكتبة sklearn.metrics، كما تُبين الشيفرة البرمجية التالية والتي نستخدم فيها بيانات مثالنا السابق: from sklearn.metrics import mean_absolute_error from sklearn.metrics import mean_squared_error from math import sqrt y_true = [15, 30, 40, 55, 75, 90] y_pred = [26, 32, 44, 50, 62, 74] print ('MAE :{:.2f}'.format(mean_absolute_error(y_true, y_pred))) print ('RMSE :{:.2f}'.format(sqrt(mean_squared_error (y_true, y_pred)))) يكون الناتج: RMSE :9.92 MAE :8.50 تقييم نماذج التعلم باستخدام طريقة التقسيم العشوائي Hold-out method لبناء نموذج مُتعلم، يجب توفير مجموعة من البيانات dataset لتنفيذ خوارزمية التعلم عليها أولًا، ومن ثم تقييم نموذج التعلم الناتج. يجب لتقييم نموذج التعلم، بشكل حيادي، أن نمرر له مجموعة من البيانات التي لم يرها خلال تدريبه وذلك تفاديًا لحصولنا على مقاييس تقييم ممتازة مزيفة نتيجة وقوع نموذج التعلم في مطب مشكلة فرط التخصيص overfitting، أي أن النموذج تعلم بشكل جيد على الأمثلة المُمره له فقط، وهو غير قادر على تعميم التعلم ليتعامل مع أمثلة جديدة بشكل جيد. تُعدّ طريقة التقسيم العشوائي من أبسط الطرق المستخدمة لتقييم نماذج التعلم والتي تُقسّم البيانات المتاحة إلى قسمين بشكل عشوائي: ندعو القسم الأول ببيانات التدريب training data (عادًة حوالي 80% من البيانات)، والقسم الآخر المتبقي (حوالي 20%) ببينات الاختبار testing data. نعمد إلى تدريب وبناء نموذج التعلم باستخدام بيانات التدريب فقط، ومن ثم تقييم النموذج الناتج باستخدام بيانات الاختبار. توفر المكتبة sklearn في بايثون كل ما يلزم للقيام بذلك كما تٌبين الشيفرة البرمجية التالية والتي نبني فيها نموذج تصنيف باستخدام مُصنّف بايز Bayes وذلك على مجموعة بيانات تصنيف أزهار السوسن iris المتاحة من المكتبة نفسها. # مجموعة بيانات # أزهار السوسن from sklearn.datasets import load_iris # مكتبة تقسيم البيانات إلى تدريب واختبار from sklearn.model_selection import train_test_split # مكتبة مُصنف بايز from sklearn.naive_bayes import GaussianNB # مكتبات مقاييس التقييم from sklearn.metrics import accuracy_score from sklearn.metrics import precision_score from sklearn.metrics import recall_score from sklearn.metrics import f1_score # تحميل البيانات X, y = load_iris(return_X_y=True) # تقسيم البيانات إلى تدريب و اختبار X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) # بناء مصنف بايز gnb = GaussianNB() # الملائمة على بيانات التدريب # والتنبؤ على بيانات الاختبار y_pred = gnb.fit(X_train, y_train).predict(X_test) # حساب مقاييس التقييم # بمقارنة بيانات الاختبار # مع تنبؤ المصنف print ('Accuracy Score :{:.2f}'.format(accuracy_score(y_test, y_pred)*100)) print ('Precision Score :{:.2f}'.format(precision_score(y_test, y_pred, average='macro')*100)) print ('Recall Score ::{:.2f}'.format(recall_score(y_test, y_pred, average='macro')*100)) print ('F1 Score ::{:.2f}'.format(f1_score(y_test, y_pred, average='macro')*100)) لاحظ أن الدالة train_test_split والتي نُمرر لها كل من: X: مصفوفة ثنائية يكون كل عنصر فيها مصفوفة من 4 عناصر (طول وعرض كل من السبال والبتلات لزهرة السوسن). y: مصفوفة أحادية (تصنيف الزهرة الموافق) test_size: النسبة المئوية لبيانات الاختبار من البيانات الكليه (20% افتراضيًا) تُعيد: X_train: بيانات التدريب المختارة عشوائيًا من X. X_test: بيانات الاختبار المختارة عشوائيًا من X. y_train: صفوف بيانات التدريب. y_test: صفوف بيانات الاختبار. يُمكن تنفيذ الشيفرة لمعاينة قيم مقاييس الأداء: Accuracy Score :93.33 Precision Score :92.59 Recall Score :93.94 F1 Score :92.50 يجب الانتباه إلى أن هذه القيم هي قيم استرشادية، بمعنى أنها ستختلف عند كل تنفيذ للشيفرة البرمجية إذ أن حسابها يعتمد في كل مرة على مجموعة مختلفة من بيانات الاختبار (إذ أن هذه البيانات تُختار كل مرة بشكل عشوائي) مثلًا يُعطي تنفيذ ثاني لنفس الشيفرة السابقة النتائج التالية: Accuracy Score :90.00 Precision Score :92.31 Recall Score :92.86 F1 Score :91.65 تقييم نماذج التعلم باستخدام طريقة التقييم المتقاطع Cross Validation method تهدف هذه الطريقة بشكل أساسي إلى استخدام كل البيانات للتدريب (بخلاف الطريقة السابقة والتي تستخدم قسمًا منها فقط)، كما أن قيم مقاييس التقييم ستكون نفسها من أجل كل تنفيذ للشيفرة (بخلاف الطريقة السابقة كما عرضنا أعلاه). عوضًا عن تقسيم البيانات إلى بيانات للتدريب وبيانات للاختبار (التقييم) مما يُخفّض من البيانات التي يُمكن لنا استخدامها للتدريب، نستخدم التقويم المتقاطع مع عدد محدّد من الحاويات K-Fold. تُقسم بيانات التدريب إلى عدد K من الحاويات ومن ثم نقوم بتكرار ما يلي K مرة: في كل مرة i نقوم بتدريب النموذج مع بيانات K-1 حاوية (كل الحاويات ما عدا الحاوية i) ومن ثم تقييمه مع بيانات الحاوية i. في النهاية، يكون مقياس الأداء النهائي هو متوسط مقياس التقييم لكل التكرارات (i:1..K). توفر المكتبة sklearn في بايثون الدالة cross_val_score لتنفيذ التقييم المتقاطع مع تحديد عدد الحاويات المطلوب، كما تُبين الشيفرة البرمجية التالية والتي نحسب فيها مقياس الدقة مثلًا: # مجموعة بيانات # أزهار السوسن from sklearn.datasets import load_iris # مكتبة تقسيم البيانات إلى تدريب واختبار from sklearn.model_selection import train_test_split # مكتبة مُصنف بايز from sklearn.naive_bayes import GaussianNB # مكتبة التقييم المتقاطع from sklearn.model_selection import cross_val_score # مكتبات مقاييس التقييم from sklearn.metrics import accuracy_score from sklearn.metrics import precision_score from sklearn.metrics import recall_score from sklearn.metrics import f1_score # تحميل البيانات X, y = load_iris(return_X_y=True) # تقسيم البيانات إلى تدريب و اختبار X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) # بناء مصنف بايز gnb = GaussianNB() # حساب مقياس الصحة scores = cross_val_score(gnb, X, y, cv=5, scoring="accuracy") print(scores) # حساب المتوسط meanScore = scores.mean() print(meanScore * 100) يكون ناتج التنفيذ (في كل مرة): [0.93333333 0.96666667 0.93333333 0.93333333 1. ] 95.33333333333334 اختيار نموذج التعلم الأفضل يُمكن استخدام طريقة التقويم المتقاطع السابقة لتقييم مجموعة من نماذج التعلم. نُعرّف في الشيفرة البرمجية التالية الدالة cv_comparison_classification والتي نُمرر لها مجموعة من نماذج التعلم models والبيانات كلها (X,y) وعدد الحاويات cv، وتُعيد هذه الدالة إطار بيانات يُظهر مقياس الدقة لكل نموذج. تدور حلقة for في الدالة على النماذج المُمرره، وتستدعي من أجل كل نموذج دالة التقويم المتقاطع من المكتبة sklearn.model والتي تُعيد قائمة بقيم مقياس الصحة (كل عنصر في القائمة هو قيمة مقياس الصحة من أجل حاوية اختبار ما). نحسب متوسط mean القائمة السابقة، ونضيف عمودًا جديدًا إلى إطار البيانات يكون اسمه اسم النموذج والقيمة في الخلية الموافقة للسطر الوحيد في إطار البيانات (والمفهرس بـ Accuracy) قيمة مقياس الصحة. # مكتبة أطر البيانات import pandas as pd # مكتبة التقييم المتقاطع from sklearn.model_selection import cross_val_score # دالة لمقارنة مجموعة من النماذج def cv_comparison_classification(models, X, y, cv): # تهيئة إطار بيانات لمقاييس التقييم cv_df = pd.DataFrame() # الدوران على النماذج # تطبيق التقييم المتقاطع for model in models: # حساب مقياس الصحة لكل حاوية acc = cross_val_score(model, X, y,scoring='accuracy', cv=cv) # حساب متوسط الصحة للنموذج acc_avg = round(acc.mean(), 4) # كتابة النتيجة في إطار البيانات cv_df[str(model)] = [ acc_avg] cv_df.index = ['Accuracy'] return cv_df نستدعي في الشيفرة البرمجية التالية الدالة السابقة للمقارنة بين ثلاثة نماذج للتصنيف: مصنف بايز GaussianNB ومصنف أشجار القرار DecisionTreeClassifier ومصنف أقرب الجيران KNeighborsClassifier. نستخدم بيانات تصنيف أزهار السوسن المتاحة من sklearn.datasets لتنفيذ نماذج التعلم عليها. # مجموعة بيانات # أزهار السوسن from sklearn.datasets import load_iris # مصنف بايز from sklearn.naive_bayes import GaussianNB # مصنف شجرة القرار from sklearn.tree import DecisionTreeClassifier # مصنف أقرب الجيران from sklearn.neighbors import KNeighborsClassifier # تحميل البيانات X, y = load_iris (return_X_y=True) # إنشاء متغيرات النماذج mlr_g = GaussianNB() mlr_d = DecisionTreeClassifier() mlr_k = KNeighborsClassifier() # وضع النماذج في قائمة models = [mlr_g, mlr_d, mlr_k] # استدعاء دالة المقارنة comp_df = cv_comparison_classification(models, X, y, 4) # إظهار إطار البيانات للمقارنه print(comp_df) يُظهر تنفيذ الشيفرة السابقة إطار البيانات التالي والذي يسمح لنا بمعاينة مقياس الصحة لكل نموذج مما يسمح لنا باختيار الأنسب منها: الخلاصة عرضنا في هذه المقالة مقاييس تقييم نماذج التعلم المختلفة وكيفية اختيار النموذج الأفضل منها لمسألة معينة. يُمكن تجربة جميع أمثلة المقالة من موقع Google Colab من الرابط أو من الملف المرفق. الملف المرفق eval.zip. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن اقرأ أيضًا المفاهيم الأساسية لتعلم الآلة تعلم الآلة: التحديات الرئيسية وكيفية التوسع في المجال النسخة الكاملة لكتاب مدخل إلى الذكاء الاصطناعي وتعلم الآلة
-
تُعدّ مسألة استكشاف قواعد الترابط في مبيعات المتاجر من المسائل المهمة جدًا لأصحاب المتاجر الإلكترونية، إذ يسمح إيجاد هذه القواعد بإظهار توصيات recommandations الشراء المناسبة للزبائن مما يساهم في زيادة مبيعات المتجر مثلًا لو عرفنا أن معظم الزبائن تشتري السلعة B مع السلعة A دومًا، فسيكون من المناسب إظهار توصية بشراء السلعة B لكل زبون يطلب شراء السلعة A مما يُحقق، في نهاية المطاف، رضى الزبون وزيادة أرباح المتجر. نعرض في هذه المقالة استخدام تقنيات تعلم الآلة لإيجاد قواعد الترابط انطلاقًا من حركات الشراء السابقة للمتجر. بيانات التدريب نستخدم بيانات عمليات الشراء لأحد متاجر مبيعات التجزئة والمتاحة على الرابط أو يمكنك تنزيلها من الملف data.zip في المقال. تأتي هذه البيانات في الملف Groceries.csv المرفق والذي يحوي حوالي 10000 صف. يحوي كل صف بيانات عربة تسوق واحدة أي مجموعة من السلع التي اشتراها أحد الزبائن معًا كما يُبين الشكل التالي: أساسيات في التنقيب عن قواعد الترابط نعرض فيما يلي بعض التعاريف الأساسية في مسألة التنقيب عن قواعد الترابط. التنقيب عن قواعد الترابط تُعرّف مسألة التنقيب عن قواعد الترابط كما يلي: بفرض أن لدينا مجموعة من الإجراءات transactions، يتألف كل إجراء من مجموعة من العناصر items. يكون المطلوب إيجاد جميع الترابطات correlations بين ظهور مجموعة جزئية من العناصر مع مجموعة جزئية أخرى. يُبين الشكل التالي مثالًا توضيحيًا: نستخدم فيما يلي المثال التالي التعليمي والذي يحوي 5 إجراءات: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الإجراء Transaction خبز، حليب Bread,Milk خبز، فوط، عصير، بيض Bread, Diaper, Juice, Eggs حليب، فوط، عصير، كولا Milk, Diaper, Juice, Coke خبز، حليب، فوط، عصير Bread, Milk, Diaper, Juice خبز، حليب، فوط، كولا Bread, Milk, Diaper, Coke نُعطي أولًا أهم التعاريف الأساسية: مجموعة عناصر itemset وهي مجموعة من العناصر مثلًا: { Milk , Bread , Diaper} (فوط أطفال، خبز، حليب) كما ندون k-itemset للدلالة على مجموعة عناصر تحوي k عنصر. عدد الدعم support count لمجموعة من العناصر وهو عدد مرات تواتر (ظهور) مجموعة من العناصر في الإجراءات مثلًا يكون عدد الدعم في مثالنا التعليمي لمجموعة العناصر السابقة: sc({Milk, Bread, Diaper}) = 2 الدعم support لمجموعة من العناصر وهو النسبة المئوية لظهور مجموعة من العناصر في الإجراءات، مثلًا يكون عدد الدعم في مثالنا التعليمي لمجموعة العناصر سابقة الذكر: s({Milk, Bread, Diaper}) = (2/5)*100 = 40% الحد الأدنى للدعم minimum support وهو حد أدنى تجريبي للدعم (يُمكن أن يكون رقم أو نسبة مئوية) نُحدّده لخوارزميات التنقيب عن القواعد. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مجموعة عناصر متواترة frequent itemset نقول عن مجموعة عناصر أنها متواترة إذا كان دعم المجموعة أكبر أو يساوي الحد الأدنى للدعم. قاعدة ترابط association rule وهي اقتضاء من الشكل: {X} => {Y} وحيث X و Y هي مجموعات من العناصر (لا تحوي، بالطبع، عناصر مشتركة) مثلاً: {Milk, Diaper} => {Bread} الدعم لقاعدة ترابط association rule support يكون الدعم لقاعدة ترابط X=>Y هو الدعم لاجتماع العناصر X و Y معًا. أي نسبة الإجراءات التي تحوي X و Y معًا من عدد الإجراءات الكلي: الثقة في قاعدة ترابط association rule confidence وهو الاحتمال الشرطي لظهور مجموعة العناصر Y في إجراء يحوي X، أي عمليًا احتمال (الثقة) أن تظهر مجموعة العناصر Y في عربة تسوق تحوي العناصر X. مثلًا يكون الدعم لمجموعة العناصر {Milk, Diaper, Bread} في المثال السابق مساويًا 40% لأن هذه العناصر ظهرت مع بعضها البعض مرتين في الإجراءات الخمسة الكلية. يُمكن من هذه العناصر الثلاثة {Milk, Diaper, Bread} توليد مجموعة من القواعد المختلفة (يكفي أن نوزع هذه العناصر على الطرف اليساري واليمني بكل الطرق الممكنة لنحصل على جميع القواعد). يُمكن أن يكون لكل قاعدة معامل ثقة مختلف كما تُبين الأمثلة التالية (المحسوبة من مثالنا التعليمي): {Milk, Diaper} => {Bread} (s=0.4, c=0.67) {Milk, Bread} => {Diaper} (s=0.4, c= 0.67) {Diaper, Bread} => {Milk} (s=0.4, c=0.67) {Bread} => {Milk, Diaper} (s=0.4, c=0.50) {Diaper} => {Milk, Bread} (s=0.4, c=0.5) {Milk} => {Diaper, Bread} (s=0.4, c=0.5) نعرض في هذه المقالة كيفية استخراج قواعد الترابط التي تحقق دعم وثقة معينين. إعداد المشروع يحتاج تنفذ شيفرات هذه المقالة بيئةً برمجيةً للغة بايثون الإصدار 3.8. ويجب أن تتضمن هذه البيئة البرمجية مدير الحِزم pip لتثبيت الحِزم، ومُنشئ البيئات الافتراضية venv لإنشاء بيئاتٍ افتراضيةٍ. نستخدم محرر الشيفرات البرمجية Jupyter Notebooks، وهو مفيد جدًا لتجربة وتشغيل الأمثلة الخاصة بتَعَلّم الآلة بطريقةٍ تفاعليةٍ، حيث نستطيع من خلاله تشغيل كتلًا صغيرةً من الشيفرات البرمجية ورؤية النتائج بسرعة، مما يُسهّل علينا اختبار الشيفرات البرمجية وتصحيحها. نحتاج أولًا لتثبيت بعض التبعيات، وذلك لإنشاء مساحة عملٍ للاحتفاظ بملفاتنا قبل أن نتمكن من تطوير برنامجنا. نُنشئ مجلدًا جديدًا خاصًا بمشروعنا وندخل إليه هكذا: mkdir asoc cd asoc نُنفذّ الأمر التالي لإنشاء البيئة الافتراضية: python -m venv asoc ومن ثم الأمر التالي في Linux لتنشيط البيئة الافتراضية: source asoc/bin/activate أما في Windows، فيكون أمر التنشيط: "asoc/Scripts/activate.bat" نستخدم إصداراتٍ مُحددةٍ من المكتبات اللازمة، من خلال إنشاء ملف requirements.txt في مجلد المشروع، وسيُحدِّد هذا الملف المتطلبات والإصدارات التي سنحتاج إليها. نفتح الملف requirements.txt في محرر النصوص، ونُضيف الأسطر التالية، وذلك لتحديد المكتبات التي نريدها وإصداراتها: asttokens==2.0.5 backcall==0.2.0 colorama==0.4.4 cycler==0.11.0 debugpy==1.6.0 decorator==5.1.1 entrypoints==0.4 executing==0.8.3 fonttools==4.33.3 ipykernel==6.13.0 ipython==8.4.0 jedi==0.18.1 joblib==1.1.0 jupyter-client==7.3.1 jupyter-core==4.10.0 kiwisolver==1.4.2 matplotlib==3.5.2 matplotlib-inline==0.1.3 mlxtend==0.20.0 nest-asyncio==1.5.5 numpy==1.22.4 packaging==21.3 pandas==1.4.2 parso==0.8.3 pickleshare==0.7.5 Pillow==9.1.1 prompt-toolkit==3.0.29 psutil==5.9.1 pure-eval==0.2.2 Pygments==2.12.0 pyparsing==3.0.9 python-dateutil==2.8.2 pytz==2022.1 pywin32==304 pyzmq==23.0.0 scikit-learn==1.1.1 scipy==1.8.1 seaborn==0.11.2 six==1.16.0 stack-data==0.2.0 threadpoolctl==3.1.0 tornado==6.1 traitlets==5.2.2.post1 wcwidth==0.2.5 نحفظ التغييرات التي طرأت على الملف ونخرج من محرر النصوص، ثم نُثَبت هذه المكتبات بالأمر التالي: (asoc) $ pip install -r requirements.txt بعد تثبيتنا لهذه التبعيات، نُصبح جاهزين لبدء العمل على مشروعنا. كتابة الشيفرة البرمجية نُشغّل محرر الشيفرات البرمجية Jupyter Notebook بمجرد اكتمال عملية التثبيت هكذا: (asoc) $ jupyter notebook ثم نُنشئ ملفًا جديدًا في داخل المحرر ونُسمّه باسم asc مثلًا. توليد قواعد الترابط نعرض في الشيفرة التالية توليد قواعد الترابط للمثال السابق بهدف التعرف على المكتبات اللازمة وآلية استخدامها. نضع إجراءات المثال السابق أولًا في مصفوفة ثنائية وبحيث يكون كل عنصر منها هو مصفوفة من عناصر إجراء واحد. نحتاج أولًا إلى توليد إطار بيانات dataframe وبحيث تكون رؤوس الأعمدة هي العناصر وقيم الخلايا هي إما True في حال وجود العنصر في صف row الإجراء الموافق أو False في حال عدم وجوده. نستخدم الصنف TransactionEncoder من المكتبة mlxtend.preprocessing للوصول إلى ذلك. # الإجراءات transactions = [['Bread', 'Milk'], ['Bread', 'Diaper', 'Juice', 'Eggs'], ['Milk', 'Diaper', 'Juice', 'Coke' ], ['Bread', 'Milk', 'Diaper', 'Juice'], ['Bread', 'Milk', 'Diaper', 'Coke']] # مكتبة ترميز الإجراءات from mlxtend.preprocessing import TransactionEncoder # إنشاء غرض من الصف te = TransactionEncoder() # ملائمة المرمز مع البيانات te_model = te.fit(transactions) # تحويل الإجراءات rows=te_model.transform(transactions) # استيراد مكتبة إطار البيانات import pandas as pd # بناء إطار بيانات الإجراءات df = pd.DataFrame(rows, columns=te_model.columns_) print(df) وبالنتيجة يكون لدينا إطار بيانات الإجراءات التالي: لاحظ مثلًا أن الصف الأول من إطار البيانات يوافق الإجراء الأول: {Bread, Milk}. نستدعي في الشيفرة التالية الدالة apriori من المكتبة mlxtend.frequent_patterns والتي تحسب العناصر المتواترة في إطار البيانات السابق (df) وفق حد أدنى معين للدعم min_support (يساوي 40% في مثالنا). يكون ناتج تطبيق هذه الدالة إطار بيانات frequent_itemsets ذي عمودين: مجموعة العناصر المتواترة itemsets والدعم support. نُضيف عمود محسوب جديد لإطار البيانات الناتج يحسب طول كل مجموعة عناصر length. # مكتبة خوارزمية إيجاد العناصر المتواترة from mlxtend.frequent_patterns import apriori # توليد المجموعات المتواترة مع تحديد الحد الأدنى للدعم frequent_itemsets = apriori(df, min_support=0.4, use_colnames=True) # حساب أطوال مجموعات العناصر frequent_itemsets['length'] = frequent_itemsets['itemsets'].apply(lambda x: len(x)) print(frequent_itemsets) تُظهر الطباعة دعم وطول كل مجموعة من مجموعات العناصر المتواترة: يُمكن الآن توليد قواعد الترابط باستخدام إطار بيانات العناصر المتواترة frequent_itemsets السابق، كما تُبين الشيفرة التالية. نستخدم الدالة association_rules من المكتبة mlxtend.frequent_patterns مع تحديد الحد الأدنى للثقة min_threshold (لنأخذ القيمة 60% في مثالنا). # مكتبة خوارزمية إيجاد قواعد الترابط from mlxtend.frequent_patterns import association_rules # توليد القواعد مع تحديد الحد الأدنى للثقة rules = association_rules(frequent_itemsets,metric="confidence",min_threshold=0.6) # الترتيب التنازلي وفق معامل الثقة rules = rules.sort_values(['confidence'], ascending =[False]) print(rules) يُبين الشكل التالي قواعد الترابط الناتجة: يُمكن استخدام رسم الإحداثيات المتوازية parallel_coordinates من المكتبة pandas.plotting لرسم مشاهدة توضيحية للقواعد السابقة. from matplotlib import pyplot as plt from pandas.plotting import parallel_coordinates # دالة تحويل القواعد إلى إحداثيات def rules_to_coordinates(rules): rules['antecedent'] = rules['antecedents'].apply(lambda antecedent: list(antecedent)[0]) rules['consequent'] = rules['consequents'].apply(lambda consequent: list(consequent)[0]) rules['rule'] = rules.index return rules[['antecedent','consequent','rule']] # توليد الإحداثيات المتوازية coords = rules_to_coordinates(rules) # توليد رسم الإحداثيات المتوازية plt.figure(figsize=(4,8)) parallel_coordinates(coords, 'rule') plt.grid(True) plt.show() يكون الرسم البياني الناتج: يُبين الرسم ارتباطات العناصر، وذلك برسم خط بين العنصر من الجهة اليسرى وبين نهاية الخط الأفقي للعنصر الآخر المرتبط معه من الجهة اليمنى، مثلًا يرتبط الحليب Milk مع كل من الخبز Bread و الفوط Diaper. تحميل بيانات المتجر نبدأ أولًا بتحميل بيانات المتجر من الملف Groceries.csv ضمن إطار من البيانات DataFrame من مكتبة Pandas ومن ثم عرض بعضها: # تحميل بيانات المتجر df = pd.read_csv('Groceries.csv',header=None) df.head() يظهر لنا أوائل صفوف الملف: نلاحظ وجود قيم كثيرة فارغة NaN وذلك لأن عدد العناصر في كل صف غير متساوي. نحذف في الشفرة التالية القيم الفارغة، ثم نُنشئ مصفوفة الإجراءات والتي هي مصفوفة يكون كل عنصر منها مصفوفة من عناصر صف واحد من إطار البيانات: # حذف القيم الفارغة # وإنشاء مصفوفة transactions = df.T.apply(lambda x: x.dropna().tolist()).tolist() print(transactions[1:10])) يُبين الشكل التالي مثلًا العناصر العشرة الأولى من مصفوفة الإجراءات الناتجة: نستخدم في الشيفرة التالية مُرمز الإجراءات للحصول على إطار بيانات الإجراءات: # إنشاء غرض من الصف te = TransactionEncoder() # ملائمة المرمز مع البيانات te_model = te.fit(transactions) # تحويل الإجراءات rows=te_model.transform(transactions) # بناء إطار بيانات الإجراءات df = pd.DataFrame(rows, columns=te_model.columns_) print(df.shape) مما يُعطي: (9835, 169) لاحظ أن عدد أعمدة إطار البيانات الناتج هو 169 عمودًا مما يعني وجود 169 عنصرًا مختلفًا فقط في الإجراءات البالغ عددها 9835 إجراء. نستدعي في الشيفرة التالية الدالة apriori والتي تحسب العناصر المتواترة في إطار البيانات df وفق حد أدنى معين للدعم min_support يساوي 0.5% (هو رقم تجريبي حصلنا عليه بتكرار توليد العناصر المتواترة وقواعد الترابط حتى الوصول لقواعد ترابط عددها محدود نسبيًا). يكون ناتج تطبيق هذه الدالة إطار بيانات frequent_itemsets ذي عمودين: مجموعة العناصر المتواترة itemsets والدعم support. نُضيف عمود محسوب جديد لإطار البيانات الناتج يحسب طول length كل مجموعة عناصر. # توليد المجموعات المتواترة مع تحديد الحد الأدنى للدعم frequent_itemsets = apriori(df, min_support=0.005, use_colnames=True) # حساب أطوال مجموعات العناصر frequent_itemsets['length'] = frequent_itemsets['itemsets'].apply(lambda x: len(x)) print(frequent_itemsets) تُبين النتائج أن لدينا 1001 مجموعة من العناصر المتواترة المُحققة للحد الأدنى للدعم ويتراوح طولها بين 1 و 4: يُمكن الآن توليد قواعد الترابط باستخدام إطار بيانات العناصر المتواترة السابق كما تُبين الشيفرة التالية. نستخدم الدالة association_rules مع تحديد الحد الأدنى للثقة 55% (رقم تجريبي حصلنا عليه بعد عدة محاولات لتوليد قواعد الترابط حتى وصلنا لمجموعة معقولة من القواعد). # توليد القواعد مع تحديد الحد الأدنى للثقة rules = association_rules(frequent_itemsets,metric="confidence",min_threshold=0.55) # الترتيب التنازلي وفق معامل الثقة rules = rules.sort_values(['confidence'], ascending =[False]) print(rules) يُبين الشكل التالي قواعد الترابط الناتجة (حوالي 50 قاعدة): يُمكن استخدام رسم الإحداثيات المتوازية لرسم مشاهدة توضيحية للقواعد السابقة: from pandas.plotting import parallel_coordinates # دالة تحويل القواعد إلى إحداثيات def rules_to_coordinates(rules): rules['antecedent'] = rules['antecedents'].apply(lambda antecedent: list(antecedent)[0]) rules['consequent'] = rules['consequents'].apply(lambda consequent: list(consequent)[0]) rules['rule'] = rules.index return rules[['antecedent','consequent','rule']] # توليد الإحداثيات المتوازية coords = rules_to_coordinates(rules) # توليد رسم الإحداثيات المتوازية plt.figure(figsize=(4,8)) parallel_coordinates(coords, 'rule') plt.legend([]) plt.grid(True) plt.show() يكون الرسم البياني الناتج: الخلاصة عرضنا في هذه المقالة خطوات بناء إيجاد قواعد الترابط بين مبيعات العناصر في المتاجر. يُمكن تجربة المثال كاملًا من موقع Google Colab من الرابط أو تنزيله من الملف المرفق. الملف المرفق: data (1).zip اقرأ أيضًا المفاهيم الأساسية لتعلم الآلة تعلم الآلة: التحديات الرئيسية وكيفية التوسع في المجال خطوات تنفيذ مشروع عن تعلم الآلة في بايثون: الجزء الأول النسخة الكاملة لكتاب مدخل إلى الذكاء الاصطناعي وتعلم الآلة
-
تُعدّ مسألة تصنيف الشخصيات بالاعتماد على تغريداتهم على وسائل التواصل الاجتماعي من المسائل المهمة مثلًا يُمكن أن يكون من المفيد تحديد الأشخاص الذين يكتبون تحليلات مهمة في مجالات الأعمال أو الاقتصاد أو الرياضة وغيرها مما يتيح للآخرين معرفة تقييمات أو آراء الأشخاص المغردين واتخاذ الإجراء المناسب. نعرض في هذه المقالة استخدام تقنيات التعلم العميق في تصنيف الشخصيات المغردة بنصوص مكتوبة باللغة العربية وباللهجة السعودية بمعنى أن اللغة المستخدمة ليست بالضرورة اللغة العربية الفصحى بل يُمكن أن تدخل فيها ألفاظ عامية يستخدمها المغردون عادةً. لتصنيف شخص ما، سنلجأ أولًا إلى تصنيف تغريداته (أي إسناد كل تغريده إلى صف معين)، ومن ثم تصنيفه بناًء على نتائج تصنيف تغريداته (الصفوف ذات التواتر الكبر). بيانات التدريب تحوي مجموعة البيانات المتوفرة حوالي 26500 تغريدة لمجموعة متنوعة من المغردين المشهورين في المملكة العربية السعودية. جُمّعت هذه التغريدات عن طريق مجموعة من الطلاب الجامعيين وذلك من موقع تويتر Twitter. بالطبع، لا يوجد تصنيف متوفر لهذه التغريدات على تويتر. تجدها موجودة هي وبقية ملفات هذا الفصل في الملف المضغوط المرفق. تصنيف بيانات التدريب يتطلب استخدام خوارزميات تعلم الآلة (خوارزميات تصنيف التغريدات في حالتنا) توفر بيانات للتدريب أي مجموعة من التغريدات مُصنفّة مُسبقًا إلى مجموعة من الصفوف، ويُمكن، كما في حالتنا، اللجوء إلى الطرق اليدوية أي الطلب من مجموعة من الأشخاص قراءة النصوص وتصنيفها وهو حل يصلح في حال كان عدد النصوص صغيرًا نسبيًا، ويتميز هذا الحل بالدقة العالية لأن الأشخاص تُدرك، بشكل عام، معاني النصوص من خلال خبرتها اللغوية المُكتسبة وتُصنّف النصوص بشكل صحيح غالبًا. طلبنا من الطلاب المشاركين في مشروعنا تصنيف كل تغريدة إلى واحدة من المواضيع (الصفوف) التالية: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الصف بالعربي English الرياضة Sports الأعمال Business التكنولوجيا Technology المجتمع Social السياسة Politics الأخبار News الاقتصاد Economy نُعطي فيما يلي أمثلة عن هذه التغريدات (بعد تصنيفها): "الحمد لله مباراة الدوري وهدف غالي يشابه هدف القناص مباراة الفتح الرائد الهلال" (الرياضة). "قريبا جدا… تتابع السوق السعودي وشركاته والأمريكي وشركاته والعملات والكربتو النفط والذهب بمنصة واحدة مباشرة وتقدر ت…" (الأعمال). "فايروس خطير جدا يستهدف مستخدمي نظام الاندرويد قادر يسرق بيانات حساسه الصور وتسجيل صوت المستخدم والوصول لمعلوماتهم وسرقة…" (التكنولوجيا) "أالسلام عليكم ورحمة الله وبركاتة اللهم فرج يفرج همه ويبارك ماله ويفتح أبواب الخيروال…" (المجتمع) "مبادرون لأجل فلسطين.. تكريم كويتي لرافضي التطبيع في الفعاليات الرياضية والأدبية" (السياسة) "الخط العربي ومخاوف التقنية في الزمن الرقمي.. تجربة عالمية أم خروج عن تقاليد الفن العريق؟" (الأخبار) "معلومة فنية (٢)للشراء المضاربي ١- اقفال السوق ٥ دقايق اذا كانت شمعة ايجابية للحصول ربح مضاربي يوم ٢-عند…" (الاقتصاد). نعرض في هذه المقالة كيفية بناء مُصنّف حاسوبي آلي يُصنّف أي تغريدة عربية إلى أحد الصفوف السبعة السابقة ومن ثم تصنيف الشخص المغرد لواحد أو أكثر من هذه الصفوف (الأكثر تواترًا). المعالجة الأولية للنصوص تتميز التغريدات، بشكل عام، باحتوائها على مجموعة من الأمور غير المهمة في مسألة التصنيف مثل الروابط Links والوسوم Hashtags والرموز التعبيرية Emojis وغيرها. يُبين الشكل التالي مثالًا عن التغريدات المُجمّعة: تهدف المعالجة الأولية إلى الحصول على الكلمات المهمة فقط من النصوص وذلك عن طريق تنفيذ بعض العمليات اللغوية عليها. لتكن لدينا مثلًا الجملة التالية: "أنا أحب الذهاب إلى الحديقة ?، كل يوم 9 صباحاً، مع رفاقي هؤلاء! @toto "، سنقوم بتنفيذ العمليات التالية: حذف الروابط والوسوم والرموز التعبيرية: يكون ناتج الجملة السابقة: "أنا أحب الذهاب إلى الحديقة، كل يوم 9 صباحاً، مع رفاقي هؤلاء!" حذف إشارات الترقيم المختلفة كالفواصل وإشارات الاستفهام وغيرها: يكون ناتج الجملة السابقة: "أنا أحب الذهاب إلى الحديقة كل يوم 9 صباحاً مع رفاقي هؤلاء" حذف الأرقام الواردة في النص: يكون ناتج الجملة السابقة: "أنا أحب الذهاب إلى الحديقة كل يوم صباحاً مع رفاقي هؤلاء" حذف كلمات التوقف stop words وهي الكلمات التي تتكرر كثيرًا في النصوص ولا تؤثر في معانيها كأحرف الجر (من، إلى، …) والضمائر (أنا، هو، …) وغيرها فيكون ناتج الجملة السابقة: " أحب الذهاب الحديقة يوم صباحاً رفاقي" تجذيع الكلمات stemming أي إرجاع الكلمات المتشابهة إلى كلمة واحدة (جذع) مما يُساهم في إنقاص عدد الكلمات الكلية المختلفة في النصوص، ومطابقة الكلمات المتشابهة مع بعضها البعض. مثلًا: يكون للكلمات الأربع: (رائع، رايع، رائعون، رائعين) نفس الجذع المشترك: (رايع) فيكون ناتج الجملة السابقة: " احب ذهاب حديق يوم صباح رفاق" إعداد المشروع يحتاج تنفذ شيفرات هذه المقالة بيئةً برمجيةً للغة بايثون الإصدار 3.8. ويجب أن تتضمن هذه البيئة البرمجية مدير الحِزم pip لتثبيت الحِزم، ومُنشئ البيئات الافتراضية venv لإنشاء بيئاتٍ افتراضيةٍ. نستخدم محرر الشيفرات البرمجية Jupyter Notebooks، وهو مفيد جدًا لتجربة وتشغيل الأمثلة الخاصة بتَعَلّم الآلة بطريقةٍ تفاعليةٍ، حيث نستطيع من خلاله تشغيل كتلًا صغيرةً من الشيفرات البرمجية ورؤية النتائج بسرعة، مما يُسهّل علينا اختبار الشيفرات البرمجية وتصحيحها. نحتاج أولًا لتثبيت بعض التبعيات، وذلك لإنشاء مساحة عمل للاحتفاظ بملفاتنا قبل أن نتمكن من تطوير برنامجنا. نُنشئ مجلدًا جديدًا خاصًا بمشروعنا وندخل إليه هكذا: mkdir arc cd arc نُنفذّ الأمر التالي لإنشاء البيئة الافتراضية: python -m venv arc ومن ثم الأمر التالي في Linux لتنشيط البيئة الافتراضية: source arc/bin/activate أما في Windows، فيكون أمر التنشيط: "arc/Scripts/activate.bat" نستخدم إصداراتٍ محددةٍ من المكتبات اللازمة، من خلال إنشاء ملف requirements.txt في مجلد المشروع، وسيُحدِّد هذا الملف المتطلبات والإصدارات التي سنحتاج إليها. نفتح الملف requirements.txt في محرر النصوص، ونُضيف الأسطر التالية، وذلك لتحديد المكتبات التي نريدها وإصداراتها: absl-py==1.0.0 asttokens==2.0.5 astunparse==1.6.3 backcall==0.2.0 cachetools==5.1.0 certifi==2021.10.8 charset-normalizer==2.0.12 click==8.1.3 colorama==0.4.4 cycler==0.11.0 debugpy==1.6.0 decorator==5.1.1 entrypoints==0.4 executing==0.8.3 flatbuffers==1.12 fonttools==4.33.3 gast==0.4.0 google-auth==2.6.6 google-auth-oauthlib==0.4.6 google-pasta==0.2.0 grpcio==1.46.1 h5py==3.6.0 idna==3.3 imbalanced-learn==0.9.1 imblearn==0.0 importlib-metadata==4.11.3 ipykernel==6.13.0 ipython==8.3.0 jedi==0.18.1 joblib==1.1.0 jupyter-client==7.3.1 jupyter-core==4.10.0 keras==2.6.0 Keras-Applications==1.0.8 Keras-Preprocessing==1.1.2 kiwisolver==1.4.2 libclang==14.0.1 Markdown==3.3.7 matplotlib==3.5.2 matplotlib-inline==0.1.3 nest-asyncio==1.5.5 nltk==3.7 numpy==1.22.3 oauthlib==3.2.0 opt-einsum==3.3.0 packaging==21.3 pandas==1.4.2 parso==0.8.3 pickleshare==0.7.5 Pillow==9.1.1 prompt-toolkit==3.0.29 protobuf==3.20.1 psutil==5.9.0 pure-eval==0.2.2 PyArabic==0.6.14 pyasn1==0.4.8 pyasn1-modules==0.2.8 Pygments==2.12.0 pyparsing==3.0.9 python-dateutil==2.8.2 pytz==2022.1 #pywin32==304 pyzmq==22.3.0 regex==2022.4.24 requests==2.27.1 requests-oauthlib==1.3.1 rsa==4.8 scikit-learn==1.1.0 scipy==1.8.0 seaborn==0.11.2 six==1.16.0 sklearn==0.0 snowballstemmer==2.2.0 stack-data==0.2.0 tensorboard==2.9.0 tensorboard-data-server==0.6.1 tensorboard-plugin-wit==1.8.1 tensorflow==2.9.0 tensorflow-estimator==2.9.0 tensorflow-io-gcs-filesystem==0.26.0 termcolor==1.1.0 threadpoolctl==3.1.0 tornado==6.1 tqdm==4.64.0 traitlets==5.2.1.post0 typing-extensions==4.2.0 urllib3==1.26.9 wcwidth==0.2.5 Werkzeug==2.1.2 wrapt==1.14.1 zipp==3.8.0 نحفظ التغييرات التي طرأت على الملف ونخرج من محرر النصوص، ثم نُثَبت هذه المكتبات بالأمر التالي: (arc) $ pip install -r requirements.txt بعد تثبيتنا لهذه التبعيات، نُصبح جاهزين لبدء العمل على مشروعنا. كتابة الشيفرة البرمجية نُشغّل محرر الشيفرات البرمجية Jupyter Notebook بمجرد اكتمال عملية التثبيت هكذا: (arc) $ jupyter notebook ثم نُنشئ ملفًا جديدًا في داخل المحرر ونُسمّه باسم ac مثلًا. تحميل البيانات نبدأ أولًا بتحميل التغريدات من الملف tweets.csv ضمن إطار من البيانات DataFrame من مكتبة Pandas ومن ثم عرض بعضها: import pandas as pd # قراءة التغريدات وتحميلها ضمن إطار من البيانات tweets = pd.read_csv('tweets.csv',encoding = "utf-8") # إظهار الجزء الأعلى من إطار البيانات tweets.head() يظهر لنا أوائل التغريدات: يُمكن استخدام خاصية الشكل shape لمعرفة عدد الصفوف والأعمدة للبيانات المُحمّلة: print('Data size:', tweets.shape) يكون الناتج: Data size: (26748, 2) المعالجة الأولية للنصوص نستخدم فيما يلي بعض الخدمات التي توفرها المكتبة nltk لمعالجة اللغات الطبيعية كتوفير قائمة كلمات التوقف باللغة العربية (حوالي 700 كلمة) واستخراج الوحدات tokens من النصوص. كما نستخدم مجذع الكلمات العربية من مكتبة snowballstemmer. كما نستخدم التعابير النمطية regular expressions للتعرف على الرموز التعبيرية والوسوم والروابط وحذفها. # مكتبة السلاسل النصية import string # مكتبة التعابير النظامية import re # مكتبة معالجة اللغات الطبيعية import nltk #nltk.download('punkt') #nltk.download('stopwords') # مكتبة كلمات التوقف from nltk.corpus import stopwords # مكتبة استخراج الوحدات from nltk.tokenize import word_tokenize # مكتبة المجذع العربي from snowballstemmer import stemmer ar_stemmer = stemmer("arabic") # دالة حذف المحارف غير اللازمة def remove_chars(text, del_chars): translator = str.maketrans('', '', del_chars) return text.translate(translator) # دالة حذف المحارف المكررة def remove_repeating_char(text): return re.sub(r'(.)\1{2,}', r'\1', text) # دالة تنظيف التغريدات def clean_tweet(tweet): stop_words = stopwords.words('arabic') # محارف الرموز التعبيرية emoj = re.compile("[" u"\U0001F600-\U0001F64F" u"\U0001F300-\U0001F5FF" u"\U0001F680-\U0001F6FF" u"\U0001F1E0-\U0001F1FF" u"\U00002500-\U00002BEF" u"\U00002702-\U000027B0" u"\U00002702-\U000027B0" u"\U000024C2-\U0001F251" u"\U0001f926-\U0001f937" u"\U00010000-\U0010ffff" u"\u2640-\u2642" u"\u2600-\u2B55" u"\u200d" u"\u23cf" u"\u23e9" u"\u231a" u"\ufe0f" u"\u3030" "]+", re.UNICODE) tweet = str(tweet) # حذف @ وما يتبعها tweet = re.sub("@[^\s]+","",tweet) tweet = re.sub("RT","",tweet) # حذف الروابط tweet = re.sub(r"(?:\@|http?\://|https?\://|www)\S+", "", tweet) # حذف الرموز التعبيرية tweet = re.sub(emoj, '', tweet) # حذف كلمات التوقف tweet = ' '.join(word for word in tweet.split() if word not in stop_words) # حذف الإشارات # tweet = tweet.replace("#", "").replace("_", " ") # حذف الأرقام tweet = re.sub(r'[0-9]+', '', tweet) # حذف المحارف غير اللازمة # علامات الترقيم العربية arabic_punctuations = '''`÷×؛<>_()*&^%][ـ،/:"؟.,'{}~¦+|!”…“–ـ''' # علامات الترقيم الإنجليزية english_punctuations = string.punctuation # دمج علامات الترقيم العربية والانكليزية punctuations_list = arabic_punctuations + english_punctuations tweet = remove_chars(tweet, punctuations_list) # حذف المحارف المكررة tweet = remove_repeating_char(tweet) # استبدال الأسطر الجديدة بفراغات tweet = tweet.replace('\n', ' ') # حذف الفراغات الزائدة من اليمين واليسار tweet = tweet.strip(' ') return tweet # دالة تقسيم النص إلى مجموعة من الوحدات def tokenizingText(text): tokens_list = word_tokenize(text) return tokens_list # دالة حذف كلمات التوقف def filteringText(tokens_list): # قائمة كلمات التوقف العربية listStopwords = set(stopwords.words('arabic')) filtered = [] for txt in tokens_list: if txt not in listStopwords: filtered.append(txt) tokens_list = filtered return tokens_list # دالة التجذيع def stemmingText(tokens_list): tokens_list = [ar_stemmer.stemWord(word) for word in tokens_list] return tokens_list # دالة دمج قائمة من الكلمات في جملة def toSentence(words_list): sentence = ' '.join(word for word in words_list) return sentence شرح الدوال السابقة: الدالة clean_tweet تحذف الرموز التعبيرية والروابط والوسوم والأرقام وعلامات الترقيم العربية والإنكليزية من النص وذلك باستخدام التعابير النظامية الموافقة. الدالة remove_repeating_char تحذف المحارف المكررة والتي قد يستخدمها كاتب التغريدة. الدالة tokenizingText تعمل على تجزئة النص إلى قائمة من الوحدات tokens. الدالة filteringText تحذف كلمات التوقف من قائمة الوحدات. الدالة stemmingText تعمل على تجذيع كلمات قائمة الوحدات المتبقية. يُبين المثال التالي نتيجة استدعاء كل دالة من الدوال السابقة: # مثال text= "أنا أحب الذهاب إلى الحديقة ?، كل يوم 9 صباحاً، مع رفاقي هؤلاء! @toto " print(text) text=clean_tweet(text) print(text) tokens_list=tokenizingText(text) print(tokens_list) tokens_list=filteringText(tokens_list) print(tokens_list) tokens_list=stemmingText(tokens_list) print(tokens_list) يكون ناتج التنفيذ: تعرض الشيفرة التالية التصريح عن الدالة process_tweet والتي تقوم أولًا بتنظيف التغريدات وذلك باستدعاء الدالة clean_tweet، ومن ثم تحويل التغريدات إلى وحدات وذلك باستدعاء الدالة tokenizingText، وأخيرًا تجذيع الوحدات عن طريق الدالة stemmingText. ومن ثم تنفيذ دالة المعالجة الأولية على جميع التغريدات: # دالة معالجة التغريدات def process_tweet(tweet): # تنظيف التغريدة tweet=clean_tweet(tweet) # التحويل إلى وحدات tweet=tokenizingText(tweet) # التجذيع tweet=stemmingText(tweet) return tweet # المعالجة الأولية للتغريدات tweets['tweet'] = tweets['tweet'].apply(process_tweet) موازنة الصفوف تتطلب معظم خوارزميات التصنيف توفر بيانات للتدريب وبصفوف متوازنة، بمعنى أن يكون عدد أسطر البيانات من كل صف متساوية تقريبًا تجنبًا لانحياز المُصنف إلى الصف ذي العدد الأكبر من الأسطر في بيانات التدريب. من المفيد إذًا أولًا معاينة توزع أعداد الصفوف. نستخدم في الشيفرة البرمجية التالية مكتبات الرسم اللازمة لرسم أشرطة تُمثّل أعداد الصفوف: # مكتبات الرسم import matplotlib.pyplot as plt import seaborn as sns # حجم الرسم plt.figure(figsize=(12, 6)) # رسم عدد كل صف sns.countplot(data=tweets, y='topic'); plt.title('Topics Distribution', fontsize=18) plt.show() يُبين الشكل الناتج عدم توازن الصفوف على الإطلاق: نستخدم في الشيفرة التالية الصنف RandomOverSampler من المكتبة imblearn.over_sampling والذي يقوم باختيار أسطر عشوائية من الصفوف القليلة العدد ويُكررها في مجموعة البيانات. # استيراد مكتبة الموازنة from imblearn.over_sampling import RandomOverSampler # إنشاء كائن من الصنف oversample = RandomOverSampler() # توليد سطر عشوائي tweets = tweets.sample(frac=1) # توليد الأسطر الجديدة tweets, Y = oversample.fit_resample(tweets, tweets.topic) نعيد رسم أعداد الصفوف بعد الموازنة: # إعادة رسم أعداد الصفوف # بعد الموازنة plt.figure(figsize=(12, 6)) sns.countplot(data=tweets, y='topic'); plt.title('Topics Distribution After OverSampling', fontsize=18) plt.show() يُبين الشكل الناتج توازن الصفوف بشكل كامل: ترميز الصفوف لا تقبل بنى تعلم الآلة النصوص كمدخلات لها، تقوم الشيفرة التالية باستخدام الصنف LabelEncoder من المكتبة sklearn.preprocessing لترميز الصفوف باستخدام الأرقام. نطبع في النهاية أسماء الصفوف والترميز المقابل لها: from sklearn.preprocessing import LabelEncoder # ترميز الصفوف le_topics = LabelEncoder() tweets['topic'] = tweets[['topic']].apply(le_topics.fit_transform) classes = le_topics.classes_ # الصفوف n_classes = len(classes) # عدد الصفوف print("No. of classes:", n_classes) print("Classes:", classes) print("Coding: ", le_topics.transform(classes)) يكون الإظهار: No. of classes: 7 Classes: ['Business' 'Economy' 'News' 'Politics' 'Social' 'Sports' 'Technology'] Coding: [0 1 2 3 4 5 6] تحويل النصوص إلى أشعة رقمية لا تقبل بنى تعلم الآلة النصوص كمدخلات لها، بل تحتاج إلى أشعة رقمية كمدخلات. نستخدم الشيفرة التالية لتحويل الشعاع النصي لكل تغريدة tweet_preprocessed إلى شعاع رقمي: from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences # نركيب جمل التغريدات من المفردات المعالجة sentences = tweets['tweet'].apply(toSentence) print(sentences[6]) # عدد الكلمات الأعظمي ذات التواتر الأكبر # التي ستُستخدم max_words = 5000 # الطول الأعظمي لشعاع الأرقام max_len = 50 # التصريح عن المجزئ # مع تحديد عدد الكلمات التي ستبقى # بالاعتماد على تواترها tokenizer = Tokenizer(num_words=max_words ) # ملائمة المجزئ لنصوص التغريدات tokenizer.fit_on_texts(sentences) # تحويل النص إلى قائمة من الأرقام S = tokenizer.texts_to_sequences(sentences) print(S[0]) # توحيد أطوال الأشعة X = pad_sequences(S, maxlen=max_len) print(X[0]) X.shape نجد من الشيفرة أن المتغير max_words يُحدّد عدد الكلمات الأعظمي التي سيتم الاحتفاظ بها حيث يُحسب تواتر كل كلمة في كل النصوص ومن ثم تُرتب حسب تواترها (المرتبة الأولى للكلمة ذات التواتر الأكبر). ستُهمل الكلمات ذات المرتبة أكبر من max_words، و يُحدّد المتغير max_len طول الشعاع الرقمي النهائي فإذا كان موافقًا لنص أقل من max_len تُضاف أصفار للشعاع حتى يُصبح طوله مساويًا إلى max_len. أما إذا كان طوله أكبر يُقتطع جزءًا منه ليُصبح طوله مساويًا إلى max_len. بينما تقوم الدالة fit_on_texts بملائمة المُجزء tokenizer لنصوص جمل التغريدات sentences.values أي حساب تواتر الكلمات والاحتفاظ بالكلمات ذات التواتر أكبر أو يساوي max_words. نطبع في الشيفرة السابقة، بهدف التوضيح، ناتج كل مرحلة. اخترنا مثلًا شعاع التغريدة 6 بعد المعالجة: تكون نتيجة تحويل الشعاع السابق النصي إلى شعاع من الأرقام: [1839, 1375, 2751, 315, 975, 1420, 1839, 3945, 436, 794, 919, 445, 1290, 312, 258] وبعد عملية توحيد الطول يكون الشعاع الرقمي النهائي الناتج: [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1839 1375 2751 315 975 1420 1839 3945 436 794 919 445 1290 312 258] تجهيز دخل وخرج الشبكة العصبية تعرض الشيفرة التالية حساب شعاع الخرج أولًا وذلك بإسناد العمود topic من إطار البيانات، والذي يحوي الترميز الرقمي للصفوف إلى المتغير y. نستخدم الدالة train_test_split لتقسيم البيانات المتاحة إلى 80% منها لعملية التدريب و20% لعملية الاختبار وحساب مقاييس الأداء: # توليد شعاع الخرج y = tweets['topic'] # مكنبة تقسيم البيانات إلى تدريب واختبار from sklearn.model_selection import train_test_split # تقسيم البيانات إلى تدريب واختبار X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0) print(X_train.shape, y_train.shape) print(X_test.shape, y_test.shape) نطبع في الشيفرة السابقة حجوم أشعة الدخل والخرج للتدريب وللاختبار: (30520, 50) (30520,) (7630, 50) (7630,) نموذج الشبكة العصبية المتعلم تُعدّ المكتبة Keras من أهم مكتبات بايثون التي توفر بناء شبكات عصبية لمسائل التعلم الآلي. تعرض الشيفرة التالية التصريح عن دالة بناء نموذج التعلّم create_model مع إعطاء جميع المعاملات المترفعة قيمًا ابتدائية: # تضمين النموذج التسلسلي from keras.models import Sequential # تضمين الطبقات اللازمة from keras.layers import Embedding, Dense, LSTM # دوال التحسين from tensorflow.keras.optimizers import Adam, RMSprop # التصريح عن دالة إنشاء نموذج التعلم # مع إعطاء قيم أولية للمعاملات المترفعة def create_model(embed_dim = 32, hidden_unit = 16, dropout_rate = 0.2, optimizers = RMSprop, learning_rate = 0.001): # التصريح عن نموذج تسلسلي model = Sequential() # طبقة التضمين model.add(Embedding(input_dim = max_words, output_dim = embed_dim, input_length = MAX_LENGTH)) # LSTM model.add(LSTM(units = hidden_unit ,dropout=dropout_rate)) # الطبقة الأخيرة model.add(Dense(units = len(classes), activation = 'softmax')) # يناء النموذج model.compile(loss = 'sparse_categorical_crossentropy', optimizer = optimizers(learning_rate = learning_rate), metrics = ['accuracy']) # طباعة ملخص النموذج print(model.summary()) return model نستخدم من أجل مسألتنا نموذج شبكة عصبية تسلسلي يتألف من ثلاث طبقات هي: طبقة التضمين Embedding وطبقة LSTM (شبكة ذات ذاكرة طويلة المدى) والطبقة الكثيفة Dense. الطبقة الأولى: طبقة التضمين Embedding نستخدم هذه الطبقة لتوليد ترميز مكثف للكلمات dense word encoding مما يُساهم في تحسين عملية التعلم. نطلب تحويل الشعاع الذي طوله input_length (في حالتنا 50) والذي يحوي قيم ضمن المجال input_dim (من 1 إلى 5000 في مثالنا) إلى شعاع من القيم ضمن المجال output_dim (مثلًا 32 قيمة). الطبقة الثانية: شبكة ذات ذاكرة طويلة المدى Long Short-Term Memory يُحدّد المعامل المترفع units عدد الوحدات المخفية لهذه الطبقة. يُساهم المعامل dropout في معايرة الشبكة خلال التدريب حيث يقوم بإيقاف تشغيل الوحدات المخفية بشكل عشوائي أثناء التدريب، وبهذه الطريقة لا تعتمد الشبكة بنسبة 100٪ على جميع الخلايا العصبية الخاصة بها. وبدلاً من ذلك، تُجبر نفسها على العثور على أنماط أكثر أهمية في البيانات من أجل زيادة المقياس الذي تحاول تحسينه (الدقة مثلًا). الطبقة الثالثة: الكثيفة Dense يُحدّد المعامل units حجم الخرج لهذه الطبقة (7 في حالتنا: عدد الصفوف) ويُبين الشكل التالي ملخص النموذج: معايرة المعاملات الفائقة للوصول لنموذج أمثلي يمكن الوصول لنموذج تعلم أمثلي بمعايرة معاملاته الفائقة وفق معطيات المشروع. لنُبين أولًا الفرق بين المعاملات الفائقة لنموذج والمعاملات الأخرى له: المعاملات الفائقة hyperparameters: هي إعدادات خوارزمية التعلّم قبل التدريب (والتي وضعها مصممو الخوارزمية). المعاملات parameters: هي المعاملات التي يتعلّمها النموذج أثناء التدريب مثل أوزان الشبكة العصبية. تؤثر عملية معايرة المعاملات الفائقة على أداء النموذج لاسيما لجهة التوزان المطلوب بين مشكلة قلة التخصيص underfitting ومشكلة فرط التخصيص overfitting واللتان تؤديان إلى نموذج غير قادر على تعميم أمثلة التدريب وبالتالي لن يتمكن من التصنيف مع معطيات جديدة (يُمكن العودة لمقال تعلم الآلة: التحديات الرئيسية وكيفية التوسع في المجال من أكاديمية حسوب للمزيد من التفصيل حول هاتين المشكلتين). تظهر مشكلة قلة التخصيص عندما لا يكون للنموذج درجات حرية كافية ليتعلّم الربط بين الميزات والهدف، وبالتالي يكون له انحياز كبير Bias–variance tradeoff نحو قيم معينة للهدف. يُمكن تصحيح قلة التخصيص بجعل النموذج أكثر تعقيدًا. أما مشكلة فرط التخصيص فتظهر عندما يقوم النموذج بتخزين بيانات التدريب فيكون له بالتالي تباين كبير والذي يُمكن تصحيحه بالحد من تعقيد النموذج باستخدام التسوية regularization. تكمن المشكلة في معايرة المعاملات الفائقة بأن قيمها المثلى تختلف من مسألة لأخرى! وبالتالي، فإن الطريقة الوحيدة للوصول لهذه القيم المثلى هي تجريب قيم مختلفة مع كل مجموعة بيانات تدريب جديدة. يوفر Scikit-Learn العديد من الطرق لتقويم المعاملات الفائقة وبالتالي سنعتمد في مشروعنا عليها دون أن نُعقّد الأمور أكثر. يُمكن العودة إلى مقال تحليل المشاعر في اللغة العربية باستخدام التعلم العميق فقرة "البحث الشبكي مع التقييم المتقاطع" لشرح طريقة حسابنا لأفضل القيم للمعاملات المترفعة. بناء نموذج التعلم النهائي نستخدم الدالة KerasClassifier من scikit لبناء المُصنف مع الدالة السابقة create_model: # مكتبة التصنيف from keras.wrappers.scikit_learn import KerasClassifier # إنشاء النموذج مع قيم المعاملات المترفعة الأمثلية model = KerasClassifier(build_fn = create_model, # معاملات النموذج dropout_rate = 0.2, embed_dim = 32, hidden_unit = 64, optimizers = Adam, learning_rate = 0.001, # معاملات التدريب epochs=10, batch_size=256, # نسبة بيانات التقييم validation_split = 0.1) # ملائمة النموذج مع بيانات التدريب model_prediction = model.fit(X_train, y_train) يُمكن الآن رسم منحني الدقة accuracy لكل من بيانات التدريب والتقييم (لاحظ أننا في الشيفرة السابقة احتفاظنا بـ 10% من بيانات التدريب للتقييم): # معاينة دقة النموذج # التدريب والتقييم fig, ax = plt.subplots(figsize = (10, 4)) ax.plot(model_prediction.history['accuracy'], label = 'train accuracy') ax.plot(model_prediction.history['val_accuracy'], label = 'val accuracy') ax.set_title('Model Accuracy') ax.set_xlabel('Epoch') ax.set_ylabel('Accuracy') ax.legend(loc = 'upper left') plt.show() يكون للمنحي الشكل التالي: حساب مقاييس الأداء يُمكن الآن حساب مقاييس الأداء المعروفة في مسائل التصنيف (الصحة Accuracy، الدقة Precision، الاستذكار Recall، المقياس F1) للنموذج المتعلم باستخدام الشيفرة التالية: # مقاييس الأداء # مقياس الصحة from sklearn.metrics import accuracy_score # مقياس الدقة from sklearn.metrics import precision_score # مقياس الاستذكار from sklearn.metrics import recall_score # f1 from sklearn.metrics import f1_score # مصفوفة الارتباك from sklearn.metrics import confusion_matrix # تصنيف بيانات الاختبار y_pred = model.predict(X_test) # حساب مقاييس الأداء accuracy = accuracy_score(y_test, y_pred) precision=precision_score(y_test, y_pred , average='weighted') recall= recall_score(y_test, y_pred, zero_division=1, average='weighted') f1= f1_score(y_test, y_pred, zero_division=1, average='weighted') print('Model Accuracy on Test Data:', accuracy*100) print('Model Precision on Test Data:', precision*100) print('Model Recall on Test Data:', recall*100) print('Model F1 on Test Data:', f1*100) confusion_matrix(y_test, y_pred) تكون النتائج: Model Accuracy on Test Data: 90.90 Model Precision on Test Data: 90.88 Model Recall on Test Data: 90.90 Model F1 on Test Data: 90.86 array([[ 964, 22, 24, 57, 16, 12, 19], [ 18, 1029, 26, 20, 15, 9, 8], [ 13, 18, 1033, 19, 5, 8, 3], [ 45, 19, 52, 871, 59, 12, 10], [ 11, 25, 18, 38, 990, 11, 3], [ 3, 10, 13, 3, 15, 986, 3], [ 4, 10, 8, 2, 0, 8, 1063]], dtype=int64) لاحظ ارتفاع قيم جميع المقاييس مما يعني جودة المُصنف. يُمكن رسم مصفوفة الارتباك confusion matrix بشكل أوضح باستخدام المكتبة seaborn: # رسم مصفوفة الارتباك import seaborn as sns sns.set(style = 'whitegrid') fig, ax = plt.subplots(figsize = (8,6)) sns.heatmap(confusion_matrix(y_true = y_test, y_pred = y_pred), fmt = 'g', annot = True) ax.xaxis.set_label_position('top') ax.xaxis.set_ticks_position('top') ax.set_xlabel('Prediction', fontsize = 14) ax.set_ylabel('Actual', fontsize = 14) plt.show() مما يُظهر المخطط التالي: يُمكن حساب بعض مقاييس الأداء الأخرى المُستخدمة في حالة وجود أكثر من صف في المسألة (Micro, Macro, Weighted): # مقاييس الأداء في حالة أكثر من صفين print('\nAccuracy: {:.2f}\n'.format(accuracy_score(y_test, y_pred))) print('Micro Precision: {:.2f}'.format(precision_score(y_test, y_pred, average='micro'))) print('Micro Recall: {:.2f}'.format(recall_score(y_test, y_pred, average='micro'))) print('Micro F1-score: {:.2f}\n'.format(f1_score(y_test, y_pred, average='micro'))) print('Macro Precision: {:.2f}'.format(precision_score(y_test, y_pred, average='macro'))) print('Macro Recall: {:.2f}'.format(recall_score(y_test, y_pred, average='macro'))) print('Macro F1-score: {:.2f}\n'.format(f1_score(y_test, y_pred, average='macro'))) print('Weighted Precision: {:.2f}'.format(precision_score(y_test, y_pred, average='weighted'))) print('Weighted Recall: {:.2f}'.format(recall_score(y_test, y_pred, average='weighted'))) print('Weighted F1-score: {:.2f}'.format(f1_score(y_test, y_pred, average='weighted'))) # تقرير التصنيف from sklearn.metrics import classification_report print('\nClassification Report\n') print(classification_report(y_test, y_pred, target_names=classes)) مما يُعطي الناتج التالي: لاحظ ارتفاع جميع المقاييس مما يعني جودة المُصنف. تصنيف الأشخاص يُمكن الآن تصنيف الأشخاص وذلك وفق تصنيفات تغريداتهم. تقوم الشيفرة التالية بتصنيف تغريدة واحدة، فيكون دخل الدالة classify_tweet سلسلة نصية نضعها أولًا في متجهة تحوي النص. نستدعي دالة تحويل النص إلى أرقام tokenizer.texts_to_sequences ومن ثم توحيد طول المتجهة الرقمية الناتجة وذلك باستدعاء الدالة pad_sequences. # دالة تصنيف تغريدة def classify_tweet(tweet): # تحويل شعاع الكلمات إلى جملة tweet = toSentence(tweet) # وضع الجملة في شعاع ar=[] ar.append(tweet) # تحويل النص إلى قائمة من الأرقام seq = tokenizer.texts_to_sequences(ar) # توحيد طول المتجهة الرقمية pseq = pad_sequences(seq, maxlen=max_len) # استدعاء دالة التنبؤ للنموذج pred = model.predict(pseq) return pred تقوم الدالة classify_person بتصنيف شخص، ويكون معامل الدالة اسم الشخص (بفرض أن ملف تغريداته يحمل نفس الاسم مع اللاحقة csv)، إذ تعمل الدالة أولًا على تحميل تغريدات الشخص في إطار بيانات df. وأخيرًا تكون دالة تصنيف الشخص classify_person هي: # دالة تصنيف الشخص def classify_person(person_name): # تحميل تغريدات الشخص # في إطار بيانات path = person_name + '.csv' df = pd.read_csv(path) # إنشاء قاموس لعد # التغريدات من كل صف classes_count=dict() # إعطاء قيم ابتدائيه 0 for i in range(len(classes)): key=classes[i] classes_count[key]=0 # الحد الأدنى لطول التغريدة min_tweet_len=5 total=0 for _, row in df.iterrows(): tweet=row['tweet'] # تنظيف التغريدة processed_tweet=process_tweet(tweet) if len(processed_tweet)>min_tweet_len: # تصنيف التغريدة c= classify_tweet(processed_tweet) # إيجاد اسم الصف من رمزه topic=le_topics.inverse_transform(c)[0] # إضافة 1 للصف الموافق classes_count[topic]=classes_count[topic]+1 total=total+1 # ترتيب الصفوف وفق العدد # تنازلياً sorted_classes = sorted(classes_count, key=classes_count.get,reverse=True) # القاموس النهائي sorted_classes_cleaned = {} min_display=total/25 # إهمال الصفوف ذات العدد الصغير for w in sorted_classes: if classes_count[w]>min_display: sorted_classes_cleaned[w] = classes_count[w] # طباعة النتائج print(sorted_classes_cleaned) n=0 for key, value in sorted_classes_cleaned.items(): n=n+value print(person_name, "is classified as :") for key, value in sorted_classes_cleaned.items(): print(key, "(", "{:.2f}".format((value/n)*100) , "%)") # رسم فطيرة أعداد الصفوف x = sorted_classes_cleaned.keys() y = sorted_classes_cleaned.values() import matplotlib.pyplot as plt # pie plt.figure(figsize=(9,9)); plt.title(person_name, fontdict = {'fontsize':20}) plt.pie(y, labels = x,autopct='%1.1f%%') plt.show() # مثال classify_person("salem") نجد من الشيفرة السابقة، تُنشئ الدالة القاموس classes_count والذي يكون مفتاحه اسم الصف وقيمته ستكون عدد التغريدات من هذا الصف (تُعطي أولًا قيمة ابتدائية 0 لكل قيم القاموس). يُحدّد المتغير min_tweet_len الطول الأدنى للتغريدة لتؤخذ بعين الاعتبار (لا تحمل التغريدات الصغيرة جدًا معاني بل تكون على الأغلب عبارات مجاملة وترحيب). تدور الدالة على تغريدات الشخص وتستدعي من أجل كل تغريدة دالة المعالجة الأولية للتغريدة process_tweet ثم دالة التصنيف السابقة classify_tweet. يكون ناتج التصنيف رقم (ترميز الصف) ولذا تستدعي الدالة inverse_transform للحصول على اسم الصف ثم نزيد عدد الصف الموافق في القاموس بـ 1. يحسب المتغير total العدد الكلي للتغريدات التي تم أخذها بعين الاعتبار، وتُستخدم الدالة المتغير sorted لترتيب القاموس تنازليا (المعامل reverse=True) وفق العدد. نضع في المتغير min_display مثلًا القيمة total/25 وذلك بهدف عدم إظهار صفوف الشخص قليلة التواتر في تغريداته، ونضع أخيرًا في القاموس sorted_classes_cleaned الصفوف الأكثر تواترًا ونطبع النتائج ونرسم فطيرة تُمثل النسب المئوية لتغريدات الشخص. تكون النتائج مثلًا: الخلاصة عرضنا في هذه المقالة خطوات بناء نموذج تعلّم لتصنيف الأشخاص وفق تغريداتهم. يُمكن تجربة المثال كاملًا من موقع Google Colab من الرابط أو من الملف المرفق data.zip. اقرأ أيضًا تحليل المشاعر في النصوص العربية باستخدام التعلم العميق دليل المبتدئين لفهم أساسيات التعلم العميق خطوات تنفيذ مشروع عن تعلم الآلة في بايثون: الجزء الأول data.zip
-
نعرض في هذه المقالة الإرشادات العامة الأساسية الواجب اتباعها لإظهار المحتوى، ولا سيما النصوص الطويلة نسبيًا بوضوح على مختلف أنواع ومقاسات شاشات العرض. القراءة على الويب يُلخص الدليل الإرشادي للكتابة الموضوع من قِبل الحكومة الأمريكية ما يريده الأشخاص من الكتابة على الويب بما يلي: تُظهر الأبحاث أن الأشخاص لا يقرؤون صفحات الويب بتمعُّن، وإنما كل ما يفعلونه هو مسحها سريعًا؛ حيث يقرأ الأشخاص حوالي 20-28% فقط من محتوى صفحة الويب وسطيًا. تكون القراءة من الشاشة أبطأ من قراءة الورق. سيهجر الأشخاص موقع الويب ويغادروه، إذا لم يكن من السهل الوصول إلى معلوماته وفهمها. الكتابة للجوال يُعدّ التركيز على الموضوع المطروح ووضع خلاصته أولًا من القواعد الأساسية للكتابة للجوال. يجب توضيح النقاط الرئيسية للموضوع في البداية؛ حيث تنص القاعدة العامة وعلى نحوٍ مثالي بوجوب وضع النقاط الأساسية في الفقرات الأربع الأولى وبما لا يزيد عن 70 كلمة لتُناسب الكتابة مختلف الأجهزة وإطارات العرض. يجب التأكد من أن المحتوى موجَّهٌ لمساعدة زوار الموقع في تحقيق أهدافهم، لذا يجب البدء أولًا بتحديد الشريحة المستهدفة وتحديد توقعات المستخدمين واحتياجاتهم. يجب الكتابة باستخدام أسلوب الخطاب المباشر وعرض الإجراءات والحلول العملية؛ كما يجب نشر ما يريده الزوار والابتعاد عن الحشو والتكرار. تُظهر أبحاث الحكومة البريطانية ما يلي أيضًا: والخلاصة هي أنه يجب استخدام لغةٍ بسيطة وكلمات أقصر وتركيبات جمل سهلة حتى مع الجمهور المتعلِّم والتقني؛ كما يجب الحفاظ على نبرةٍ خطابية ما لم يكن هناك سببٌ وجيهٌ لخلاف ذلك. تنص أحد القواعد القديمة للصحافة بأن نكتب كما لو كنا نتحدث إلى شخص ذكي يبلغ 11 عامًا. المستخدمون القادمون يُعدّ أسلوب الكتابة المُختزل ضروريًا للقراء على الأجهزة المحمولة خصوصًا، وهو أمرٌ بالغ الأهمية عند إنشاء محتوى الهواتف منخفضة التكلفة ذات إطارات العرض الصغيرة، والتي تتطلب مزيدًا من التمرير وقد تحتوي على شاشاتٍ ذات جودةٍ منخفضة واستجابة ضعيفة. يمتلك معظم مستخدمي الويب، والبالغ عددهم أكثر من مليار مستخدم، أجهزةً رخيصة، ولا يرغبون في إنفاق كلفة الاتصال بالويب على التنقل في محتوًى طويل، كما أنهم قد لا يقرؤون بلغتهم الأم؛ لذلك يجب دومًا اختصار النص، أي استخدام جملٍ قصيرة وعلامات ترقيم أقل وفقرات من خمسة أسطر أو أقل وعناوين على سطر واحد فقط؛ كما يجب استخدام النصوص المتجاوبة، مثل استخدام عناوين أقصر لإطارات العرض الصغيرة، مع الحذر من الجوانب السلبية. يؤدي اتباع أسلوب الحد الأدنى من النص إلى تسهيل توطين المحتوى وتدويله أيضًا، ويزيد من احتمالية اقتباس المحتوى في وسائل التواصل الاجتماعي. يجب الإلتزام بقواعد الحد الأدنى: الحفاظ على البساطة. تقليل الحشو والجمل السردية الطويلة. التوجُّه للمغزى المفيد مباشرةً. حذف المحتوى غير الضروري يتزايد حجم صفحات الويب يومًا بعد يوم؛ كما تتيح تقنيات التصميم المتجاوب -التي عرضناها سابقًا- تقديم محتوًى مختلف لإطارات العرض الأصغر، ولكن من الأجدر البدء بتبسيط النص والصور والمحتويات الأخرى دائمًا. يقول جاكوب نيلسون Jakob Nielsen: يجب التساؤل عن أهداف زوار الموقع دومًا وفيما إذا كان كل مكوّن في الصفحة يُساعد الزوار في الوصول لأهدافهم. حذف عناصر الصفحة المكررة يبلغ الحجم الوسطي لملفات HTML حوالي 70 كيلو بايت مع أكثر من تسعة طلبات لصفحة الويب الواحدة وسطيًا وفق أرشيف HTTP. تستخدم العديد من المواقع الشهيرة عدة آلافٍ من عناصر HTML في كل صفحة، وعدة آلافٍ من سطور التعليمات البرمجية، وذلك حتى على أجهزة الجوال. قد لا يجعل الحجم الزائد لملف HTML عملية التحميل أبطأ، إلا أنه يُعطي إشاراتٍ واضحة على تضخُّم المحتوى؛ حيث يُشير إلى عناصر أكثر ونصوصًا أكبر أو الأمرين معًا. يؤدي تخفيض تعقيد HTML إلى تخفيض حجم الصفحة والمساعدة في التخصيص المحلي والدولي وتسهيل تخطيط التصميم المتجاوب وتصحيحه. للحصول على معلوماتٍ حول كتابة HTML بكفاءة أكبر، يُمكن الرجوع إلى HTML عالي الأداء. من التغريدات الشهيرة لكاربور سيل Gabor Cselle على تويتر: ينطبق نفس الأمر على المحتوى؛ حيث يجب مساعدة المستخدمين في الوصول إلى المطلوب بأسرع ما يُمكن؛ كما لا يجب إخفاء المحتوى لمستخدمي الجوال فقط. يجب محاولة تحقيق مبدأ تكافؤ المحتوى، لأن تخمين الميزات التي لن يفقدها مستخدمو الجوال قد يكون خاطئًا مع بعض الأشخاص. يجب إنشاء إصداراتٍ مختلفة من نفس المحتوى في حال توفر الموارد لتُناسب الحجوم المختلفة لإطارات العرض، أو على الأقل لعناصر الصفحة ذات الأولوية العالية. يجب أخذ إدارة المحتوى وتسلسل خطوات العمل بالحسبان: هل تؤدي الأنظمة القديمة إلى محتوًى قديم؟ تبسيط النص يتزايد تصفح الويب على أجهزة الجوال مما يُلزم تغيير طريقة الكتابة للوصول إلى محتوًى أسهل يذهب مباشرًة للمغزى المقصود بعيدًا عن الحشو بلا فائدة. حذف الصور المكررة يُمكن أن تكون الصور جميلةً وممتعةً وغنيةً بالمعلومات، إلا أنها تستخدم موارد الصفحة وتُضيف إلى حجمها وتزيد من عدد طلبات الملفات. تؤدي رداءة الاتصال إلى زيادة زمن الاستجابة؛ مما يعني أن الزيادة في طلبات ملفات الصور ستُفاقم المشكلة عند فتح الموقع من الجوال. يُظهر موقع أرشفة بيانات HTTP أن صفحات الويب تطلب ملفات الصور 54 مرةً وسطيًا: كما تُشكّل الصور أكثر من 60% من حجم الصفحة: تستهلك الصور الطاقة أيضًا، حيث يُعدّ الاتصال ثاني أكبر سببٍ لاستنفاد بطارية الجوال بعد الشاشة؛ وهذا يعني أن زيادة طلبات الصور تستلزم مزيدًا من استخدام الاتصال وبالتالي تفريغ البطارية. يتناسب استهلاك الطاقة مع إظهار الصور طردًا مع حجمها وعددها. يُمكن العودة لتقرير من قتل بطاريتي من ستانفورد. يُحبَّذ التخلص من الصور إن أمكن ذلك. ومن الإرشادات المقترحة: يجب التفكير في تصميمات تتجنب الصور تمامًا، أو تستخدمها باعتدال. يُمكن أن يكون استخدام النص لوحده رائعًا (راجع الرابط). يجب البدء أولًا بدراسة سلوك زوار الموقع؛ وماذا يُريدون منه؛ وفيما إذا كانت الصور مُساعدةً لهم أم لا. شاع سابقًا حفظ العناوين والنصوص الهامة مثل صور؛ ولكن لا يتجاوب هذا الأسلوب مع تغييرات حجم إطارات العرض؛ كما أنه يزيد من حجم الصفحة ومن زمن الاستجابة. لن تصل محركات البحث ولا قارئات الشاشة ولا التقنيات المساعدة الأخرى إلى النصوص المحفوظة مثل صور. يجب استخدام النصوص "الحقيقية" ما أمكن ذلك، كما يمكن أن توفّر خطوط الويب وأنماط CSS مظهرًا جميلًا للنصوص. يُحبذ استخدام أنماط CSS بدلًا من الصور للتدرجات والظلال والزوايا الدائرية ونقشات الخلفية (وهي جميعًا مدعومة من قبل كل المتصفحات الحديثة). ومع ذلك، يجب الانتباه إلى أنه وعلى الرغم من أن استخدام CSS أفضل من استخدام الصور؛ إلا أن له كلفةٌ إضافيةٌ للمعالجة والإظهار لاسيما على الجوال. من النادر أن تعمل صور الخلفية جيدًا على الجوال. يُمكن استخدام استعلامات الوسائط لتجنُّب وضع صور الخلفية على إطارات العرض الصغيرة. يجب تجنب وضع الصور في شاشة البداية. يجب استخدام أنماط CSS للتحريك (راجع مقالة أساسيات التحريك). يجب معرفة الخطوط الرسومية اللازمة واستخدام الرموز unicode والأيقونات عوضًا عن الصور، واستخدام خطوط الويب Web Fonts إذا كان ذلك ضروريًا. يُفضَّل استخدام الأيقونات المتوفرة في الخطوط لأنها رسومات متجهة يُمكن تحجيمها بدون حدود، كما يُمكن تنزيل مجموعة من الأيقونات في نوع خطٍ واحد. يُمكن استخدام عنصر الحاوية <canvas> لإنشاء الصور في سكريبت جافا باستخدام الخطوط والمنحنيات والنصوص وصور أخرى. لا تقلّل الصور من النوع SVG أو من نوع روابط البيانات (يُمكن وضع كلا النوعين سطريًا inline في CSS) من حجم الصفحة، إلا أنها تُخفّض من زمن الاستجابة عن طريق تخفيض عدد طلبات الملف المصدر. يتوفر للصور SVG دعمٌ واسع على الجوالات وعلى متصفحات الحواسيب المكتبية؛ كما يُمكن لأدوات التحسين تخفيض حجم الرسومات SVG. وبالمثل، تُدعم بيانات الروابط جيدًا. يُفضّل استخدام العنصر <video> عوضًا عن الصور المتحركة GIFs. تصميم المحتوى ليعمل جيدا على مختلف حجوم إطارات العرض ينصح براين فلينج في تصميم وتطوير الجوال Mobile Design and Development بما يلي: لا يلجأ المصممون المتميزون إلى عمليات التحسين لملاءمة الجوال، بل يفكرون على نحوٍ متجاوب في إنشاء مواقعٍ تعمل على مختلف الأجهزة. تٌعدّ هيكلية النص ومحتويات الصفحة الأخرى أمرًا أساسيًا لتحقيق النجاح على مختلف الأجهزة. يستخدم الكثير من الأشخاص الذين يدخلون على الويب والذي يتجاوز عددهم المليار مستخدم جوالاتٍ منخفضة التكلفة مع إطارات عرض صغيرة، وبذلك يُمكن أن تكون القراءة على شاشة منخفضة الدقة مقاس 3.5 بوصة أو 4 بوصة عملًا شاقًا. يُبين الشكل التالي صورةً لهذين المقاسين معًا: يبدو النص على الشاشة الكبيرة صغيرًا إلا أنه مقروء؛ بينما يكون على الشاشة الصغيرة غير قابلًا للقراءة رغم ظهور تخطيط الصفحة صحيحًا، كما يبدو العرض ضبابيًا عند التكبير وتفقد الألوان من بريقها فلا يعود اللون الأبيض أبيضًا مثلًا، ويصبح المحتوى غير واضح. تصميم المحتوى للجوال يجب وضع المحتوى على أنه أولوية مع مراحل التخطيط والتصميم الفني، أي أنه يجب التصميم مع نصوص وصور حقيقية وليس مع محتوًى وهمي. يقول جيفري زيلدمان Jeffrey Zeldman: يجب وضع المحتوى الأكثر أهمية في الأعلى، حيث يميل المستخدمون إلى قراءة صفحات الويب على شكل الحرف F؛ أي يهتمون أولًا بالجزء الأعلى ثم يمسحون المنتصف. يزور المستخدمون الموقع لتحقيق هدفٍ ما؛ لذلك يجب دومًا دراسة ما يحتاجون إليه لتحقيق هذا الهدف والتخلص من كل شيءٍ آخر إضافي. يجب التدقيق في الزخارف المرئية والنصية والمحتوى القديم والروابط الزائدة وما لا داعٍ له. يجب توخي الحذر عند استخدام أيقونات المشاركة الاجتماعية، حيث يُمكن أن تُسبب فوضى في التخطيطات، كما يُمكن لشيفرتها أن تُبطئ تحميل الصفحة. يجب تصميم التخطيطات المتجاوبة مع المحتوى وغير المخصصة لحجوم أجهزةٍ ثابتة. اختبار المحتوى لنتذكر أنه لتحقيق النجاح: مهما فعلنا، فلا بُدّ من الاختبار. يجب التحقق من إمكانية القراءة على إطارات العرض الأصغر باستخدام أدوات المطور Chrome DevTools وأدوات المحاكاة الأخرى. يجب اختبار المحتوى في ظل ظروف حيز النطاق التراسلي المنخفض والتأخير العالي؛ لذلك يجب تجربة المحتوى في مجموعةٍ متنوعة من سيناريوهات الاتصال. يجب محاولة قراءة المحتوى والتفاعل معه على جوالٍ رخيص. يجب الطلب من الأصدقاء والزملاء تجربة التطبيق أو الموقع. يجب بناء مختبر لاختبار الجهاز. يوفّر GitHub repo الخاص بمختبر Mini Mobile Device من Google الإرشادات حول كيفية إنشاء مختبرٍ مُخصص. من المفيد استخدام OpenSTF، وهو تطبيق ويب بسيط لاختبار مواقع الويب على العديد من أجهزة Android. يُبين الشكل التالي استخدام OpenSTF: يتزايد استخدام الأجهزة المحمولة لتصفح المحتوى والحصول على المعلومات، وليس فقط أجهزةً للاتصال والألعاب والوسائط المتعددة، مما يجعل من الأهمية بمكان تصميم المحتوى ليعمل على طيفٍ واسعٍ من إطارات العرض، وإعطاء المحتوى الأولوية عند تصميم تخطيط الصفحة والواجهات والتفاعل مع المستخدم بحيث يظهر المحتوى صحيحًا على مختلف الأجهزة. فهم كلفة البيانات يتزايد حجم صفحات الويب على نحوٍ مُطّرد. فوفقًا لـ أرشيف HTTP يبلغ متوسط حجم الصفحة لـ أهم مليون موقع أكثر من 2 ميغا بايت. يتجنب المستخدمون المواقع أو التطبيقات التي يعتقدون أنها بطيئة أو باهظة الثمن، لذا من الضروري فهم تكلفة تحميل الصفحة ومكونات التطبيق. يُمكن أن يكون تخفيض حجم الصفحة مربحًا أيضًا. اكتشف كريس زاكرياس من YouTube أنه عند تخفيض حجم صفحة المشاهدة من 1.2 ميغا بايت إلى 250 كيلو بايت: وبعبارةٍ أخرى: يُمكن أن يؤدي تخفيض حجم الصفحة إلى فتح أسواقٍ جديدة بالكامل. حساب حجم الصفحة يتوفر العديد من الأدوات لحساب حجم الصفحة. تعرض لوحة المطور Chrome DevTools Network الحجم الإجمالي بالبايت لجميع الموارد، ويُمكن استخدامها للتأكد من حجم كل نوع من الموارد. يُمكن أيضًا التحقق من العناصر المُستعادة من ذاكرة التخزين المؤقت cache للمتصفح. يوفر المتصفح Firefox والمتصفحات الأخرى أدواتٍ مماثلةً أيضًا. يوفر WebPagetest إمكانية اختبار تحميل الصفحة للمرة الأولى والتحميلات اللاحقة لها. يُمكن أتمتة الاختبار باستخدام سكريبت (لتسجيل الدخول إلى موقعٍ ما مثلًا) أو باستخدام واجهات برمجة التطبيقات RESTful APIs الخاصة بهم. يوضح المثال التالي المُنزّل من developers.google.com/web بأن التخزين المؤقت كان ناجحًا وأن عمليات تحميل الصفحة اللاحقة لا تتطلب مواردًا إضافية. يعرض WebPagetest الحجم وتفصيلات الطلب حسب نوع MIME أيضًا. حساب كلفة الصفحة ينظر كثيرٌ من المستخدمين إلى الكلفة المالية لتصفح الموقع؛ وليس إلى عدد البايتات اللازمة؛ أو إلى أداء الموقع السريع. يسمح الموقع "ما هي كلفة موقعي" What Does My Site Cost? بتقدير التكلفة المالية الفعلية لتحميل موقعٍ ما. يُبين المخطط التكراري التالي كلفة تحميل الموقع amazon.com (باستخدام طريقة الدفع المُسبق للبيانات): يجب الانتباه إلى أن ذلك لا يأخذ بالحسبان قدرة الشخص على تحمُّل التكاليف موازنةً بدخله. يُمكن أيضًا الرجوع إلى الموقع blog.jana.com لمعاينة كلفة البيانات. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } البلد كلفة 500MB الحد الأدنى للأجر الساعي عدد ساعات العمل لدفع كلفة 500MB الهند $3.38 $0.20 17 ساعة أندونيسيا $2.39 $0.43 6 ساعة البرازيل $13.77 $1.04 13 ساعة لا يُشكّل حجم الصفحة مشكلةً فقط للأسواق الناشئة؛ حيث يجب أيضًا ملاحظة اشتراك الكثير من الأشخاص في معظم البلدان بخطط الدفع محدودة البيانات وبأنهم يتجنبون بالطبع الصفحات الثقيلة والمُكلفة؛ كما أن خطط البيانات "غير المحدودة" للجوالات وشبكات wifi يكون لها في النهاية حدٌ معين للبيانات تتوقف بعده الخدمة أو يُحدّ منها. يُنصح بالتمتُّع بالشفافية والإعلام عن حجم البيانات التي يستهلكها الموقع. وبالنتيجة، يؤثر حجم الصفحة على كلٍ من الأداء والتكلفة المالية. ترجمة -وبتصرف- للمقالة Multi-Device Content للمؤلف: Sam Dutton. اقرأ أيضًا الصور في تصميم صفحات الويب المتجاوب نماذج تصميم الويب المتجاوب تحريك واجهات العرض أثناء التنقل في موقع الويب
-
يُمكن في تصميم الويب المتجاوب تغيير المحتوى إضافًة إلى تغيير التخطيط وفقًا لمواصفات الجهاز. يمكن عرض الصور عالية الدقة على نحوٍ ممتاز على الشاشات عالية الدقة (2x)؛ كما يُمكن أن تظهر صورةٌ عرضها 50% جيدًا على متصفحٍ عرضه 800px، بينما ستستهلك كثيرًا من المساحة على هاتفٍ ضيق، كما أن تحجيمها لملاءمة الشاشات الصغيرة سيتطلب نفس تكلفة حيّز النطاق التراسلي bandwidth. الإدارة الفنية تتطلب مسائلٌ أخرى إجراء تغييرات جذرية على الصور، مثل تغيير نسب الصورة، أو القص، أو حتى استبدال كامل الصورة، وتُدعى هذه التغييرات بالإدارة الفنية ويُمكن العودة إلى responsiveimages.org لمزيدٍ من الأمثلة. الصور المتجاوبة ربما لا يعلم الأشخاص أن الصور تُمثّل أكثر من 60٪ وسطيًا من البايتات اللازمة لتحميل صفحة ويب. سنعرض فيما يلي كيفية التعامل مع الصور الموجودة على الويب الحديث بحيث تبدو الصور رائعةً وتُحمّل على أي جهازٍ بسرعة. كما نشرح مجموعةً من المهارات والتقنيات لمكاملة الصور المتجاوبة ضمن تسلسل عمليات تطوير صفحات الويب؛ بحيث تتكيف هذه الصور وتُلائم حجوم إطارات العرض المختلفة وسيناريوهات الاستخدام المتعددة. الصور في لغات الترميز markup يُعدّ العنصر img من العناصر الأساسية القوية فهو ينزِّل المحتوى ويفك ترميزه ويعرضه، كما تدعم المتصفحات الحديثة طيفًا واسعًا من تنسيقات الصور. لا يختلف تضمين الصور في الأجهزة المختلفة عن تضمينها في حاسوبٍ مكتبي مع ضرورة إجراء بعض التعديلات الطفيفة أحيانًا لتحقيق تجربة استخدامٍ جيدة. يجب عمومًا الانتباه لما يلي: استخدام الحجوم النسبية للصور لمنع امتدادها خارج حاويتها عن طريق الخطأ. استخدام العنصر picture لتحديد صورٍ مختلفة تظهر واحدةٌ منها وفق مواصفات جهاز العرض (الإدارة الفنية). استخدام السمة "مجموعة المصادر" srcset والسمة x في العنصر img لإرشاد المتصفح لاختيار الصورة الأنسب من بين كثافاتٍ مختلفة. استخدام الصور السطرية inline في حال احتواء الصفحة على صورةٍ أو صورتين لتخفيض عدد طلبات تحميل ملف الصورة. استخدام الحجم النسبي للصور لا بُدّ من استخدام الوحدات النسبية عند تحديد عرض الصورة كي لا تمتد خارج إطار العرض عن طريق الخطأ؛ فعند تحديد العرض إلى width: 50% مثلًا، سيكون عرض الصورة دومًا 50% من عرض حاويتها وليس 50% من عرض إطار العرض أو من عرض الصورة نفسها. يُمكن أيضًا أن نحتاج لاستخدام max-width: 100% وذلك لسماح أنماط CSS للمحتوى بالامتداد خارج حاويته. img, embed, object, video { max-width: 100%; } يجب توفير وصفٍ مفيدٍ للصورة باستخدام السمة alt في عناصر img؛ مما يُساعد قارئات الشاشة والتقنيات المساعدة الأخرى من الوصول للموقع بسهولةٍ أكبر. تحسين عنصر الصور img باستخدام السمة srcset للأجهزة عالية الكثافة تُحسّن السمة srcset من أداء العنصر img، حيث توفّر مجموعة ملفات صور متعددة للاختيار منها وفقًا لمواصفات الجهاز. على غرار الدالة image-set الأساسية في أنماط CSS، تسمح السمة srcset للمتصفح باختيار الصورة الأنسب وفقًا لمواصفات الجهاز، مثل استخدام صورة 2x على شاشة عرض 2x، أو ربما لاحقًا، صورة 1x على شاشة 2x عند محدودية النطاق الترددي للشبكة المستخدمة. <img src="photo.png" srcset="photo@2x.png 2x" ...> تستخدم المتصفحات التي لا تدعم srcset ملف الصورة الافتراضي المُحدّد بالسمة src، لذا فمن المهم دومًا تضمين صورة 1x يُمكن عرضها على أي جهازٍ بغض النظر عن إمكاناته؛ أما في حال دعم السمة srcset، فتُحلّل قائمة الصور/الشروط المفصولة بفواصل قبل أي طلب، ومن ثم تُنزّل وتُعرض الصورة الأكثر ملاءمة. يُمكن للشروط الموضوعة على الصور أن تحوي أي شيءٍ، مثل كثافة البكسلات والعرض والطول، إلا أن الكثافة فقط هي المدعومة حاليًا. يجب دومًا توفير صورة 2x لتحقيق التوازن بين السلوك الحالي والميزات المستقبلية لاحقًا. الإدارة الفنية للصور المتجاوبة باستخدام العنصر picture يُمكن تغيير الصور وفقًا لمواصفات الجهاز والمعروفة أيضًا باسم الإدارة الفنية، باستخدام العنصر picture؛ الذي يوفر إمكانية التصريح لمجموعةٍ من الصور المختلفة للاختيار منها وفقًا لمواصفات الجهاز، مثل الحجم والدقة والاتجاه وغيرها. يتزايد دعم العنصر picture في المتصفحات، بالرغم من عدم توفره في جميعها بعد؛ ولكن يُنصح باستخدام هذا العنصر لتوافقه الكبير مع الإصدارات السابقة واحتمال استخدام المزايا التي توفّرها تقنيات الصور المتجاوبة المتوفرة في المشروع من النمط "نقص الدعم" Picturefill polyfill. يُستخدم العنصر picture عند توفُّر الصورة بكثافاتٍ مختلفة؛ أو عندما يتطلب التصميم المتجاوب عرض صورٍ مختلفة على بعض أنواع الشاشات. وعلى غرار عنصر الفيديو video، يُمكن تضمين عدة عناصر "مصدر" source لتحديد ملفات صورٍ مختلفة اعتمادًا على استعلامات الوسائط أو تنسيق الصورة. <picture> <source media="(min-width: 800px)" srcset="head.jpg, head-2x.jpg 2x"> <source media="(min-width: 450px)" srcset="head-small.jpg, head-small-2x.jpg 2x"> <img src="head-fb.jpg" srcset="head-fb-2x.jpg 2x" alt="a head carved out of wood"> </picture> يُمكن معاينة مثال github.io. يستخدم المتصفح في المثال السابق الصورة head.jpg، أو الصورة head-2x.jpg (حسب دقة الجهاز) إذا كان عرضه 800px على الأقل؛ أما إذا كان عرض المتصفح بين 450px و 800px، فيستخدم head-small.jpg، أو head-small- 2x.jpg (حسب دقة الجهاز)؛ بينما تُعرض الصورة المُحدّدة في العنصر img (والواجب تضمينه دائمًا) على الشاشات ذات العرض الأصغر من 450px، أو في حال عدم دعم العنصر picture. الصور ذات الحجم النسبي يُمكن أن يكون صعبًا تحديد كثافة الصور في حال عدم معرفة الحجم النهائي للصورة، خصوصًا مع الصور المُنسابة والتي يُمكن أن تمتد لتتناسب مع عرض المتصفح. يُمكن عوضًا عن تقديم حجوم وكثافات ثابتة، تحديد حجم كل صورة بضبط سمة العرض إضافًة لحجم عنصر الصورة؛ مما يسمح للمتصفح حساب كثافة البكسلات تلقائيًا واختيار الصورة الأنسب للتنزيل. <img src="lighthouse-200.jpg" sizes="50vw" srcset="lighthouse-100.jpg 100w, lighthouse-200.jpg 200w, lighthouse-400.jpg 400w, lighthouse-800.jpg 800w, lighthouse-1000.jpg 1000w, lighthouse-1400.jpg 1400w, lighthouse-1800.jpg 1800w" alt="a lighthouse"> يُمكن معاينة المثال يعرض المثال السابق صورةً لها نصف عرض إطار العرض sizes="50vw"، ويختار المتصفح الصورة المناسبة اعتمادًا على عرض المتصفح وعلى نسبة البكسلات في الجهاز وذلك بغض النظر عن حجم نافذة المتصفح. يُبين الجدول التالي بعض الأمثلة عن الصور التي سيختارها المتصفح: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } عرض المتصفح نسبة البكسلات للجهاز الصورة المستخدمة الدقة الفعلية 1x 200.jpg 1 400px 2x 400.jpg 2 400px 2.5x 400.jpg 2 320px 2.67x 800.jpg 2 600px 3.125x 1000.jpg 3 640px 1.45x 800.png 1 1100px الصور المتجاوبة والنقاط الحدية يُمكن تغيير حجم الصورة اعتمادًا على النقاط الحدّية المُحدّدة في تخطيط الموقع. مثلًا: يُمكن تفضيل امتداد صورة على كامل عرض إطار العرض في شاشة صغيرة، مع وضعها في جزء صغير من شاشة كبيرة. <img src="400.png" sizes="(min-width: 600px) 25vw, (min-width: 500px) 50vw, 100vw" srcset="100.png 100w, 200.png 200w, 400.png 400w, 800.png 800w, 1600.png 1600w, 2000.png 2000w" alt="an example image"> يُمكن معاينة المثال تستخدم سمة الحجوم sizes في المثال السابق عدة استعلامات وسائط لتحديد حجم الصورة. يُصبح حجم الصورة 25% من عرض إطار العرض عندما يتجاوز عرض المتصفح 600px؛ بينما يُصبح 50% من عرض إطار العرض عندما يكون عرض المتصفح بين 500px و 600px؛ أما عندما يكون عرض المتصفح أقل من 500px، فتمتد الصورة على كامل عرض المتصفح. توسيع صور المنتجات يحتاج مستخدمو مواقع التجارة الإلكترونية لمعاينة مشاهد مُقرّبة من المنتجات بدقة عالية بهدف تفحص تفاصيل المنتج، كما تؤكد الدراسات الإحباط الكبير لهؤلاء المستخدمين إذا لم يتمكنوا من ذلك. يوفر موقع J. Crew مثالًا جيدًا للصور القابلة للنقر والتوسيع حيث يظهر على كل صورة شريط صغير (يختفي عند النقر) يُعلّم المستخدم بإمكانية النقر على الصورة لتكبيرها ومعاينة تفاصيلها. تقنيات أخرى مع الصور الصور المضغوطة توفر تقنيات الصور المضغوطة compressive image technique صورًا مضغوطة 2x تُناسب جميع الأجهزة مهما كانت إمكاناتها؛ حيث ينخفض حجم الصور كثيرًا (حسب نوع الصورة ودرجة الضغط) مع عدم ملاحظة أي تغيير في جودة الصورة. ويُمكن معاينة مثال compressive.html يجب توخي الحذر عند استخدام التقانات الضاغطة، حيث تتطلب ذاكرةً أكبر ومعالجةً أكثر لفك الضغط. يُعدّ تغيير حجم الصور الكبيرة لملاءمة الشاشات الصغيرة أمرًا مُكلفًا ويُمكن أن يكون مرهقًا خصوصًا للأجهزة قليلة الإمكانات ذات الذاكرة الصغيرة والمعالجة المحدودة. استبدال الصور باستخدام JavaScript يُمكن استخدام سكريبت جافا لفحص قدرات الجهاز ومن ثم إجراء الأنسب؛ حيث يُمكن مثًلا معرفة نسبة بكسلات الجهاز باستخدام window.devicePixelRatio؛ كما يُمكن معرفة طول الشاشة وعرضها؛ إضافًة لإمكانية فحص ميزات الاتصال الشبكي باستخدام navigator.connection أو إجراء طلبٍ مزيف. وعند الحصول على جميع هذه المعلومات، ستُحدّد الصورة المناسبة للتحميل. يُعدّ تأخير تحميل الصورة حتى انتهاء عمليات الفحص والتحقق أحد سلبيات استخدام JavaScript؛ مما يعني أن تحميل الصور لن يبدأ إلا بعد تشغيل حدث تحميل الصفحة pageload. علاوًة على ذلك، يُمكن أن يُنزِّل المتصفح كلًا من الصور 1x و 2x مما يؤدي لزيادة حجم الصفحة. الصور السطرية- الصور النقطية والصور المتجهة تُنشأ الصور وتُخزّن باستخدام طريقتين مختلفتين تمامًا مما ينعكس على طريقة نشر الصور على نحوٍ متجاوب. الصور النقطية: مثل الصور الفوتوغرافية وغيرها، والتي تُمثّل بشبكةٍ من نقاط الألوان (البكسلات). تُنتِج الكاميرات والماسحات الضوئية الصور النقطية عادًة، كما يُمكن إنتاجها باستخدام عناصر الحاويات canavas في HTML. تُستخدم التنسيقات، مثل PNG و JPEG و WebP لتخزين هذا النوع من الصور. الصور المتجهة: تُعرّف هذه الصور باستخدام مجموعة من المنحنيات والخطوط والأشكال وألوان التعبئة والتدرجات اللونية، مثل الشعارات logo والرسومات الخطية. يُمكن إنشاء الصور المتجهة باستخدام برامجٍ متخصصة، مثل Adobe Illustrator أو Inkscape، أو استخدام لغة ترميزٍ معينة، مثل لغة الرسومات المتجهة القابلة للتحجيم Scalable Vector Graphics. الرسومات المتجهة SVG القابلة للتحجيم .side-by-side { display: inline-block; margin: 0 20px 0 0; width: 45%; } span#data_uri { background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0D%0A%3C%21--%20Generator%3A%20Adobe%20Illustrator%2016.0.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%206.00%20Build%200%29%20%20--%3E%0D%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%0D%0A%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%0D%0A%09%20width%3D%22396.74px%22%20height%3D%22560px%22%20viewBox%3D%22281.63%200%20396.74%20560%22%20enable-background%3D%22new%20281.63%200%20396.74%20560%22%20xml%3Aspace%3D%22preserve%22%0D%0A%09%3E%0D%0A%3Cg%3E%0D%0A%09%3Cg%3E%0D%0A%09%09%3Cg%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23E44D26%22%20points%3D%22409.737%2C242.502%20414.276%2C293.362%20479.828%2C293.362%20480%2C293.362%20480%2C242.502%20479.828%2C242.502%20%09%09%09%0D%0A%09%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpath%20fill%3D%22%23E44D26%22%20d%3D%22M281.63%2C110.053l36.106%2C404.968L479.757%2C560l162.47-45.042l36.144-404.905H281.63z%20M611.283%2C489.176%0D%0A%09%09%09%09L480%2C525.572V474.03l-0.229%2C0.063L378.031%2C445.85l-6.958-77.985h22.98h26.879l3.536%2C39.612l55.315%2C14.937l0.046-0.013v-0.004%0D%0A%09%09%09%09L480%2C422.35v-79.32h-0.172H368.853l-12.207-136.871l-1.189-13.325h124.371H480v-49.668h162.17L611.283%2C489.176z%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23F16529%22%20points%3D%22480%2C192.833%20604.247%2C192.833%20603.059%2C206.159%20600.796%2C231.338%20599.8%2C242.502%20599.64%2C242.502%20%0D%0A%09%09%09%09480%2C242.502%20480%2C293.362%20581.896%2C293.362%20595.28%2C293.362%20594.068%2C306.699%20582.396%2C437.458%20581.649%2C445.85%20480%2C474.021%20%0D%0A%09%09%09%09480%2C474.03%20480%2C525.572%20611.283%2C489.176%20642.17%2C143.166%20480%2C143.166%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23F16529%22%20points%3D%22540.988%2C343.029%20480%2C343.029%20480%2C422.35%20535.224%2C407.445%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23EBEBEB%22%20points%3D%22414.276%2C293.362%20409.737%2C242.502%20479.828%2C242.502%20479.828%2C242.38%20479.828%2C223.682%20%0D%0A%09%09%09%09479.828%2C192.833%20355.457%2C192.833%20356.646%2C206.159%20368.853%2C343.029%20479.828%2C343.029%20479.828%2C293.362%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23EBEBEB%22%20points%3D%22479.828%2C474.069%20479.828%2C422.4%20479.782%2C422.413%20424.467%2C407.477%20420.931%2C367.864%20%0D%0A%09%09%09%09394.052%2C367.864%20371.072%2C367.864%20378.031%2C445.85%20479.771%2C474.094%20480%2C474.03%20480%2C474.021%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22343.784%2C50.229%20366.874%2C50.229%20366.874%2C75.517%20392.114%2C75.517%20392.114%2C0%20366.873%2C0%20366.873%2C24.938%20%0D%0A%09%09%09%09343.783%2C24.938%20343.783%2C0%20318.544%2C0%20318.544%2C75.517%20343.784%2C75.517%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22425.307%2C25.042%20425.307%2C75.517%20450.549%2C75.517%20450.549%2C25.042%20472.779%2C25.042%20472.779%2C0%20403.085%2C0%20%0D%0A%09%09%09%09403.085%2C25.042%20425.306%2C25.042%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22508.537%2C38.086%20525.914%2C64.937%20526.349%2C64.937%20543.714%2C38.086%20543.714%2C75.517%20568.851%2C75.517%20568.851%2C0%20%0D%0A%09%09%09%09542.522%2C0%20526.349%2C26.534%20510.159%2C0%20483.84%2C0%20483.84%2C75.517%20508.537%2C75.517%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22642.156%2C50.555%20606.66%2C50.555%20606.66%2C0%20581.412%2C0%20581.412%2C75.517%20642.156%2C75.517%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23FFFFFF%22%20points%3D%22480%2C474.021%20581.649%2C445.85%20582.396%2C437.458%20594.068%2C306.699%20595.28%2C293.362%20581.896%2C293.362%20%0D%0A%09%09%09%09480%2C293.362%20479.828%2C293.362%20479.828%2C343.029%20480%2C343.029%20540.988%2C343.029%20535.224%2C407.445%20480%2C422.35%20479.828%2C422.396%20%0D%0A%09%09%09%09479.828%2C422.4%20479.828%2C474.069%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23FFFFFF%22%20points%3D%22479.828%2C242.38%20479.828%2C242.502%20480%2C242.502%20599.64%2C242.502%20599.8%2C242.502%20600.796%2C231.338%20%0D%0A%09%09%09%09603.059%2C206.159%20604.247%2C192.833%20480%2C192.833%20479.828%2C192.833%20479.828%2C223.682%20%09%09%09%22%2F%3E%0D%0A%09%09%3C%2Fg%3E%0D%0A%09%3C%2Fg%3E%0D%0A%3C%2Fg%3E%0D%0A%3C%2Fsvg%3E%0D%0A) no-repeat; background-size: cover; height: 484px; } span#svg { background: url(data:image/svg+xml;utf8,) no-repeat; background-size: cover; height: 484px; } تُمكّن الرسومات SVG من تضمين رسوماتٍ متجهةٍ متجاوبة في صفحة ويب. تُعدّ إمكانية المستعرض عرض صورةٍ متجهة بأي حجم من أهم ميزات تنسيقات الملفات المتجهة موازنةً مع تنسيقات الملفات النقطية. كما تصف تنسيقات متجهات SVG هندسة الصورة (أي كيفية بنائها من الخطوط والمنحنيات والألوان وما إلى ذلك). على النقيض من ذلك، لا تحتوي التنسيقات النقطية إلا على معلوماتٍ حول نقاط الألوان، مما يتوجب على المتصفح تخمين كيفية ملء الفراغات (البكسلات الناقصة) عند عملية تحجيم الصورة. يُظهر الشكل التالي نسختين من نفس الصورة: صورة PNG على اليسار و SVG على اليمين. تبدو الصورة SVG رائعًة بأي حجم، بينما تزداد ضبابية الصورة PNG مع ازدياد عرض الشاشة. See the Pen Images SVG vs. PNG by Hsoub (@Hsoub) on CodePen. روابط البيانات توفّر روابط البيانات Data URIs طريقةً لتضمين ملف (ملف صورة مثلًا) سطريًا inline عن طريق ضبط سمة المصدر src للعنصر img باستخدام سلسلة نصية مُرمزة "Base64" ومع التنسيق التالي: <img src="data:image/svg+xml;base64,[data]"> مثلًا: تكون بداية الشيفرة للشعار HTML5 السابق على النحو التالي (طول الشيفرة الكلي أكثر من 5000 محرف): <img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiB BZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW ..."> توفِّر مثل الأداة المتاحة jpillora.com/base64-encoder إمكانية تحويل أي ملفٍ ثنائي، مثل الصور إلى روابط بيانات؛ حيث يكفي سحب ملف الصورة وإفلاته على الأداة. وعلى غرار الرسومات SVG، تُدعم روابط البيانات جيدًا من قِبل متصفحات الأجهزة المحمولة والحواسيب المكتبية. النمط السطري في CSS يُمكن وضع روابط البيانات والرسومات SVG بنمطٍ سطري inline في CSS، حيث تَدعم متصفحات الأجهزة المحمولة والحواسيب المكتبية هذا النمط. يُبين الشكل التالي صورتين (تبدوان متطابقتين) موضوعتين مثل صور خلفية في CSS الأولى باستخدام روابط بيانات والثانية باستخدام SVG. <span class="side-by-side" id="data_uri"></span> <span class="side-by-side" id="svg"></span> <style> .side-by-side { display: inline-block; margin: 0 20px 0 0; width: 45%; } span#data_uri { background: url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0D%0A%3C%21--%20Generator%3A%20Adobe%20Illustrator%2016.0.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%206.00%20Build%200%29%20%20--%3E%0D%0A%3C%21DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%0D%0A%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%0D%0A%09%20width%3D%22396.74px%22%20height%3D%22560px%22%20viewBox%3D%22281.63%200%20396.74%20560%22%20enable-background%3D%22new%20281.63%200%20396.74%20560%22%20xml%3Aspace%3D%22preserve%22%0D%0A%09%3E%0D%0A%3Cg%3E%0D%0A%09%3Cg%3E%0D%0A%09%09%3Cg%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23E44D26%22%20points%3D%22409.737%2C242.502%20414.276%2C293.362%20479.828%2C293.362%20480%2C293.362%20480%2C242.502%20479.828%2C242.502%20%09%09%09%0D%0A%09%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpath%20fill%3D%22%23E44D26%22%20d%3D%22M281.63%2C110.053l36.106%2C404.968L479.757%2C560l162.47-45.042l36.144-404.905H281.63z%20M611.283%2C489.176%0D%0A%09%09%09%09L480%2C525.572V474.03l-0.229%2C0.063L378.031%2C445.85l-6.958-77.985h22.98h26.879l3.536%2C39.612l55.315%2C14.937l0.046-0.013v-0.004%0D%0A%09%09%09%09L480%2C422.35v-79.32h-0.172H368.853l-12.207-136.871l-1.189-13.325h124.371H480v-49.668h162.17L611.283%2C489.176z%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23F16529%22%20points%3D%22480%2C192.833%20604.247%2C192.833%20603.059%2C206.159%20600.796%2C231.338%20599.8%2C242.502%20599.64%2C242.502%20%0D%0A%09%09%09%09480%2C242.502%20480%2C293.362%20581.896%2C293.362%20595.28%2C293.362%20594.068%2C306.699%20582.396%2C437.458%20581.649%2C445.85%20480%2C474.021%20%0D%0A%09%09%09%09480%2C474.03%20480%2C525.572%20611.283%2C489.176%20642.17%2C143.166%20480%2C143.166%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23F16529%22%20points%3D%22540.988%2C343.029%20480%2C343.029%20480%2C422.35%20535.224%2C407.445%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23EBEBEB%22%20points%3D%22414.276%2C293.362%20409.737%2C242.502%20479.828%2C242.502%20479.828%2C242.38%20479.828%2C223.682%20%0D%0A%09%09%09%09479.828%2C192.833%20355.457%2C192.833%20356.646%2C206.159%20368.853%2C343.029%20479.828%2C343.029%20479.828%2C293.362%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23EBEBEB%22%20points%3D%22479.828%2C474.069%20479.828%2C422.4%20479.782%2C422.413%20424.467%2C407.477%20420.931%2C367.864%20%0D%0A%09%09%09%09394.052%2C367.864%20371.072%2C367.864%20378.031%2C445.85%20479.771%2C474.094%20480%2C474.03%20480%2C474.021%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22343.784%2C50.229%20366.874%2C50.229%20366.874%2C75.517%20392.114%2C75.517%20392.114%2C0%20366.873%2C0%20366.873%2C24.938%20%0D%0A%09%09%09%09343.783%2C24.938%20343.783%2C0%20318.544%2C0%20318.544%2C75.517%20343.784%2C75.517%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22425.307%2C25.042%20425.307%2C75.517%20450.549%2C75.517%20450.549%2C25.042%20472.779%2C25.042%20472.779%2C0%20403.085%2C0%20%0D%0A%09%09%09%09403.085%2C25.042%20425.306%2C25.042%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22508.537%2C38.086%20525.914%2C64.937%20526.349%2C64.937%20543.714%2C38.086%20543.714%2C75.517%20568.851%2C75.517%20568.851%2C0%20%0D%0A%09%09%09%09542.522%2C0%20526.349%2C26.534%20510.159%2C0%20483.84%2C0%20483.84%2C75.517%20508.537%2C75.517%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20points%3D%22642.156%2C50.555%20606.66%2C50.555%20606.66%2C0%20581.412%2C0%20581.412%2C75.517%20642.156%2C75.517%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23FFFFFF%22%20points%3D%22480%2C474.021%20581.649%2C445.85%20582.396%2C437.458%20594.068%2C306.699%20595.28%2C293.362%20581.896%2C293.362%20%0D%0A%09%09%09%09480%2C293.362%20479.828%2C293.362%20479.828%2C343.029%20480%2C343.029%20540.988%2C343.029%20535.224%2C407.445%20480%2C422.35%20479.828%2C422.396%20%0D%0A%09%09%09%09479.828%2C422.4%20479.828%2C474.069%20%09%09%09%22%2F%3E%0D%0A%09%09%09%3Cpolygon%20fill%3D%22%23FFFFFF%22%20points%3D%22479.828%2C242.38%20479.828%2C242.502%20480%2C242.502%20599.64%2C242.502%20599.8%2C242.502%20600.796%2C231.338%20%0D%0A%09%09%09%09603.059%2C206.159%20604.247%2C192.833%20480%2C192.833%20479.828%2C192.833%20479.828%2C223.682%20%09%09%09%22%2F%3E%0D%0A%09%09%3C%2Fg%3E%0D%0A%09%3C%2Fg%3E%0D%0A%3C%2Fg%3E%0D%0A%3C%2Fsvg%3E%0D%0A) no-repeat; background-size: cover; height: 484px; } span#svg { background: url(data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' x='0px' y='0px' width='50%' height='560px' viewBox='281.63 0 396.74 560' enable-background='new 281.63 0 396.74 560' xml:space='preserve'><g><g><g><polygon fill='#E44D26' points='409.7,242.5 414.3,293.4 479.8,293.4 480,293.4 480,242.5 479.8,242.5'/><path fill='#E44D26' d='M281.63 110.053l36.106 404.968L479.757 560l162.47-45.042l36.144-404.905H281.63z M611.283 489.2 L480 525.572V474.03l-0.229 0.063L378.031 445.85l-6.958-77.985h22.98h26.879l3.536 39.612l55.315 14.937l0.046-0.013v-0.004 L480 422.35v-79.32h-0.172H368.853l-12.207-136.871l-1.189-13.325h124.371H480v-49.668h162.17L611.283 489.176z'/><polygon fill='#F16529' points='480,192.8 604.2,192.8 603.1,206.2 600.8,231.3 599.8,242.5 599.6,242.5 480,242.5 480,293.4 581.9,293.4 595.3,293.4 594.1,306.7 582.4,437.5 581.6,445.9 480,474 480,474 480,525.6 611.3,489.2 642.2,143.2 480,143.2'/><polygon fill='#F16529' points='541,343 480,343 480,422.4 535.2,407.4'/><polygon fill='#EBEBEB' points='414.3,293.4 409.7,242.5 479.8,242.5 479.8,242.4 479.8,223.7 479.8,192.8 355.5,192.8 356.6,206.2 368.9,343 479.8,343 479.8,293.4'/><polygon fill='#EBEBEB' points='479.8,474.1 479.8,422.4 479.8,422.4 424.5,407.5 420.9,367.9 394.1,367.9 371.1,367.9 378,445.9 479.8,474.1 480,474 480,474'/><polygon points='343.8,50.2 366.9,50.2 366.9,75.5 392.1,75.5 392.1,0 366.9,0 366.9,24.9 343.8,24.9 343.8,0 318.5,0 318.5,75.5 343.8,75.5'/><polygon points='425.3,25 425.3,75.5 450.5,75.5 450.5,25 472.8,25 472.8,0 403.1,0 403.1,25 425.3,25'/><polygon points='508.5,38.1 525.9,64.9 526.3,64.9 543.7,38.1 543.7,75.5 568.9,75.5 568.9,0 542.5,0 526.3,26.5 510.2,0 483.8,0 483.8,75.5 508.5,75.5'/><polygon points='642.2,50.6 606.7,50.6 606.7,0 581.4,0 581.4,75.5 642.2,75.5'/><polygon fill='#FFFFFF' points='480,474 581.6,445.9 582.4,437.5 594.1,306.7 595.3,293.4 581.9,293.4 480,293.4 479.8,293.4 479.8,343 480,343 541,343 535.2,407.4 480,422.4 479.8,422.4 479.8,422.4 479.8,474.1'/><polygon fill='#FFFFFF' points='479.8,242.4 479.8,242.5 480,242.5 599.6,242.5 599.8,242.5 600.8,231.3 603.1,206.2 604.2,192.8 480,192.8 479.8,192.8 479.8,223.7'/></g></g></g></svg>) no-repeat; background-size: cover; height: 484px; } </style> الناتج: الإيجابيات والسلبيات رغم طول الشيفرة للصور، لاسيما عند استخدام روابط البيانات، فإنها تؤدي للتقليل من طلبات HTTP؛ حيث يُمكن تحميل صفحةٍ تحتوي صورًا وأنماط CSS وسكريبت جافا مرةً واحدةً فقط. من أهم سلبيات هذه الطريقة: يُمكن أن يستغرق إظهار الصور مع روابط بيانات وقتًا أطول بكثير من الصور مع مصدر src خارجي على الهواتف المحمولة. يُمكن أن تزيد روابط البيانات من حجم صفحة HTML كثيرًا. يُمكن أن تزيد من تعقيد الشيفرة وتسلسل خطوات العمل في إنشاء الصفحة. زيادة حجم روابط البيانات بحوالي 30% عن حجم الملف الثنائي، وبالتالي لن تُخفف هذه الطريقة من حجم التنزيل الكلي. غير مدعومة أبدًا في IE6 و IE7، مع توفُّر دعمٍ جزئي في IE8. لا تعود مسألة تخفيض عدد الطلبات ملحة عند استخدام HTTP/2. نحتاج دومًا لاختبار ما يعمل على نحوٍ أفضل لتحقيق التجاوب الجيد. يُمكن استخدام أدوات المطور لقياس حجم الملف المُنزّل وعدد الطلبات ووقت الاستجابة الكلي. قد تكون روابط البيانات اختيارًا موفقًا للصور النقطية لصفحةٍ رئيسة تحتوي صورةً واحدةً أو اثنتين غير مستخدمتين في أماكن أخرى في الموقع؛ أما عند الحاجة لصورٍ سطرية متجهة، تكون رسومات SVG هي الخيار الأفضل. الصور في أنماط CSS تُعدّ خاصية الخلفية background في CSS أداةً مهمةً لإضافة صورٍ معقدة إلى العناصر؛ حيث أنها تُسهّل إضافة صورٍ متعددة وتكرارها وغير ذلك من الأمور؛ كما تزداد قوة هذه الخاصية عند دمجها مع استعلامات الوسائط، مما يتيح تحميل الصوره شرطيًا وفقًا لدقة الشاشة وحجم إطار العرض وغير ذلك من مواصفات الجهاز. يجب تغيير خاصية صورة الخلفية background-image في CSS لأجهزة العرض عالية الدقة، وذلك باستخدام استعلامات الوسائط مع الدقة الأدنى min-resolution و نسبة البكسلات الأدنى webkit-min-device-pixel-ratio-. يجب استخدام مجموعة المصادر srcset لتوفير صورٍ عالية الدقة إضافًة إلى الصورة 1x في الشيفرة. يجب التدقيق في التأثير على الأداء عند استخدام تقنيات استبدال الصور في سكريبت جافا، وعند توفير صورٍ مضغوطةٍ عالية الدقة لأجهزةٍ ذات دقة منخفضة. استخدام استعلامات الوسائط للتحميل الشرطي للصور أو للإدارة الفنية يُمكن استخدام استعلامات الوسائط لتغيير تخطيط الصفحة، كما يُمكن استخدامها أيضًا لتحميل الصور شرطيًا، أو لتوفير الإدارة الفنية وفقًا لعرض إطار العرض. يُظهر المثال التالي طلب تنزيل الملف small.png فقط ووضعه في محتوى الحاوية div على الشاشات الصغيرة؛ أما على الشاشات الأكبر، فيكون لخلفية جسم الصفحة صورة (background-image: url(body.png، وللحاوية صورةٌ أخرى (background-image: url(large.png. .example { height: 400px; background-image: url(small.png); background-repeat: no-repeat; background-size: contain; background-position-x: center; } @media (min-width: 500px) { body { background-image: url(body.png); } .example { background-image: url(large.png); } } يُمكن معاينة المثال السابق. استخدام image-set لتوفير صور عالية الدقة تُحسّن الدالة ()image-set من أداء خاصية الخلفية background عن طريق توفير مجموعةٍ متعدّدة من الصور وفقًا لمواصفات الجهاز المختلفة؛ مما يسمح للمتصفح باختيار أفضل صورة اعتمادًا على خصائص الجهاز، حيث يمكن مثلًا استخدام صورة 2x على جهاز 2x وصورة 1x على جهاز 2x عند محدودية حيز النطاق التراسلي للشبكة. background-image: image-set( url(icon1x.jpg) 1x, url(icon2x.jpg) 2x ); يقيس المتصفح الصورة المناسبة إضافًة إلى تنزيلها، حيث يفترض المتصفح أن حجم الصور 2x أكبر مرتين من الصور 1x، وبالتالي يُخفَّض حجم الصورة 2x بنسبة 2، بحيث تظهر الصورة بنفس الحجم على الصفحة. يجب توفير صورةٍ احتياطية لاستخدامها في حالة عدم توفر الدعم للدالة ()image-set، حيث ما زال دعم هذه الدالة جديدًا ومتوفرًا على كلٍ من Chrome و Safari فقط مع بادئة محرك المتصفح webkit-. ألقِ نظرةً على ما يلي على سبيل المثال: .sample { width: 128px; height: 128px; background-image: url(icon1x.png); background-image: -webkit-image-set( url(icon1x.png) 1x, url(icon2x.png) 2x ); background-image: image-set( url(icon1x.png) 1x, url(icon2x.png) 2x ); } يمكن معاينة المثال السابق. تطلب الشيفرة السابقة تحميل الصورة المناسبة على المتصفحات التي تدعم الدالة ()image-set؛ وإلا فتُستخدم الصورة 1x. وبهذا ستحصل المتصفحات التي لا تدعم الدالة على الصور 1x. استخدام استعلامات الوسائط لتوفير صور عالية الدقة أو الإدارة الفنية يُمكن لاستعلامات الوسائط إنشاء قواعدٍ بناءً على نسبة بكسلات الجهاز device pixel ratio، مما يُمكّن من توفير صورٍ مختلفة لشاشات 1x وشاشات 2x. @media (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) { /* الأنماط عالية الكثافة والمصادر هنا */ } تدعم المتصفحات Chrome و Firefox و Opera معيار الدقة الأدنى (min-resolution: 2dppx)؛ بينما يتطلب كلٌ من متصفحي Safari و Android كتابة القيمة بدون الوحدة dppx. يجب الانتباه إلى حدوث تحميل هذه الأنماط فقط عند مطابقة الجهاز لاستعلام الوسائط، وبالتالي يجب تحديد هذه الأنماط من أجل الحالة الأساسية، وهذا يضمن عرض شيءٍ ما إذا كان المتصفح لا يدعم استعلامات الوسائط الخاصة بالدقة. .sample { width: 128px; height: 128px; background-image: url(icon1x.png); } @media (min-resolution: 2dppx), /* Standard syntax */ (-webkit-min-device-pixel-ratio: 2) /* Safari & Android Browser */ { .sample { background-size: contain; background-image: url(icon2x.png); } } يمكن معاينة المثال السابق. ويُمكن أيضًا استخدام خاصية العرض الأدنى min-width لإظهار صورٍ بديلة اعتمادًا على حجم إطار العرض؛ حيث تتمتع هذه التقنية بميزة عدم تنزيل الصورة في حال عدم تحقق استعلام الوسائط. على سبيل المثال: تُنزّل الصورة bg.png وتوضع في الجسم body، إذا كان عرض المتصفح أكبر أو يساوي 500px فقط: @media (min-width: 500px) { body { background-image: url(bg.png); } } استخدام رسومات SVG للأيقونات تُستخدم الرسومات المتجهة SVG لإضافة الأيقونات للصفحة عندما يكون ذلك مُمكنًا، أو المحارف unicode في بعض الحالات. استبدال الأيقونات البسيطة بـالمحارف unicode يدعم الكثير من الخطوط المحارف الرسومية unicode، والتي يُمكن استخدامها عوضًا عن الصور لا سيما وأنها على خلاف الصور تظهر جيدًا مهما كان حجمها. تتضمن المحارف الرسومية إضافًة إلى المحارف العادية، رموز الأسهم (←) والمعاملات الرياضية (√) والأشكال الهندسية (★) وصور التحكم (▶) والعلامات الموسيقية (♬) والأحرف اليونانية (Ω) وحتى قطع الشطرنج ( ♞). تُضمّن هذه المحارف بنفس طريقة تدوين الكائنات على النحو التالي: XXXX&#؛ حيث يُمثّل XXXX رقم محرف unicode. ألقِ نظرةً على المثال التالي: You're a super ★ والذي يُظهِر: You're a super ★ استبدال الأيقونات المعقدة برسومات SVG يُمكن استخدام رسومات SVG للأيقونات الأكثر تعقيدًا؛ نظرًا لأن هذه الرسومات خفيفة وسهلة الاستخدام عمومًا، كما يُمكن تصميمها باستخدام أنماط CSS. وتتمتع بالمزايا التالية موزانةً مع الصور النقطية: يُمكن تحجيم الرسومات المتجهة بلا حدود. يُمكن استخدام تأثيرات CSS مثل اللون والتظليل والشفافية والتحريك مباشرةً. يُمكن تضمين هذه الرسومات سطريًا inline. توفر دلالة واضحة. توفر إمكانية وصول أفضل مع استخدام السمات المناسبة. With SVG icons, you can either add icons using inline SVG, like this checkmark: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32"> <path d="M27 4l-15 15-7-7-5 5 12 12 20-20z" fill="#000000"></path> </svg> or by using an image tag, like this credit card icon: <img src="credit.svg">. يُمكن معاينة المثال السابق. إرشادات استخدام الخطوط للأيقونات يشيع استخدام الخطوط للأيقونات لسهولة استخدامها، إلا أن لها بعض العيوب موزانةً مع أيقونات رسومات SVG: تُنشَأ باستخدام رسوميات مُتجهة، مما يُمكّن من تحجيمها بلا حدود؛ ولكن يُمكن أن تكون غير مصقولة، مما يُعطي أحيانًا أيقونات غير دقيقة كما هو متوقع منها أن تكون. لا توفِّر دعمًا كاملًا لأنماط CSS. يُمكن أن يكون تحقيق التوضع المثالي للبيكسل أمرًا صعبًا اعتمادًا على ارتفاع الخط وتباعد المحارف وغير ذلك. لا توفر الدلالة semantic، مما يجعل من الصعب استخدامها مع قارئات الشاشة أو التقنيات المساعدة الأخرى. يُمكن أن ينتج عن استخدام مجموعةٍ فرعيةٍ صغيرةٍ فقط منها حجم ملفٍ كبير ما لم يُحدّد نطاقها صحيحًا. يُبين الشكل التالي مثالًا لصفحة تستخدم الخطوط FontAwesome: With Font Awesome, you can either add icons by using a unicode entity, like this HTML5 logo (<span class="awesome"></span>) or by adding special classes to an <i> element like the CSS3 logo (<i class="fa fa-css3"></i>). يُمكن معاينة المثال السابق. تتوفر المئات من خطوط الأيقونات المجانية والمدفوعة بما في ذلك Font Awesome و Pictos و Glyphicons. يجب التأكد من التوازن بين طلبات HTTP الإضافية وحجم الملف حين الحاجة للأيقونات؛ حيث يُفضل استخدام صورةٍ، أو مجموعة صور مُضمّنة في صورةٍ واحدة image sprite في حال الحاجة لعددٍ قليل من الأيقونات. تحسين الصور لتحقيق الأداء الأمثل تُشكّل الصور غالبًا العدد الأكبر من البايتات المُنزّلة كما أنها تشغل قسمًا كبيرًا من المساحة المرئية على الصفحة. وبالنتيجة، يؤدي تحسين الصور إلى تخفيض عدد البايتات اللازم وبالتالي تحسين أداء الموقع؛ فكلما انخفض عدد البايتات الواجب تنزيلها، انخفض التنافس على حجز حيّز النطاق التراسلي، وزادت سرعة التحميل والعرض. يجب عدم اختيار تنسيق الصورة عشوائيًا، بل يجب فهم التنسيقات المختلفة المتاحة واستخدام التنسيق الأنسب. يجب تضمين أدوات تحسين الصور وضغطها في سير العمل على الموقع لتخفيض حجم الملفات. يُمكن تقليل عدد طلبات http عن طريق وضع الصور المُستخدمة على نحوٍ متكرر في حاوية صور image sprites. يُمكن تحسين زمن تحميل الصفحة الأولى والتخفيف من وزنها بتحميل الصور فقط عند الوصول إليها. اختيار التنسيق الصحيح يجب الانتباه لنوعين من الصور، وهما: الصور المتجهة و الصور النقطية. ونحتاج اختيار تنسيق الضغط المناسب بالنسبة للصور النقطية، مثل GIF و PNG و JPG. الصور النقطية: مثل الصور الفوتوغرافية وغيرها، والتي تُمثّل بشبكةٍ من نقاط الألوان (البكسلات). تُنتج الكاميرات والماسحات الضوئية الصور النقطية عادًة، كما يُمكن إنتاجها باستخدام عناصر الحاويات canavas في HTML؛ وكلما زاد حجم الصورة، زاد حجم الملف أيضًا. عندما يتغير حجم الصورة إلى حجمٍ أكبر من حجمها الأصلي، تُصبح الصور النقطية ضبابية، لأن المتصفح يحتاج إلى تخمين كيفية ملء البكسلات الناقصة. الصور المُتجهة: تُعرّف هذه الصور باستخدام مجموعةٍ من المنحنيات والخطوط والأشكال وألوان التعبئة والتدرجات اللونية، مثل الشعارات logo والرسومات الخطية، ويُمكن إنشاؤها باستخدام برامجٍ متخصصة، مثل Adobe Illustrator أو Inkscape؛ وتُحفَظ بتنسيقٍ متجه، مثل SVG. نظرًا لأن الصور المتجهة مبنية على عناصر أولية بسيطة، يُمكن تحجيمها دون أي خسارةٍ في الجودة، أو تغييرٍ في حجم الملف. من المهم الانتباه لمنشأ الصورة (نقطية أو متجهة) والمحتوى (الألوان، التحريك، النص،..) عند اختيار التنسيق المناسب. لا يوجد تنسيقٌ واحدٌ يُناسب جميع أنواع الصور؛ إذ لكل تنسيق نقاط قوة وضعف. من الإرشادات الأساسية لاختيار التنسيق المناسب: استخدام JPG للصور الفوتوغرافية. استخدام الرسوميات SVG للرسومات المتجهة والرسومات ذات الألوان الصلبة مثل الأيقونات والخطوط الفنية؛ وفي حال كان الرسم المتجه غير متاح، يُمكن تجربة التنسيقات WebP، أوPNG. استخدام PNG عوضًا عن GIF، لأنها تتيح المزيد من الألوان وتوفر نسب ضغط أفضل. استخدام عنصر الفيديو <video> للحصول على زمن تحريك أطول، والذي يوفر أيضًا نوعية صور أفضل، إضافًة لتحكُّم المستخدم في تشغيل العرض. تخفيض حجم الملف يُمكن تخفيض حجم ملف الصورة إلى حدٍ كبير عن طريق "المعالجة اللاحقة" للصور بعد حفظها. يتوفر العديد من الأدوات المتاحة لضغط الصور مع ضياع بعض البيانات أو بدون ضياع؛ ومنها متاحٌ على الويب؛ ومنها على هيئة برامج ذات واجهات رسومية أو سطور أوامر. من الأفضل تضمين عمليات تحسين الصور على نحوٍ مؤتمت ضمن سير العمل في بناء الموقع. تتوفر العديد من الأدوات ذات الأداء العالي والتي تضغط الصور دون ضياعٍ لبيانات الملفات JPG و PNG، وبدون أي تأثير على جودة الصورة. يُمكن استخدام الأدوات jpegtran أو jpegoptim (متوفر على لينكس Linux فقط؛ ويجب تشغيله مع خيار إزالة الكل strip-all--) للصور JPG؛ بينما يُمكن استخدام OptiPNG أو PNGOUT للصور PNG. استخدام تتابع الصور تسمح تقنية التتابع CSS spriting بدمج مجموعةٍ من الصور في "صورةٍ واحدة sprite sheet". يُمكن بعد ذلك انتقاء صورةٍ منها للعرض عن طريق تحديد الصورة الخلفية لعنصر sprite sheet مع تحديد الإزاحة المناسبة لعرض الجزء المطلوب. .sprite-sheet { background-image: url(sprite-sheet.png); width: 40px; height: 25px; } .google-logo { width: 125px; height: 45px; background-position: -190px -170px; } .gmail { background-position: -150px -210px; } .maps { height: 40px; background-position: -120px -165px; } يُمكن معاينة المثال السابق. يُخفّض التتابع من عدد التنزيلات المطلوبة للحصول على صور متعدّدة مع السماح بالتخزين المؤقت لها. استخدام التحميل الكسول يُمكن أن يؤدي استخدام التحميل الكسول إلى تسريعٍ كبير لتحميل الصفحات الطويلة، التي تتضمن العديد من الصور الموجودة أسفل الجزء المرئي من الصفحة، عن طريق تحميلها؛ إما عند الحاجة لعرضها؛ أو عند انتهاء تحميل المحتوى الأساسي وعرضه. يُمكن أن يؤدي استخدام التحميل الكسول إلى إنشاء تجارب تمرير لا نهائية إضافًة لتحسين الأداء. يجب توخي الحذر عند إنشاء صفحات تمرير لا نهائية، لأن المحتوى يُحمّل عندما يُصبح مرئيًا فقط مما يجعل محركات البحث غير قادرةٍ على رؤية هذا المحتوى إطلاقًا. علاوًة على ذلك، فإن المستخدمين الذين يبحثون عن المعلومات التي يتوقعون رؤيتها في التذييل لا يرونه (أي التذييل) أبدًا نظرًا تحميل المحتوى الجديد دائمًا. تجنب الصور نهائيا يُمكن في بعض الحالات أن تكون الصورة الأفضل ليست صورةً على الإطلاق. يجب استخدام الإمكانات الأصلية للمتصفح لتوفير الوظائف نفسها أو وظائف مشابهة. تنشئ المستعرضات اليوم عناصرًا مرئية كانت تتطلب صورًا سابقًا؛ مما يعني أن المتصفحات لم تعد بحاجةٍ إلى تنزيل ملفات صور منفصلة، وبالتالي تتجنب حجم الصور غير الملائم. يُمكن استخدام خطوط يونيكود unicode أو خطوط الأيقونات الخاصة لعرض الأيقونات. وضع النص في الشيفرة عوضا عن تضمينه في الصور يجب أن يكون النص نصًا وليس مُضمّنًا في الصور كلما كان ذلك مُمكنًا؛ حيث يؤدي استخدام الصور للعناوين الرئيسية أو وضع معلومات الاتصال، مثل أرقام الهواتف أو العناوين في الصور إلى منع المستخدمين من نسخ المعلومات ولصقها؛ كما أن ذلك يجعل المعلومات غير متاحة لبرامج قراءة الشاشة وغير متجاوبة. عوضًا عن ذلك، يُمكن وضع النص في الشيفرة واستخدام خطوط الويب المتاحة لتحقيق النمط المطلوب. استخدام أنماط CSS لاستبدال الصور يُمكن للمتصفحات الحديثة استخدام خصائص CSS لإنشاء أنماط كانت تتطلب صورًا سابقًا. يُمكن مثلًا إنشاء التدرجات اللونية المعقدة باستخدام خاصية الخلفية background؛ ويُمكن إنشاء الظلال باستخدام صندوق الظلال box-shadow؛ كما يُمكن إضافة الزوايا المستديرة باستخدام خاصية نصف قطر الحدود border-radius. <style> div#noImage { color: white; border-radius: 5px; box-shadow: 5px 5px 4px 0 rgba(9,130,154,0.2); background: linear-gradient(rgba(9, 130, 154, 1), rgba(9, 130, 154, 0.5)); } </style> يجب الانتباه إلى أن استخدام هذه التقنيات يتطلب عدة دورات للإظهار؛ مما يُعدّ أمرًا مرهقًا على الهواتف المحمولة. سيُفقِد الإفراط في الاستخدام أي فائدةٍ مكتسبة، إضافًة إلى إعاقة الأداء. ترجمة -وبتصرف- للمقالة Images للمؤلف: Pete LePage. اقرأ أيضًا أساسيات تصميم الويب المتجاوب ما هو الفرق بين التصميم المتجاوب (Responsive Web Design) والتصميم المتلائم (Adaptive Web Design)
-
تتطور نماذج تصميم الويب المتجاوب بصورةٍ متسارعة، ولكن يعمل عددٌ قليلٌ منها فقط جيدًا على الحواسيب المكتبية وعلى الأجهزة المحمولة معًا. يُمكن تصنيف معظم التخطيطات المُستخدمة في صفحات الويب المتجاوب إلى خمس فئات: المُنساب عمومًا mostly fluid؛ وإفلات العمود column drop؛ والتخطيط المُزاح layout shifter؛ والتعديلات الطفيفة tiny tweaks؛ وخارج اللوحة off canvas. مع الإشارة إلى أنه يُمكن للصفحة استخدام أكثر من نموذج معًا، مثل استخدام "إفلات العمود" مع "خارج اللوحة". تُشكّل هذه الفئات، والتي عرّفها أولًا لوك روبلسكي Luke Wroblewski)، نقطة انطلاقٍ أساسية لأي صفحةٍ متجاوبة. كُتبت جميع الأمثلة التالية بلغةٍ ترميزية باستخدام الصندوق المرن flexbox بهدف التبسيط وسهولة الفهم، وذلك مع حاويةٍ رئيسة div تضم ثلاث أو خمس حاويات div ثانوية، وبدءًا من العرض الأصغر، ومن ثم أُضيفت نقاطٌ حدّية عند الضرورة. تدعم المتصفحات الحديثة نمط تخطيط الصندوق المرن إلا أنه ما زال يتطلب بعض التعديلات من قبل المصنعين وصولًا للدعم الأمثل له. النموذج المنساب عموما Mostly Fluid يتكون النموذج المُنساب عمومًا من شبكةٍ انسيابية بصورةٍ أساسية؛ حيث تُحافظ هذه الشبكة على حجمها على الشاشات المتوسطة والكبيرة مع ضبط الهوامش على الشاشات الأوسع؛ بينما تتسبب بإعادة تدفق المحتوى الرئيسي مع تكديس الأعمدة عموديًا على الشاشات الصغيرة. من الميزات الأساسية لهذا النموذج عدم الحاجة إلا لنقطةٍ حدّيةٍ واحدة بين الشاشات الصغيرة والشاشات الكبيرة كما يُبين المثال التالي: تُكدَّس كل حاوية div عموديًا في العرض الأصغر؛ وعندما يتجاوز عرض الشاشة 600px، تُحافظ الحاوية div الأولى على العرض width: 100%؛ بينما تظهر الحاويات الأربع div الثانوية مثل عمودين أسفل الحاوية الأولى. عندما يتجاوز عرض الشاشة 800px، يُصبح عرض الحاوية الأساسية div ثابتًا مع توسيطها على الشاشة. من المواقع التي تستخدم هذا النموذج: A List Apart. Media Queries. SimpleBits. .container { display: -webkit-flex; display: flex; -webkit-flex-flow: row wrap; flex-flow: row wrap; } .c1, .c2, .c3, .c4, .c5 { width: 100%; } @media (min-width: 600px) { .c2, .c3, .c4, .c5 { width: 50%; } } @media (min-width: 800px) { .c1 { width: 60%; } .c2 { width: 40%; } /*لا يعمل استخدام 33.33 دومًا بسبب التقريب*/ .c3, .c4 { width: 33%; } .c5 { width: 34%; } } @media (min-width: 800px) { .container { width: 800px; margin-left: auto; margin-right: auto; } } نموذج إفلات العمود Column drop يكدِّس هذا النموذج الأعمدة عموديًا، عندما يُصبح عرض النافذة ضيقًا في التخطيطات متعدّدة الأعمدة والمُمتدة عرضًا على كامل الشاشة. ويُمكن أن يؤدي هذا إلى تكديس جميع الأعمدة عموديًا؛ لذلك يعتمد اختيار النقاط الحدّية لهذا النموذج على المحتوى وعلى تفاصيل التصميم. يُبين المثال التالي استخدام هذا النموذج: وكما الحال في النموذج المُنساب عمومًا، يُكدّس المحتوى في العرض الأصغر؛ إلا أنه عندما يتجاوز عرض الشاشة 600px، تأخذ الحاوية الأولى والثانية العرض الكامل للشاشة؛ أما عند تجاوز 800px، تأخذ جميع الحاويات الثلاث كامل عرض الشاشة. تُحدّد خاصية الترتيب order في أنماط CSS ترتيب الحاويات. من المواقع التي تستخدم هذا النموذج: Modernizr. .container { display: -webkit-flex; display: flex; -webkit-flex-flow: row wrap; flex-flow: row wrap; } .c1, .c2, .c3 { width: 100%; } @media (min-width: 600px) { .c1 { width: 60%; -webkit-order: 2; order: 2; } .c2 { width: 40%; -webkit-order: 1; order: 1; } .c3 { width: 100%; -webkit-order: 3; order: 3; } } @media (min-width: 800px) { .c2 { width: 20%; } .c3 { width: 20%; } } نموذج التخطيط المزاح Layout shifter يُعدّ هذا النموذج أكثر النماذج استجابةً مع عدّة نقاطٍ حدّية تُحدّد حسب عرض الشاشة؛ حيث يكمن الفرق الجوهري في هذا النموذج بطريقة تحريك المحتوى عوضًا عن إعادة تدفق المحتوى وإفلات الأعمدة أسفل بعضها بعضًا. يتطلب هذا النموذج تحديد مجموعةٍ من النقاط الحدّية، مما يُصعّب عمليات التعديل اللاحقة؛ إذ قد تتطلب كل نقطةٍ حدّية إجراء تغييرات على العناصر وليس على تخطيط المحتوى العام فقط. يُبيّن المثال التالي استخدام هذا النموذج: حيث يُكدَّس المحتوى عموديًا في الشاشات الأصغر، إلا أنه يتغير جذريًا على الشاشات الأكبر؛ إذ تُوضع حاوية div على اليسار وتُكدَّس حاويتان على يمينها. من المواقع التي تستخدم هذا النموذج: Andersson-Wise Architects. .container { display: -webkit-flex; display: flex; -webkit-flex-flow: row wrap; flex-flow: row wrap; } .c1, .c2, .c3, .c4 { width: 100%; } @media (min-width: 600px) { .c1 { width: 25%; } .c4 { width: 75%; } } @media (min-width: 800px) { .container { width: 800px; margin-left: auto; margin-right: auto; } } نموذج التعديلات الطفيفة Tiny tweaks يُجري هذا النموذج بعض التعديلات الطفيفة على التخطيط، مثل تعديل حجم الخط، أو تغيير حجوم الصور، أو تحريك المحتوى بطرقٍ بسيطةٍ جدًا. يُناسب هذا النموذج تخطيطات العمود الواحد، مثل مواقع الصفحة الخطية الواحدة والمقالات ذات النص الكبير. يُبين المثال التالي استخدام هذا النموذج: عمليًا، وكما يوحي اسم هذا النموذج، لا يتغير الكثير مع تغير حجم الشاشة؛ فكلما زاد عرض الشاشة، كبُر حجم الخط وزادت مساحة الحشوة padding. من المواقع التي تستخدم هذا النموذج: Ginger Whale. Future Friendly. .c1 { padding: 10px; width: 100%; } @media (min-width: 500px) { .c1 { padding: 20px; font-size: 1.5em; } } @media (min-width: 800px) { .c1 { padding: 40px; font-size: 2em; } } نموذج خارج اللوحة Off canvas عوضًا عن تكديس المحتوى عموديًا، يضع هذا النموذج المحتوى الأقل استخدامًا، مثل قوائم التنقل أو قوائم التطبيق خارج الشاشة، ويظهر هذا المحتوى عندما يصبح حجم الشاشة كبيرًا بدرجةٍ كافية فقط. أما على الشاشات الأصغر، فيجب النقر لإظهار هذا المحتوى المخفي. يُبين المثال التالي استخدام هذا النموذج: عوضًا عن تكديس المحتوى عموديًا، يَستخدم هذا المثال سمة التحويل لإخفاء حاويتين بوضعهما خارج الشاشة: 'transform: translate(-250px, 0)' تُستخدم JavaScript لإظهار الحاويات عن طريق إضافة الصف class المُسمى open إلى العنصر لجعله مرئيًا. ومع اتساع عرض الشاشة، تُزال مواضع العناصر خارج الشاشة فتعود هذه العناصر لتظهر ضمن إطار العرض المرئي. بما أن Safari for iOS 6 و Android Browser لا يدعمان flex-flow: row nowrap من flexbox، استُخدم التوضُّع المُطلق في هذا المثال. من المواقع التي تستخدم هذا النموذج: HTML5Rocks Articles. Google Nexus. Facebook's Mobile Site. body { overflow-x: hidden; } .container { display: block; } .c1, .c3 { position: absolute; width: 250px; height: 100%; /* حيلة لتحسين الأداء على المتصفح كروم See: http://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/ #perfmatters */ -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transition: -webkit-transform 0.4s ease-out; transition: transform 0.4s ease-out; z-index: 1; } .c1 { /* حيلة لتحسين الأداء على المتصفحات القديمة من كروم Using translate3d as a trick to improve performance on older versions of Chrome See: http://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/ #perfmatters */ -webkit-transform: translate(-250px,0); transform: translate(-250px,0); } .c2 { width: 100%; position: absolute; } .c3 { left: 100%; } .c1.open { -webkit-transform: translate(0,0); transform: translate(0,0); } .c3.open { -webkit-transform: translate(-250px,0); transform: translate(-250px,0); } @media (min-width: 500px) { /* استخدام الصندوق المرن إذا كان عرض الشاشة أكبر من 500 بكسل */ .container { display: -webkit-flex; display: flex; -webkit-flex-flow: row nowrap; flex-flow: row nowrap; } .c1 { position: relative; -webkit-transition: none 0s ease-out; transition: none 0s ease-out; -webkit-transform: translate(0,0); transform: translate(0,0); } .c2 { position: static; } } @media (min-width: 800px) { body { overflow-x: auto; } .c3 { position: relative; left: auto; -webkit-transition: none 0s ease-out; transition: none 0s ease-out; -webkit-transform: translate(0,0); transform: translate(0,0); } } ترجمة -وبتصرف- للمقالة Responsive Web Design Patterns للمؤلف: Pete LePage. اقرأ أيضًا أساسيات تصميم الويب المتجاوب ما هو الفرق بين التصميم المتجاوب (Responsive Web Design) والتصميم المتلائم (Adaptive Web Design) الدليل الشامل لشرح النقاط الحدية لصفحات الويب المتجاوبة
-
تعرض هذه المقالة أساسيات إنشاء صفحات ويب متجاوبة مع احتياجات المستخدمين وقدرات الجهاز الذي تُعرض عليه. يتزايد استخدام الأجهزة المحمولة لتصفُّح الويب كثيرًا يومًا بعد يوم، مما يتطلب استخدام طرق عرضٍ مناسبة لصفحات الويب على شاشات هذه الأجهزة المتميزة بصغر حجمها نسبيًا. يُلبّي تصميم الويب المتجاوب احتياجات المستخدمين ويتكيف مع قدرات أجهزتهم؛ وقد وضع إيثان ماركوت Ethan Marcotte أساسياته في مقالته في موقع alistapart؛ وهو موقعٌ يُعنى بقضايا تصميم الويب. يتغير تخطيط صفحة الويب في تصميم الويب المتجاوب وفق حجم الجهاز وقدراته؛ حيث يمكن مثلًا عرض محتوًى ما ضمن عمودٍ واحدٍ فقط على جهازٍ محمول؛ بينما يُعرض نفس المحتوى ضمن عمودين على جهاز لوحي أكبر. من المهم جدًا أن تتكيف صفحات الويب مع مختلف حجوم الشاشات، والتي تتغير بصورةٍ مستمرة وفق أنواع الأجهزة المختلفة، مثل الهواتف والأجهزة اللوحية والحواسيب ووحدات التحكم في الألعاب وأجهزة التلفاز والأجهزة القابلة للارتداء. علاوًة على ذلك، يُمكن أن تختلف طرق التفاعل مع الأجهزة، كأن تكون عن طريق اللمس في البعض منها مثلًا. وبالنتيجة، يجب أن يأخذ التصميم الحديث المتجاوب كل هذه الأمور في الحسبان لتحسين تجربة الاستخدام للجميع. إعداد إطار العرض يجب أن تتضمن الصفحات المُعدّة على نحوٍ مثالي لطيفٍ متنوعٍٍ من الأجهزة وسمًا وصفيًا meta لإطار العرض viewport؛ حيث يُحدّد هذا الوسم للمتصفح كيفية تحجيم الصفحة واختيار أبعادها. تعرض متصفحات الجوال الصفحة بعرض شاشة حاسوب مكتبي (حوالي 980 بكسل عادًة، كما يُمكن أن تختلف حسب الجهاز)، وذلك بهدف تقديم أفضل تجربة استخدام، ثم تحاول تحسين مظهر المحتوى عن طريق زيادة حجم الخطوط وتحجيم المحتوى ليُناسب أبعاد شاشة العرض، مما يجعل الخطوط تبدو للمستخدمين غير متناسبة مع حجم الشاشة. وبالتالي، سيُضطر المستخدمون للنقر المزدوج أو القرص للتكبير pinch-to-zoom، للتمكُّن من معاينة المحتوى والتفاعل معه براحة. <!DOCTYPE html> <html lang="en"> <head> … <meta name="viewport" content="width=device-width, initial-scale=1"> … </head> … يؤدي إسناد القيمة width=device-width في وسم إطار العرض viewport إلى توجيه الصفحة لإظهار المحتوى على كامل عرض الشاشة وذلك باستخدام وحدة البكسلات المُستقلة عن الجهاز device-independent pixels؛ وهي وحدة قياس طول تُحوّل إلى عددٍ من البكسلات الفيزيائية حسب كثافة البكسلات على الجهاز، فكلما ارتفعت الكثافة زادت البكسلات الفيزيائية الموافقة لبكسل مستقل، وهذا يسمح للصفحة بإظهار المحتوى بما يتناسب مع مختلف حجوم الشاشات، بدءًا من الهواتف الصغيرة المحمولة، وانتهاءً بشاشات الحواسيب المكتبية الكبيرة. يعرض المثال التالي إظهار صفحةٍ في جهاز دون استخدام الوسم الوصفي لإطار العرض. أما مع استخدام الوسم الوصفي لإطار العرض، فسيكون الإظهار: تُحافظ بعض المتصفحات على عرض الصفحة عند التدوير إلى الوضع الأفقي وعند تصغير أو تكبير الصفحة عوضًا عن إعادة التدفق لملء كامل الشاشة. يؤدي ضبط سمة الحجم الابتدائي initial-scale = 1 إلى توجيه المستعرضات لإنشاء علاقة 1:1 بين وحدات بكسل أنماط CSS ووحدات البكسل المستقلة عن الجهاز وذلك بغض النظر عن اتجاه الجهاز؛ مما يسمح للصفحة بالاستفادة من العرض الأفقي كاملًا. التأكد من إمكانية الوصول لإطار العرض تتحقق أداة التدقيق Lighthouse من وجود الوسم الوصفي لإطار العرض viewport؛ وفي حال عدم وجوده تُظهر التنبيه الموافق "لا تتوفر السمة الوصفية لإطار العرض مع تحديد العرض أو الحجم الابتدائي" Does not have a <meta name="viewport"> tag with width or initial-scale، وهذا يُساعد في التحقق من استخدام مستندات HTML لهذا الوسم على نحوٍ صحيح. يُمكن ضبط السمات التالية لإطار العرض، إضافًة إلى ضبط سمة الحجم الابتدائي initial-scale: الحجم الأدنى minimum-scale. الحجم الأقصى maximum-scale. الحجم القابل للتخصيص من قبل المستخدم user-scalable. لا نوصي بضبط هذه السمات، إذ قد يؤدي ذلك إلى تعطيل إمكانية تكبير أو تصغير إطار العرض مما يحدّ من إمكانيات الوصول. تحجيم المحتوى وفق إطار العرض اعتاد المستخدمون على التنقل عموديًا في صفحات الويب، ويؤدي إرغام المستخدم على التمرير أفقيًا أو التصغير لمعاينة الصفحة بأكملها إلى تجربة استخدام سيئة. يُمكن أحيانًا، عن طريق الخطأ، إنشاء محتوى صفحة على الجوال لا يُناسب إطار العرض المُحدّد وذلك على الرغم من استخدام وسم إطار العرض؛ حيث يُمكن مثلًا أن تتسبب صورةٌ بضرورة التمرير الأفقي إذ كان عرضها أكبر من عرض إطار العرض، وبالتالي يجب ضبط المحتوى ليُناسب عرض إطار العرض وبحيث لا يُضطر المستخدم إلى التمرير الأفقي. تتحقق أداة التدقيق Lighthouse من عدم تمدُّد المحتوى خارج إطار العرض؛ وفي حال حدوث ذلك، تُظهر التنبيه الموافق "لم يُضبط حجم المحتوى صحيحًا بما يُناسب إطار العرض" Content is not sized correctly for the viewport. الصور تتسبب الصور ذات الأبعاد الثابتة والتي تكون أكبر من إطار العرض بظهور أشرطة التمرير. ومن الطرق الشائعة لتجاوز هذه المشكلة، هي إعطاء جميع الصور عرضًا أقصى max-width بنسبة 100%؛ مما يؤدي إلى تقليص حجم الصورة لتُناسب المساحة إذا كان حجم إطار العرض أصغر من حجم الصورة. وفي جميع الأحوال، لن يزداد حجم الصورة أكبر من حجمها الطبيعي مع استخدام max-width وليس width بنسبة 100%. من المستحسن عمومًا إضافة ما يلي إلى ملف الأنماط CSS منعًا من ظهور أشرطة التمرير مع الصور العريضة: img { max-width: 100%; display: block; } إضافة أبعاد الصورة إلى العنصر img يؤدي استخدام max-width: 100% إلى تعديل override أبعاد الصورة الأصلية. ومع ذلك، يجب الاستمرار في استخدام سمة العرض width والإرتفاع height لوسم الصورة <img>؛ نظرًا لاستخدام المتصفحات الحديثة هذه الأبعاد لحجز مساحة الصورة قبل تحميلها؛ مما يُساعد على تجنُّب الإزاحات في التخطيط layout shifts عند تحميل المحتوى. التخطيط نظرًا لاختلاف أبعاد الشاشة وعرضها المُحدّد بالبكسل في أنماط CSS كثيرًا بين الأجهزة (مثلًا، بين الهواتف والأجهزة اللوحية، وحتى بين الهواتف المختلفة)، يجب ألّا يعتمد المحتوى على عرض إطار عرضٍ معيّن لإظهار المحتوى جيدًا. تطلّب ذلك سابقًا ضبط العناصر المُستخدمة لإنشاء التخطيط باستخدام النسب المئوية. يُبين المثال التالي تخطيط عمودين مع عناصرٍ عائمة باستخدام البكسل لتحديد الحجوم. يتعيّن على المستخدم استخدام شريط التمرير الأفقي لرؤية المحتوى عندما يُصبح عرض إطار العرض أصغر من مجموع عرضي العمودين: بينما تبقى الأعمدة دائمًا نسبًا مئوية معينة من الحاوية عند استخدام النسب المئوية للعرض؛ مما يعني أن الأعمدة ستُصبح أضيق عوضًا عن ظهور أشرطة التمرير، كما يُبين المثال التالي: يسمح استخدام بعض تقنيات التخطيط الحديثة إنشاء هذه الشبكات المرنة بسهولةٍ كبيرة، مثل تقنية الصندوق المرن Flexbox والتخطيط الشبكي Grid Layout والتخطيط متعدد الأعمدة Multicol. التخطيط باستخدام الصندوق المرن Flexbox تُعدّ هذه الطريقة طريقة التخطيط المثالية عند وجود مجموعةٍ من العناصر ذات الحجوم المختلفة والمطلوب وضعها في صفٍ واحد أو عدة صفوف، مع احتلال العناصر الأصغر مساحةً أقل والأخرى الأكبر مساحةً أكثر. .items { display: flex; justify-content: space-between; } يُمكن استخدام طريقة التخطيط Flexbox لعرض العناصر في صفٍ واحد أو في صفوفٍ متعددة مع تقليص المساحة المتاحة، كما يُبين المثال التالي: التخطيط الشبكي باستخدام أنماط CSS يسمح استخدام التخطيط الشبكي في أنماط CSS بإنشاء الشبكات المرنة مباشرةً؛ حيث يُمكن مثلًا إعادة إنشاء المثال السابق مع العناصر العائمة باستخدام التخطيط الشبكي والوحدة fr، التي تُمثّل جزءًا من المساحة المتاحة في الحاوية، عوضًا عن النسب المئوية كما يلي: .container { display: grid; grid-template-columns: 1fr 3fr; } يُمكن أيضًا استخدام التخطيط الشبكي لإنشاء تخطيط شبكةٍ منتظمةٍ مع أي عددٍ من العناصر التي تُناسبها؛ حيث ينخفض عدد المسارات (الأعمدة) مع تقليص حجم الشاشة. يُبين المثال التالي توضُّع العدد المناسب من البطاقات في كل سطر مع حجم ٍأدنى 200px: التخطيط متعدد الأعمدة Multicol يُمكن استخدام التخطيط متعدد الأعمدة Multicol مع بعض أنواع التخطيطات لإنشاء عددٍ من الأعمدة المتجاوبة باستخدام خاصية عرض العمود column-width. يُمكن في المثال التالي معاينة إمكانية إضافة أعمدةٍ أخرى بعرض 200px إذا وجدت المساحة الكافية لها. استخدام استعلامات الوسائط في أنماط CSS لتحقيق التجاوب نحتاج أحيانًا إلى إجراء تغييراتٍ جذرية على التخطيط لدعم حجم شاشةٍ معينة وعلى نحوٍ أكبر مما تسمح به التقنيات السابقة. يأتي هنا دور استعلامات الوسائط media queries؛ وهي عوامل تصفية يُمكن تطبيقها على أنماط CSS بهدف تعديل الأنماط وفق أنواع الأجهزة التي تُظهر المحتوى أو ميزات هذه الأجهزة، مثل العرض والارتفاع والاتجاه وقابلية الحومان hover، وفيما إذا كانت الشاشة تعمل باللمس أم لا. نحتاج لاستهداف نوعٍ من الإظهار لتوفير أنماطٍ مختلفة للطباعة. يُمكن تضمين ورقة أنماط stylesheet تحوي أنماط الطباعة المختلفة كما يلي: <!DOCTYPE html> <html lang="en"> <head> … <link rel="stylesheet" href="print.css" media="print"> … </head> … كما يُمكن عوضًا عن الطريقة السابقة، تضمين أنماط الطباعة في ورقة الأنماط الرئيسية باستخدام استعلام الوسائط على النحو التالي: @media print { /* توضع أنماط الطباعة هنا */ } يُمكن تضمين أوراق أنماطٍ منفصلة في ملف أنماط CSS الرئيسي الخاص بك باستخدام صيغة import@، مثلًا: `@import url(print.css) print; إلا أنه لا يُوصى بهذا الاستخدام لأسبابٍ تتعلق بالأداء. يُمكن الرجوع إلى تجنُّب عمليات استيراد CSS لمزيدٍ من التفاصيل. يُستعلم في تصميم الويب المتجاوب عن ميزات الجهاز بهدف توفير تخطيطٍ مختلف للشاشات الأصغر؛ أو عند اكتشاف استخدام الزائر لشاشةٍ تعمل باللمس. استعلامات الوسائط المعتمدة على حجم إطار العرض تسمح استعلامات الوسائط بإنشاء تجربة استخدامٍ متجاوبة، حيث تُطبّق أنماطٌ معينة وفق حجوم الشاشات المختلفة؛ أي أن الميزة التي نستعلم عنها هي حجم الشاشة، كما يُمكن الاستعلام أيضًا عمّا يلي: العرض width (أدنى عرض min-width، أقصى عرض max-width). الارتفاع height (أدنى ارتفاع min-height، أقصى ارتفاع max-height). الاتجاه orientation. نسبة العرض إلى الارتفاع aspect-ratio. تتمتع كل هذه السمات بدعمٍ كامل من جميع المتصفحات. يجب عدم استخدام سمة عرض الجهاز device-width وسمة ارتفاع الجهاز device-height رغم وردهما في المواصفات القياسية؛ حيث أُلغي الاعتماد عليهما لأنهما تختبران الحجم الحقيقي لنافذة الجهاز وهو أمرٌ غير مفيد عمليًا، إذ يُمكن أن يكون هذا الحجم مختلفًا عن حجم إطار العرض الذي يُعاينه المستخدم، لاسيما فيما لو غيَّر حجم نافذة المتصفح مثلًا. استعلامات الوسائط المعتمدة على قدرات الجهاز لا يُمكن الجزم بأن كل جهازٍ كبير هو حاسوبٌ مكتبي، أو أن الأشخاص يستخدمون شاشات اللمس فقط على الأجهزة الصغيرة وذلك نظرًا لتنوع الأجهزة المُتاحة كثيرًا. يُمكن استخدام الإضافات الحديثة لمواصفات استعلامات الوسائط لاختبار نوع المؤشر المُستخدم للتفاعل مع الجهاز وفيما إذا كان المستخدم يستطيع الحومان hover على العناصر. الحومان hover. المؤشر pointer. "أي حومان" any-hover. "أي مؤشر" any-pointer. يُمكن للقارئ معاينة هذا العرض على أجهزةٍ مختلفة، مثل حاسوبٍ مكتبي، أو هاتف، أو جهاز لوحي. تتمتع هذه السمات الجديدة بدعمٍ كاملٍ من جميع المتصفحات الحديثة. استخدام سمة أي حومان any-hover وسمة أي مؤشر any-pointer تختبر سمة أي حومان any-hover فيما إذا كان المستخدم يتمتع بإمكانية الحومان؛ كما تختبر سمة أي مؤشر any-pointer استخدام نوعٍ ما من المؤشرات، وذلك حتى لو لم تكن الطريقة الأساسية لتفاعل المستخدم مع الجهاز. يجب توخي الحذر عند استخدام هذه السمات إذ لن يكون الطلب من المستخدم استخدام الفأرة عوضًا عن شاشة اللمس أمرًا مُحبذًا. يُمكن أن تكون هاتان السمتان مفيدتين، إذا كان من المهم معرفة نوع الجهاز الذي يمتلكه المستخدم. على سبيل المثال، ينبغي أن يُتابع الحاسوب المحمول المزود بشاشة لمس ولوحة تتبُّع المؤشرات العريضة والدقيقة إضافًة إلى إمكانية الحومان. كيفية اختيار النقاط الحدية يجب عدم اختيار النقاط الحدّية وفق فئات الأجهزة، حيث أن تعريف هذه النقاط اعتمادًا على أجهزةٍ، أو منتجات، أو أسماء علاماتٍ تجارية، أو نظم تشغيلٍ مُحدّدة قيد الاستخدام حاليًا يُمكن أن يؤدي إلى صعوبة الصيانة لاحقًا. عوضًا عن ذلك، ينبغي أن يُحدّد المحتوى كيفية ملائمة التخطيط لحاويته. اختيار النقاط الحدية بدءا من الحجم الأصغر ومن ثم الأكبر يجب تصميم المحتوى ليلائم حجم الشاشات الصغيرة أولًا، ومن ثم يُمكن توسيع الشاشة حتى يُصبح إدراج نقطة حدّية ضروريًا؛ حيث يُتيح ذلك الحصول على نقاط حدّية أمثلية بالاعتماد على المحتوى وبأقل عددٍ ممكن من هذه النقاط. بالعودة إلى مثال توقعات الطقس، الذي عرضناه في البداية، تكمن الخطوة الأولى في إظهار التوقعات على شاشةٍ صغيرة جيدًا كما يُبين الشكل التالي: ومن ثم تعديل حجم المتصفح حتى الحصول على فراغاتٍ بيضاء واسعة بين العناصر، وبحيث لا يبدو منظر توقعات الطقس جيدًا. يُمكن بالطبع أن يكون الحكم على جودة المنظر قرارًا شخصيًا، إلا أن الزيادة عن 600px ستُعطي فراغاتٍ عريضةً بالتأكيد. يُبين الشكل التالي مظهر التطبيق في وضعٍ يُظهر وجوب تعديل التصميم: لإدراج نقطةٍ حدّية عند 600px، نُنشئ استعلامي وسائط في نهاية أنماط CSS للمكوّن؛ حيث يُستخدم الأول عندما يكون عرض المتصفح أقل أو يساوي 600px؛ بينما يُستخدم الآخر عندما يكون عرض المتصفح أكبر من 600px. @media (max-width: 600px) { } @media (min-width: 601px) { } أخيرًا، نُعيد تشكيل أنماط CSS كما يلي: نُضيف أنماط CSS للشاشات الصغيرة ضمن استعلام الوسائط الأول وأنماط CSS للشاشات الأكبر ضمن استعلام الوسائط الثاني. اختيار نقاط حدية ثانوية عند الضرورة من المفيد إجراء بعض عمليات الضبط الطفيفة إضافًة إلى النقاط الحدّية الرئيسية المستخدمة لتغييرات التخطيط الكبيرة؛ حيث من المفيد مثلًا ضبط هوامش أو بطانة padding عنصر أو زيادة حجم الخط بين النقاط الحدّية الرئيسية مما يُساهم في جعل التخطيط مريحًا أكثر. يُمكن مثلًا البدء بتحسين تخطيط الشاشات الصغيرة عن طريق تكبير حجم الخط عند تجاوز عرض إطار العرض 360px، كما يُمكن الفصل بين درجات الحرارة العليا والدنيا بحيث تكون على نفس السطر عوضًا عن وضعها فوق بعضها بعضًا، إضافًة لتكبير أيقونة الطقس قليلًا وذلك عند توفر المساحة الكافية لذلك. @media (min-width: 360px) { body { font-size: 1.0em; } } @media (min-width: 500px) { .seven-day-fc .temp-low, .seven-day-fc .temp-high { display: inline-block; width: 45%; } .seven-day-fc .seven-day-temp { margin-left: 5%; } .seven-day-fc .icon { width: 64px; height: 64px; } } وبالمثل، يكون من الأفضل تحديد أقصى عرضٍ للوحة توقعات الطقس، بحيث لا تمتد على كامل عرض الشاشة. إعدادات النص للقراءة الأمثلية تنص قواعد إتاحة القراءة السهلة على وجوب عدم احتواء السطر الواحد على أكثر من 70 إلى 80 حرفًا (حوالي 8 إلى 10 كلمات في اللغة الإنجليزية)؛ مما يتطلب إدراج نقطة حدّية في حال تجاوز عدد الكلمات في كتلةٍ نصية 10 كلمات. يُبين الشكل التالي مظهر النص على هاتف جوال: بينما يظهر نفس النص على حاسوبٍ مكتبي بعد إضافة النقاط الحدّية لتحديد طول السطر: يُبين المثال السابق ملاءمة الخط Roboto من الحجم 1em على نحوٍ أمثلي للشاشات الصغيرة، حيث يوفر حوالي 10 كلمات في السطر الواحد؛ أما بالنسبة للشاشات الكبيرة فيجب إضافة نقطة حدّية. يُبين المثال التالي تحديد عرض المحتوى إلى 550px إذا تجاوز عرض المتصفح 575px. @media (min-width: 575px) { article { width: 550px; margin-left: auto; margin-right: auto; } } تجنب إخفاء المحتوى يجب توخي الحذر عند اختيار المحتوى المطلوب إخفاءه أو إظهاره وفق حجم الشاشة؛ إذ لا يجب إخفاء محتوًى ما لمجرد عدم ملاءمته لحجم الشاشة، فقد يكون هذا المحتوى مهمًا جدًا للمستخدم. يُشكّل مثلًا إخفاء نسبة غبار الطلع في الهواء من توقعات الطقس مشكلةً كبيرة للذين يعانون من الحساسية في فصل الربيع والذين يحتاجون لهذه المعلومة لمعرفة فيما إذا كان بإمكانهم الخروج من المنزل أم لا. معاينة النقاط الحدية لاستعلامات الوسائط في أدوات التطوير Chrome DevTools يُمكن تغيير حجم المتصفح لمعاينة مظهر صفحات الموقع بعد الانتهاء من إعدادات النقاط الحدّية، كما يُمكن أيضًا استخدام أدوات التطوير Chrome DevTools، والتي تسمح بمعاينة الصفحة مع مختلف النقاط الحدّية. يُبين الشكل التالي تطبيق حالة الطقس مع إطار عرضٍ عريض باستخدام DevTools: كما يُبين الشكل التالي تطبيق حالة الطقس مع إطار عرضٍ ضيق باستخدام DevTools: لمعاينة الصفحة مع نقاط حدّية مختلفة، يُمكن فتح أدوات المطور DevTools ثم تشغيل وضع الجهاز Device Mode مما يؤدي لفتح الصفحة بالوضع المتجاوب responsive mode. كما يُمكن لمعاينة استعلامات الوسائط وإظهار النقاط الحدّية على هيئة أشرطةٍ ملونة، اختيار Show media queries من القائمة Device Mode. يؤدي النقر على شريطٍ من هذه الأشرطة إلى معاينة الصفحة مع تنشيط استعلام الوسائط الموافق، كما يؤدي النقر بزر الفأرة الأيمن على شريطٍ ما للانتقال إلى تعريف استعلام الوسائط الموافق. ترجمة -وبتصرف- للمقالة Responsive web design basics للمؤلفين: Pete LePage و Rachel Andrew. اقرأ أيضًا ما هو الفرق بين التصميم المتجاوب (Responsive Web Design) والتصميم المتلائم (Adaptive Web Design) الدليل الشامل لشرح النقاط الحدية لصفحات الويب المتجاوبة
-
يتنقل المستخدمون بين واجهات العرض المختلفة طوال الوقت، مثل الانتقال من واجهةٍ تحوي قائمةً من العناصر إلى واجهةٍ تعرض تفاصيل عنصرٍ ما من هذه العناصر، أو إظهار شريط تنقُّلٍ جانبي عن طريق النقر على جزءٍ منه. يُساهم التحريك بين الواجهات إلى زيادة ارتباط المستخدم بالتطبيق وإضفاء الحياة عليه. يجب استخدام الانتقالات translations للتنقُل بين الواجهات، مع تجنُّب استخدام خصائصٍ، مثل اليسار left أو الأعلى top والتي تُنشّط التخطيط. يجب التأكد من سرعة التحريك وقصر مدته. يجب الانتباه لتغييرات التحريك والتخطيط عند زيادة حجم الشاشة، إذ أن ما يصلح على شاشةٍ صغيرة قد يبدو غريبًا على شاشة حاسوب مكتبي. يعتمد مظهر وسلوك الانتقالات بين الواجهات على أنواع واجهات العرض المختلفة؛ حيث يختلف مثلًا تحريك شريطٍ منبثق شرطي أعلى واجهةٍ عن الانتقال بين قائمة عناصر وواجهة عرض تفاصيل عنصرٍ منها. من قواعد النجاح الأساسية المحافظة على 60 إطارًا في الثانية عند التحريك. وبهذا، نتجنب ظهور التحريك المتقطع المتداخل مع تفاعل المستخدمين؛ كما يجب التأكد من ضبط الخاصية "سوف يُعدّل" will-change لأي عنصرٍ يُخطط لتحريكه لاحقًا. أما بالنسبة للانتقالات بين واجهات العرض، يُستحسن استخدام will-change: transform. استخدام الانتقالات للتنقل بين واجهات العرض لتسهيل عرض الأفكار في هذه المقالة، سنفترض في مثالنا وجود واجهتين، الأولى هي واجهة عرض قائمةٍ من العناصر، والثانية هي واجهة عرض تفاصيل عنصرٍ منها؛ فعند نقر المستخدم على عنصرٍ في قائمة العرض الأولى، تنزلق واجهة عرض التفاصيل لتظهر داخلًة على الشاشة، وتنزلق قائمة العرض الأولى لتختفي خارجةً من الشاشة. لتنفيذ التأثير السابق، نحتاج إلى حاويةٍ لكلتا واجهتي العرض مع ضبط خاصية الفيضان overflow إلى مخفي overflow: hidden. وبهذه الطريقة، توضع كلتا الواجهتين داخل الحاوية جنبًا إلى جنب دون إظهار أي أشرطة تمريرٍ أفقية، كما يُمكن أن تنزلق كل واجهة جنبًا إلى جنب داخل الحاوية حسب الحاجة. تكون أنماط CSS للحاوية: .container { width: 100%; height: 100%; overflow: hidden; position: relative; } يمكن ضبط خاصية موقع الحاوية إلى نسبي relative؛ مما يعني توضُّع كل واجهة عرض ضمن هذه الحاوية تمامًا في الزاوية اليسرى العلوية ومن ثم تُحرّك باستخدام التحويلات. تُعدّ هذه الطريقة أفضل وأسهل من حيث الأداء، من استخدام خاصية اليسار left، التي يؤدي إلى تشغيل التخطيط والطلاء، ويكون من السهل عادًة تخفيف تكلفة هذه الطريقة. .view { width: 100%; height: 100%; position: absolute; left: 0; top: 0; /* أعلم المتصفح بخطة تحريك كل واجهة عرض دخولًا وخروجًا*/ will-change: transform; } تؤدي إضافة الانتقال transition في خاصية التحويل transform إلى إضفاء تأثير انتقالٍ لطيف. يُستخدم منحني بيزيه cubic-bezier مخصّص للوصول إلى شعور استخدام مُحبَّب. .view { transition: transform 0.3s cubic-bezier(0.465, 0.183, 0.153, 0.946); } يجب تحريك واجهة العرض الموجودة خارج الشاشة إلى اليمين، لذا يجب في هذه الحالة نقل واجهة عرض التفاصيل: .details-view { transform: translateX(100%); } يجب الآن كتابة بعض تعليمات JavaScript للتعامل مع الصفوف. تبدِّل الشيفرة التالية الصفوف المناسبة لواجهات العرض: var container = document.querySelector('.container'); var backButton = document.querySelector('.back-button'); var listItems = document.querySelectorAll('.list-item'); /* تعديل الصفوف في الحاوية واختيار واجهة العرض */ function onViewChange(evt) { container.classList.toggle('view-change'); } //عند النقر على عنصر في القائمة يحب عرض واجهة تفاصيله for (var i = 0; i < listItems.length; i++) { listItems[i].addEventListener('click', onViewChange, false); } //العودة للواجهة الأولى عند النقر على زر العودة للخلف backButton.addEventListener('click', onViewChange); وأخيرًا، تُضاف تصريحات CSS إلى هذه الصفوف: .view-change .list-view { transform: translateX(-100%); } .view-change .details-view { transform: translateX(0); } يُمكن تجربة المثال. يُمكن توسيع المثال لإضافة واجهات عرض متعددة مع نفس منهجية العمل: تكون كل واجهة غير مرئية خارج الشاشة مع إحضارها وإظهارها حين الحاجة وإزالة واجهة العرض الحالية. إضافًة إلى الانتقال بين واجهات العرض، يُمكن تطبيق هذه التقنية أيضًا على العناصر المنزلقة، مثل عناصر التنقل في الشريط الجانبي. يكمن الاختلاف الحقيقي الوحيد في أنه لا يجب تحريك واجهات العرض الأخرى. التأكد من تنفيذ التحريك على الشاشات الأكبر يجب الاحتفاظ بقائمة العرض طوال الوقت بالنسبة للشاشات الأكبر عوضًا عن إزالتها، والانتقال لواجهة عرض التفاصيل من الجانب الأيمن. يؤدي هذا إلى سلوكٍ مشابهٍ للتعامل مع واجهة عرض تنقل. تحريك واجهات العرض المنبثقة الشرطية تُستخدم واجهات العرض المنبثقة الشرطية لعرض الرسائل الهامة وذلك في حال توفر الأسباب الموجبة لتعطيل التفاعل مع واجهة المستخدم. يجب عمومًا عدم الإفراط في استخدام هذا النوع من الواجهات لأنها تقاطع تجربة الاستخدام وقد تؤدي لإنهائها؛ إلا أنها يُمكن أن تكون ضرورية في بعض الحالات؛ كما يُسهم إضافة التحريك لها في إضفاء الحيوية عليها. يجب استخدام واجهات العرض المنبثقة الشرطية باعتدال؛ حيث يشعر المستخدمون بالإحباط إذا قاطعت تجربتهم دون داعٍ. تُساهم نسبة التحجيم المناسبة في إضفاء التأثير اللطيف "إسقاط على drop on". يجب إخفاء واجهات العرض المنبثقة الشرطية بسرعة عندما يرفضها المستخدم؛ كما يجب إظهار هذه الواجهات ببطء حتى لا تُفاجئ المستخدم. يجب تطابق حجم غطاء الواجهة المنبثقة مع إطار العرض وذلك عن طريق ضبط خاصية الموضع position إلى ثابت fixed: .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; opacity: 0; will-change: transform, opacity; } تكون قيمة الشفافية opacity للواجهة 0 في البداية وتكون بذلك مخفية، إلا أنها تحتاج أيضًا إلى ضبط أحداث المؤشر pointer-events إلى لا شيء none حتى لا تتجاوب مع أحداث المستخدم مثل النقر واللمس؛ وبدون ذلك، تُعطّل جميع التفاعلات وتغدو الصفحة غير مستجيبة أبدًا. أخيرًا، يجب استخدام will-change مع كلٍ من الخصائص opacity و transform التي يُطبّق التحريك عليها. يُمكن الرجوع إلى استخدام الخاصية will-change. يجب أن تستجيب الواجهة المنبثقة عندما تكون مرئيةً لتفاعلات المستخدم مع شفافيةٍ opacity قيمتها 1: .modal.visible { pointer-events: auto; opacity: 1; } يُمكن استخدام سكريبت جافا لتبديل الصف إلى مرئي "visible" عند الحاجة لعرض الواجهة المنبثقة. modal.classList.add('visible'); يُمكنك الآن، إضافة التحريك إلى الواجهة المنبثقة. .modal { transform: scale(1.15); transition: transform 0.1s cubic-bezier(0.465, 0.183, 0.153, 0.946), opacity 0.1s cubic-bezier(0.465, 0.183, 0.153, 0.946); } تُساهم نسبة التحجيم scale في جعل المنظر يبدو وكأنه يسقط على الشاشة بهدوء، مما يُعطي تأثيرًا جميلًا. يُطبّق الانتقال الافتراضي على كلٍ من خاصية التحويل transform والشفافية opacity مع منحني مخصص ومدةٍ تبلغ 0.1 ثانية. تبدو المدة 0.1 ثانية لظهور الواجهة المنبثقة قصيرةً جدًا، إلا أنها مثاليةٌ للمستخدم الذي يريد اغلاق هذه الواجهة والعودة إلى التطبيق. يكمن الجانب السلبي لهذه المدة القصيرة بالظهور السريع المفاجئ للواجهة. يُمكن إصلاح هذا الخلل بتجاوز هذه القيمة للصف المرئي visible ووضع قيمةٍ أكبر: .modal.visible { transform: scale(1); transition: transform 0.3s cubic-bezier(0.465, 0.183, 0.153, 0.946), opacity 0.3s cubic-bezier(0.465, 0.183, 0.153, 0.946); } يستغرق الآن ظهور الواجهة المنبثقة وقتًا أطول (أقل مفاجأةً للمستخدم) مع إخفاءٍ سريع مما يُلبي طموح المستخدم. توقيت التحريك غير المتزامن يُحسِّن توقيت التحريك غير المتزامن من تجربة الاستخدام من خلال السماح بإضفاء هويةٍ للتطبيق مع التجاوب السريع مع تفاعلات المستخدم بنفس الوقت؛ كما يوفر أيضًا تباين التفاعل مما يجعل الواجهة أكثر جاذبيةً. يُستخدم التوقيت غير المتزامن لإضفاء هويةٍ للتطبيق ولتحقيق تباين العمل. يجب دومًا تفضيل تفاعل المستخدم. يجب مثلًا استخدام فتراتٍ أقصر عند الاستجابة لأحداث المستخدم، مثل النقر أو السحب؛ والاحتفاظ بفتراتٍ أطول للحالات الأخرى. يجب دومًا التجريب لمعرفة المناسب للتطبيق تمامًا مثل معظم قواعد التحريك، مع الانتباه إلى أن المستخدم ليس له الصبر الكافي لفعل ذلك. تنص القاعدة الأساسية على وجوب الاستجابة لتفاعل المستخدم بسرعة. وبما أن تفاعل المستخدم غير متزامن معظم الوقت يجب أن يكون التحريك كذلك. مثلًا: في حال نقر المستخدم على شريط تنقُّل جانبي، لا بُدّ من عرضه مباشرًة وخلال فترة حوالي 100 ميلي ثانية؛ بينما يُمكن التباطؤ في عملية التحريك خارجًا لحوالي 300 ميلي ثانية عند إخفاء المستخدم لقائمة. على النقيض من ذلك، عند إحضار واجهة عرض منبثقة مشروطة (عادةً لعرض خطأ أو بعض الرسائل الهامة الأخرى)، يُمكن إظهار العرض على نحوٍ أبطأ قليلاً (أيضًا حوالي 300 ميلي ثانية)؛ أما عند طلب المستخدم لإغلاق الواجهة، فيجب أن يحدث هذا بسرعة كبيرة. نُبين فيما يلي القواعد العامة للتحريك: يكون للتحريك في واجهة المستخدم والذي يُنشّط عند تفاعل المستخدم، مثل التنقل بين واجهات العرض أو إظهار عنصر ما، مقدمةً سريعة (مدة قصيرة)، وخاتمةً بطيئة (مدة أطول). يكون للتحريك في واجهة المستخدم والذي يُنشّط من خلال شيفرة المطور البرمجية، مثل إظهار الأخطاء أو واجهات العرض المنبثقة المشروطة، مقدمةً أبطأ (مدة أطول)، وخاتمةً سريعة (مدة قصيرة). ترجمة -وبتصرف- للمقالات التالية: Animating Between Views للمؤلف: Paul Lewis. Animating Modal Views للمؤلف: Paul Lewis. Asymmetric animation timing للمؤلف: Paul Lewis. اقرأ أيضًا التحكم في تسارع وتباطؤ الحركات المطبقة على عناصر صفحات الويب المرجع الشامل إلى التحريك عبر CSS أفضل 25 مكتبة تحريك في CSS النسخة العربية الكاملة من كتاب: التحريك عبر CSS
-
تعدّ عمليات دفع الأموال من العملاء أهم الأمور الواجب تسهيلها لهم وتنويع طرقها كي لا نفقد بعض العملاء الذين قد يواجهون صعوبات في عملية الدفع أو حتى عدم توافرها لديهم، كما يجب توفير طرق متنوعة لشحن البضائع للعملاء ولمختلف المناطق. نعرض في هذا الدرس الأخير من السلسلة إعدادات الدفع والشحن التي يوفرها متجر أوبن كارت بالتفصيل. هذا المقال جزء من سلسلة تعريفية بلوحة تحكم متجر أوبن كارت، إليك فهرس مقالات كامل السلسلة: مدخل إلى متجر أوبن كارت وكيفية تثبيته إدارة الأقسام والمنتجات في متجر أوبن كارت إدارة إعدادات متجر أوبن كارت إدارة المتجر في أوبن كارت شرح الإضافات والقوالب في لوحة تحكم متجر أوبن كارت نظرة على خيارات التسويق التي يوفرها متجر أوبن كارت التقارير والإحصائيات: نافذة على أداء متجر أوبن كارت إعدادات الدفع والشحن في متجر أوبن كارت بوابات الدفع لمتجر أوبن كارت يوفر أوبن كارت مجموعة كبيرة من طرق الدفع الممكنة بدءًا من التحويل البنكي إلى الدفع الإلكتروني عبر الويب، كما يُمكن استخدام أكثر من بوابة دفع Payment Gateway في آن واحد. يجب على مدير المتجر تثبيت وتمكين بوابات الدفع المناسبة للمتجر لتصبح متاحة للعملاء في واجهة المتجر، ويُمكن استعراض قائمة بوابات الدفع المتاحة من صفحة "الإضافات" والتي نصل إليها من "لوحة التحكم" ثم "الإضافات"، ثم نختار نوع الإضافة "طرق الدفع" من القائمة "اختيار نوع الإضافة": تظهر جميع بوابات الدفع المتاحة: لتمكين بوابة الدفع، يجب أولًا تثبيتها وذلك بالنقر على الزر الأخضر "تنصيب" المجاور لها ومن ثم تحرير بوابة الدفع لإدخال الإعدادات المناسبة. يُمكن أيضًا تنزيل طرق دفع أخرى من الرابط. ضبط بوابات الدفع تختلف الإعدادات حسب طريقة الدفع إلا أنها تتشارك جميعًا في الحقول التالية: الإجمالي المطلوب لتفعيل طريقة الدفع Total: الحد الأدنى للمبلغ الذي يُمكن للعميل دفعه باستخدام طريقة الدفع. حالة الطلب Order Status: الحالة التي ستكون للطلب بعد إتمام العميل لعملية الدفع. يُنصح وضع الحالة "جاري التجهيز" لإتاحة الوقت للإدارة لمراجعة الطلب وتجهيزه. الحالة Status: "تمكين" عملية الدفع أو تعطيلها. ترتيب الفرز Sort Order: ترتيب العرض. مثلًا من أجل طريقة الدفع "تحويل بنكي": تكون حقول هذه الطريقة (إضافًة للحقول الأربعة السابقة): اسم البنك وصاحب الحساب Bank Account: معلومات الحساب البنكي للمتجر باللغتين العربية والإنكليزية. المنطقة الجغرافية Geo Area: المنطقة الجغرافية التي يُمكن فيها استخدام طريقة الدفع. أما بالنسبة لطريقة الدفع باستخدام PayPal: تكون حقول طريقة الدفع: تتطلب طريقة الدفع باستخدام PayPal الاشتراك المسبق مع الشركة المسؤولة والحصول على معلومات الاشتراك. الدفع في واجهة المتجر تظهر طرق الدفع المتاحة للعميل في واجهة المتجر في "الخطوة الخامسة: طريقة الدفع" من عملية إتمام الطلب Checkout: يُمكن للعميل معاينة طلباته في واجهة المتجر وذلك بالدخول إلى صفحة "تفاصيل الطلب" ليجد جميع تفاصيل طلباته: الضرائب يحتوي أوبن كارت على خيارات عديدة لإضافة الضريبة على السعر الأساسي، ويعتمد سعر الضريبة على الدولة وبهذا يُمكن تحصيل ضريبة مختلفة من العملاء حسب مناطقهم الجغرافية ووفقًا للضريبة المحلية الموافقة. يُمكن إعداد الضريبة من من "لوحة التحكم" ثم "الضبط" ثم "الضرائب" ثم "أسعار الضريبة": يُمكن أن تكون الضريبة نسبة مئوية أو مبلغًا ثابتًا. بعد الانتهاء من ضبط إعدادات الضرائب، يجب تعريف الضريبة لكل منتج من خيارات المنتج نفسه. طرق الشحن تحتاج المتاجر التي تبيع منتجات ملموسة (غير إلكترونية يُمكن تحميلها من المتجر) إلى طرق شحن مناسبة لها. للوصول إلى قائمة طرق الشحن المتاحة بشكل افتراضي في المتجر، نفتح "الإضافات" من "لوحة التحكم" ثم "الإضافات" ثم "الإضافات" ومن ثم نختار "طرق الشحن" من القائمة "اختيار نوع الإضافة": تظهر طرق الشحن المتاحة: يجب تثبيت طريقة الشحن المطلوبة (بالنقر على الزر "تنصيب" الموافق) ومن ثم إدخال الإعدادات المناسبة لها. تتشارك جميع طرق الشحن في الحقول التالية: سعر الشحن Total: الحد الأدنى للمبلغ الإجمالي لاستخدام طريقة الشحن. المنطقة الجغرافية Geo Zone: المنطقة الجغرافية التي تتوفر لها طريقة الشحن. الحالة Status: "تمكين" طريقة الشحن أو تعطيلها في واجهة المتجر. الفرز Sort Order: ترتيب الإظهار. تختلف حقول إعداد طريقة الشحن وفق الطريقة المختارة. مثلًا من أجل طريقة الشحن "تكلفة ثابتة للشحن": تكون الحقول: بينما من أجل الطريقة "الشحن بالقطعة": تكون الحقول: كما يُمكن الشحن عبر الشركات العالمية للشحن مثل UPS: يجب إدخال معلومات الاشتراك والتعامل مع الشركة: يؤدي ضبط مدير المتجر طرق الشحن في لوحة التحكم بالمتجر إلى إتاحة الطرق المختارة إلى العملاء في واجهة المتجر في سلة الشراء Shopping Cart وفي صفحات إتمام الطلب Checkout. ملاحظة: يُمكن إعداد المناطق الجغرافية من صفحة "المناطق الجغرافية" والتي نفتحها من "الضبط" ثم "الأوضاع" ثم "المناطق الجغرافية". تُستخدم المناطق الجغرافية في إعدادات الشحن والضرائب. يُمكن وضع دول ومناطق مختلفة في مجموعة جغرافية واحدة: إضافة أجور الشحن في سلة الشراء تحتوي سلة الشراء التبويب "الشحن المتوقع" "Estimate Shipping & Taxes" والذي يسمح بمعرفة أجور الشحن المترتبة. تظهر أجور الشحن بعد النقر على الزر "إرسال": حيث يُطلب اختيار طريقة الشحن المناسبة ومن ثم التأكيد بالنقر على الزر "اعتمد الشحن"، وستًضاف قيمة الشحن إلى إجمالي الطلبية. لاحظ أنه يُمكن تمكين أو تعطيل هذه الميزة من الإضافة "طريقة الشحن" كما يلي، نفتح صفحة "الإضافات" ونختار "إجماليات الطلب" من القائمة "اختيار نوع الإضافة": حيث تظهر جميع الإضافات والتي يُمكن أن تُعدّل (إضافة أو إنقاص) من إجمالي الطلبية: مثلًا يُمكن تمكين "طريقة الشحن": تحديد الشحن أثناء إتمام الطلب Checkout يتوجب على العميل في الخطوة الرابعة من إتمام الطلب إلى تحديد طريقة الشحن قبل إنهاء عملية الشراء. تُعرض جميع طرق الشحن المُمكنّة من قبل مدير المتجر: خاتمة عرضنا في هذا الدرس مختلف آليات الدفع والشحن المتاحة في أوبن كارت والتي تُناسب مختلف الحالات المُمكنة عمليًا. اقرأ أيضًا كيف تختار السعر الملائم للمنتج؟ مراحل عملية الشراء -عند الإقدام على فعل الشراء-
-
لا يتحرك أي شيء في الطبيعة من نقطةٍ إلى أخرى خطيًا، حيث تميل الأشياء إلى التسارع أو التباطؤ أثناء تحرُّكها على أرض الواقع. بما أن أدمغتنا مصممةٌ لتوقُّع مثل هذا النوع من الحركة، يجب استخدام ذلك عند التحريك لتحسينه وجعل الحركة تبدو طبيعية مما يؤدي لشعور المستخدمين براحةٍ أكبر والوصول إلى تجربة استخدامٍ أفضل للتطبيق عمومًا. يؤدي التخفيف إلى جعل التحريك يبدو طبيعيًا. يُفضّل استخدام تخفيف السرعة نهاية الحركة ease-out مع عناصر الواجهة. يجب تجنُّب استخدام تخفيف السرعة بداية الحركة ease-in وتخفيف السرعة بداية الحركة ونهايتها ease-in-out ما لم يكن التحريك قصيرًا، لأنهما تتسببان بنوعٍ من الحركة الخمولة. الكلمات المفتاحية في التخفيف تسمح كلٌ من الانتقالات والتحريك في CSS باختيار نوع التخفيف المطلوب للتحريك (راجع فقرة اختيار التخطيط الصحيح). يُمكن استخدام الكلمات المفتاحية التي تؤثر على التخفيف (أو التوقيت timing كما يُطلق عليه أحيانًا) للحركة المعنية؛ كما يُمكن أيضًا تخصيص التخفيف (راجع فقرة تخصيص التخفيف)، مما يمنح الحرية الواسعة لإعطاء هويةٍ مميزة للتطبيق. أهم الكلمات المفتاحية المُمكن استخدامها في أنماط CSS: خطي linear. تخفيف السرعة بداية الحركة ease-in. تخفيف السرعة نهاية الحركة ease-out. تخفيف السرعة بداية الحركة ونهايتها ease-in-out. يُمكن الوصول إلى المصدر في W3C. يُطلق مصطلح "الدخول ببطء slow in" في الرسوم المتحركة للدلالة على الحركة التي تبدأ ببطء ومن ثم تتسارع؛ كما يُطلق مصطلح "الخروج ببطء slow out" على الحركة التي تبدأ مُسرعًة ومن ثم تتباطأ. يُستخدم بصورةٍ مماثلة كلٌ من المصطلحين "تخفيف السرعة بداية الحركة ease in" و"تخفيف السرعة نهاية الحركة ease out" في التحريك على الويب. يُمكن الجمع أحيانًا بين نوعي التحريك السابقين وصولًا إلى "تخفيف السرعة بداية الحركة ونهايتها ease-in-out". يؤدي استخدام التخفيف الحصول على حركة أقل حدًّة وأكثر وضوحًا. يُمكن استخدام الكلمة المفتاحية خطوات steps لإنشاء الانتقالات ذات الخطوات المنفصلة، ولكن تُعدّ الكلمات المفتاحية السابقة أكثر فائدةً في إنشاء التحريك الذي يبدو طبيعيًا. التحريك الخطي يُوصف التحريك الذي لا يستخدم أي تخفيفٍ بالتحريك الخطي linear. يوضّح الرسم البياني التالي مراحل الانتقال الخطي؛ حيث تزداد القيمة زياداتٍ متساوية عبر الزمن. تبدو الحركة الخطية آليةً وغير طبيعية مما يُنفّر المستخدمين، وبالتالي يجب تجنُّب التحريك الخطي. يُمكن استخدام التحريك الخطي دومًا سواءٌ عند استخدام أنماط CSS أو عند استخدام JavaScript. يُمكن معاينة تحريك خطي. للحصول على التأثير السابق باستخدام أنماط CSS: transition: transform 500ms linear; تخفيف السرعة نهاية الحركة يؤدي تخفيف السرعة نهاية الحركة ease-out إلى بدءٍ أسرع للحركة مما هو في التحريك الخطي، وتَباطُؤ في النهاية، كما هو موضحٌ في الرسم البياني التالي. يُعدّ تخفيف السرعة نهاية الحركة ease-out الخيار الأفضل لواجهات المستخدم؛ حيث تُعطي البداية السريعة الانطباع بالتجاوب مع توفير التباطؤ الطبيعي في النهاية. يُمكن معاينة تخفيف السرعة نهاية الحركة. يُمكن تحقيق تخفيف السرعة نهاية الحركة بعدة طرق؛ ومن أسهلها استخدام الكلمة المفتاحية ease-out في CSS: transition: transform 500ms ease-out; تخفيف السرعة بداية الحركة Ease-in يبدأ التحريك من هذا النوع ببطء وينتهي بسرعة خلافًا للتحريك من النوع تخفيف السرعة نهاية الحركة Ease-out، كما هو موضح في الرسم البياني التالي. يشبه هذا التحريك تسارع سقوط حجرٍ ثقيل؛ حيث يبدأ ببطء ويصطدم بالأرض بسرعةٍ كبيرة. يُمكن مع ذلك أن يبدو هذا النوع من الحركة غير طبيعي بسبب نهايتها المفاجئة، حيث تميل الأشياء المتحركة في عالمنا الحقيقي إلى التباطؤ عوضًا عن التوقُّف المفاجئ. يؤدي تخفيف السرعة بداية الحركة إلى الشعور بالركود عند البداية البطيئة؛ مما يؤثر سلبًا على ملاحظة الإستجابة في الموقع أو التطبيق. يُمكن معاينة تخفيف السرعة بداية الحركة. يُمكن تحقيق تخفيف السرعة بداية الحركة باستخدام الكلمة المفتاحية ease-in في CSS: transition: transform 500ms ease-in; تخفيف السرعة بداية الحركة ونهايتها Ease-in-out يُشبه تخفيف السرعة بداية الحركة ونهايتها عمليات تسارع وتباطؤ السيارة ويُمكنه توفير تأثيراتٍ أفضل من تأثيرات تخفيف السرعة نهاية الحركة في حال استخدامه بحكمة. لا يجب وضع مدةٍ طويلةٍ للتحريك بسبب البطء في بداية التحريك مع تخفيف الدخول. يُمكن أن تكون أي قيمةٍ بين 300 و500 ميلي ثانية مناسبةً؛ وتعتمد القيمة الدقيقة على طبيعة المشروع. تؤدي البداية البطيئة والتسارع في المنتصف والنهاية البطيئة إلى مزيدٍ من التباين في التحريك مما يُرضي المستخدمين. يُمكن معاينة تخفيف السرعة بداية الحركة ونهايتها. يُمكن الحصول على تحريك من النوع "تخفيف السرعة بداية الحركة ونهايتها" باستخدام الكلمة المفتاحية ease-in-out: transition: transform 500ms ease-in-out; التخفيف المخصص يُمكن في بعض الأحيان التخلّي عن استخدام الكلمات المفتاحية في CSS، أو واجهة برمجة التطبيقات Web Animations، أو إطار عمل JavaScript، وتعريف منحنياتٍ أو معادلاتٍ مخصصة عوضًا عن ذلك؛ مما يوفر تحكُّمًا أكبر في التحريك المطلوب. يسمح التخفيف المُخصّص بإضفاء هويةٍ شخصيةٍ مُميزةٍ للمشروع. يُمكّن التخفيف المُخصّص من إنشاء منحنيات بيزيه Bézier المكعبة، والتي تُشبه منحنيات التحريك الافتراضية (تخفيف السرعة بداية الحركة، تخفيف السرعة نهاية الحركة، …) مع التركيز على جوانبٍ مختلفة. تُستخدم JavaScript عند الحاجة لتوفير تحكمٍ أكبر في توقيت التحريك وسلوكه، مثل التحريك المرن أو المُرتدّ bounce . يُمكن تعريف منحنيات بيزيه المكعبة في أنماط CSS لتحديد التوقيت؛ حيث توافق الكلمات المفتاحية ease و ease-in و ease-out و linear في الحقيقة منحنيات بيزيه مُعرّفةً مسبقًا. يُمكن الرجوع للتفاصيل في CSS transitions specification و Web Animations specification. تأخذ منحنيات بيزيه أربع قيم (أو زوجين من الأرقام)؛ حيث يُحدّد كل زوجٍ إحداثيات X و Y لنقاط التحكم في منحني بيزيه المكعب. يكون لنقطة البداية لمنحني بيزيه الإحداثيات (0 ، 0)، والإحداثيات (1 ، 1) لنقطة النهاية، ويُمكن ضبط قيم X و Y لنقطتي التحكم. يجب أن تكون قيم X لنقطتي التحكم بين 0 و 1، بينما يُمكن لقيم Y تجاوز المجال [0,1]. لا تُحدّد المواصفات مقدار التجاوز المسموح بوضوح. يُعطي تغيير قيمة X و Y لكل نقطة تحكم منحنًى مختلفٍ تمامًا، وبالتالي شعورًا مختلفًا تمامًا مع التحريك المُخصص. إذا كانت نقطة التحكم الأولى في المنطقة اليمنى السفلية مثلًا، يكون بدء التحريك بطيئًا؛ أما إذا كانت في المنطقة العلوية اليسرى، يكون بدء التحريك سريعًا؛ وعلى العكس من ذلك، إذا كانت نقطة التحكم الثانية في المنطقة اليمنى السفلية من الشبكة، يكون التحريك سريعًا في النهاية؛ أما إذا كانت في المنطقة العلوية اليسرى، يكون التحريك بطيئًا في النهاية. يُمكن مقارنة منحنيين في الشكل التالي، المنحني الأيسر مع تخفيف-داخل أما المنحني الأيمن فهو مُخصص: يُمكن معاينة التحريك مع تخفيف مخصص. تكون أنماط CSS للتخفيف المخصص: transition: transform 500ms cubic-bezier(0.465, 0.183, 0.153, 0.946); يُحدّد الرقمان الأولان إحداثيات X و Y لنقطة التحكم الأولى؛ بينما يحدد الرقمان الثانيان إحداثيات X و Y لنقطة التحكم الثانية. يُعدّ إنشاء منحنًى مخصصًا أمرًا ممتعًا للغاية، ويمنح تحكمًا كبيرًا في طبيعة التحريك. يُشبه المنحنى السابق مثلًا المنحني التقليدي في "تخفيف السرعة بداية الحركة ونهايتها" مع تباطؤ الدخول والخروج. يُمكن تجريب أداة منحني التحريك ومعاينة تأثيرات المنحني على طبيعة التحريك. استخدم أطر عمل JavaScript لتوفير المزيد من التحكم تظهر الحاجة أحيانًا إلى تحكمٍ أكبر مما يوفِّره منحني بيزيه المكعب، حيث يجب مثلًا استخدام أطر عمل JavaScript في حال ضرورة توفير الشعور بالارتداد المرن؛ لأنه لا يُمكن توفير ذلك باستخدام أنماط CSS أو Web Animations. إطار العمل TweenMax يُعدّ إطار العمل GreenSock’s TweenMax (أو الإطار TweenLite في حال الرغبة بإبقاء الشيفرة خفيفة) من الأطر القوية التي توفر قدرًا كبيرًا من التحكم باستخدام مكتبة JavaScript صغيرة؛ علمًا أن هذه المكتبة تحتوي شيفرة قاعدية ناضجة. يُمكن معاينة تخفيف تحريك مرن. لاستخدام TweenMax، يجب تضمين الشيفرة التالية في الصفحة: <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script> بعد ذلك، يُمكن استدعاء TweenMax مع أي عنصرٍ لتحريكه مع ضبط الخصائص المناسبة لأي تخفيفٍ مطلوب. يوجد العديد من خيارات التخفيف المُمكن استخدامها؛ حيث تَستخدم الشيفرة التالية مثلًا تخفيف خروجٍ مرن: var box = document.getElementById('my-box'); var animationDurationInSeconds = 1.5; TweenMax.to(box, animationDurationInSeconds, { x: '100%', ease: 'Elastic.easeOut' }); تُسلِّط وثائق TweenMax الضوء على جميع الخيارات الممكنة. اختيار التخفيف الصحيح بعد مناقشتنا السابقة للخيارات المختلفة المُتاحة لتخفيف التحريك، تبرز الأسئلة التالية: ما نوع التخفيف الواجب استخدامه في المشاريع؟ وما هي المدة الأنسب للتحريك؟ يُفضّل استخدام "تخفيف السرعة نهاية الحركة" لتحريك عناصر الواجهة، ويُعدّ Quintic من أكثر الأنواع جاذبيةً وأناقة وإن كان سريعًا. يجب التأكُّد من ضبط مدة التحريك؛ حيث يُمكن أن تكون مدة 200 إلى 500 ميلي ثانية مناسبةً لتخفيف السرعة بداية الحركة ونهايتها؛ بينما يستلزم التخفيف المرن والمُرتدّ مدًةً أطول بين 800 إلى 1200 ميلي ثانية. يُعدّ "تخفيف السرعة نهاية الحركة" الخيار الصحيح (يجب وضعه الخيار الإفتراضي) عمومًا، ويتميز بسرعة البدء، مما يُعطي الشعور بتجاوب التطبيق، مع تباطؤٍ لطيف في النهاية. توجد مجموعةٌ من المعادلات المعروفة المستخدمة لتنفيذ التحريك مع "تخفيف السرعة نهاية الحركة" والمختلفة عن تلك المحددة بالكلمة المفتاحية ease-out في CSS والتي تتراوح في شدتها. يُمكن استخدام Quintic ease-out للحصول على تأثير "تخفيف السرعة نهاية الحركة". يُمكن معاينة تحريك تخفيف السرعة نهاية الحركة Quintic. يجب الاعتدال في استخدام معادلات التخفيف الأخرى، لا سيما معادلات الارتدادات أو التخفيف المرن، واستخدامها فقط عندما تكون مناسبةً للمشروع؛ فقد تؤدي بعض الأشياء الصغيرة إلى تردِّي تجربة الاستخدام في حالات التحريك السيء المتنافر. إذا لم يكن المرح من أحد أهداف المشروع، فلا يجب إظهار عناصرٍ تتحرك وترتد؛ أما في حال الرغبة بإضفاء جوٍ من المتعة والمرح على التطبيق، يجب استخدام الارتداد بأي طريقة! يجب التجريب واللعب مع طرق التخفيف المختلفة للحكم على الطريقة الأنسب لهوية المشروع. يُمكن الرجوع إلى easings.net لمزيدٍ من التفاصيل. اختيار المدة المناسبة للحركة تُعدّ مسألة اختيار المدّة الصحيحة للحركة من أهم المسائل؛ حيث يُعطي التحريك قصير الأمد شعورًا بالعدوانية والحدّية؛ بينما يصبح التحريك طويل الأمد معرقلًا ومزعجًا. التخفيف الخارج Ease-outs: حوالي 200 إلى 500 ميلي ثانية، حيث تمنح هذه المدّة للعين فرصًة لرؤية التحريك دون أي معوقات. التخفيف الداخل Ease-ins: حوالي 200 إلى 500 ميلي ثانية. يجب الانتباه إلى مسألة السقوط السريع في النهاية مما لا يسمح لتعديلات المدّة بتنعيم الحركة. تأثيرات الارتداد أو المرونة: حوالي 800 إلى 1200 مللي ثانية. يلزم إتاحة الوقت الكافي لاستقرار التأثير المرن أو المرتد. بدون هذا الوقت الإضافي، سيكون الجزء المرتد المرن من التحريك عدوانيًا وغير مريح للعين. ما عرضناه هو مجرد إرشادات، لذلك يجب تجريب طرق التخفيف الممكنة واختيار الأنسب منها للمشروع. ترجمة -وبتصرف- للمقالات التالية: The Basics of Easing للمؤلف: Paul Lewis. Custom Easing للمؤلفين: Paul Lewis و Sam Thorogood. Choosing the Right Easing للمؤلفين: Paul Lewis و Perf Advocate. اقرأ أيضًا المرجع الشامل إلى التحريك عبر CSS أفضل 25 مكتبة تحريك في CSS النسخة العربية الكاملة من كتاب: التحريك عبر CSS
-
تعدّ التقارير والإحصائيات أهم الأدوات المتوفرة في أوبن كارت التي توفر طريقة سهلة لمعرفة أداء المتجر عن طريق حساب وإظهار مجموعة متنوعة من الإحصائيات والملخصات الإجمالية، فيوفر أوبن كارت بشكل افتراضي 12 تقريرًا حول المبيعات والعملاء والشحن وغيرها. يُمكن الانتقال لصفحة "التقارير" من الخيار "التقارير" في لوحة التحكم ثم "التقارير" ثم اختيار التقرير المطلوب من القائمة "اختر نوع التقرير". يسمح الفلتر الموجود يسار الصفحة بفلترة بيانات التقرير. يُمكن أن تختلف حقول الفلتر وفق التقرير إلا أنه يحوي دائمًا حقلي تاريخ بداية وتاريخ نهاية التقرير. نتعرف في هذا المقال على التقارير التي يوفرها متجر أوبن كارت والتي تساعد في عملية التجارة الإلكترونية وإدارة المتجر ومعرفة أدائه لاتخاذ الخطوة المناسبة. هذا المقال جزء من سلسلة تعريفية بلوحة تحكم متجر أوبن كارت، إليك فهرس مقالات كامل السلسلة: مدخل إلى متجر أوبن كارت وكيفية تثبيته إدارة الأقسام والمنتجات في متجر أوبن كارت التعرف على إعدادات واجهة متجر أوبن كارت تعلم كيفية ضبط متجر أوبن كارت شرح الإضافات والقوالب في لوحة تحكم متجر أوبن كارت نظرة على خيارات التسويق التي يوفرها متجر أوبن كارت التقارير والإحصائيات: نافذة على أداء متجر أوبن كارت إعدادات الدفع والشحن في متجر أوبن كارت تقرير المبيعات Orders Report يُعدّ تقرير المبيعات طريقة سهلة لمعرفة مدى جودة أداء المتجر إذ يسمح بمعاينة إيرادات المبيعات لأيام أو أسابيع أو شهور أو سنوات، ويُبين هذا التقرير عدد الطلبيات التي تمت خلال فترة معينة وعدد المنتجات المباعة وإجمالي المبالغ المُحصّلة والضرائب المترتبة. يعرض هذا التقرير الأعمدة التالية: تاريخ البداية Date Start: تاريخ البداية (أول يوم من الأسبوع إذا كان الفرز وفق الأسابيع). تاريخ النهاية Date End: تاريخ النهاية (آخر يوم من الأسبوع إذا كان الفرز وفق الأسابيع). رقم الطلب No. of Orders: عدد الطلبيات من تاريخ البداية إلى تاريخ النهاية. رقم المنتج No. of Products: عدد المنتجات المباعة من تاريخ البداية إلى تاريخ النهاية. الضريبة Tax: مجموع الضريبة المدفوعة من قبل الزبائن. الإجمالي Total: مجموع المبالغ المدفوعة من الزبائن. تقرير الضريبة Tax Report يسمح هذا التقرير بمعاينة الضرائب التي يدفعها الزبائن، ويُبين الضرائب المدفوعة لكل نوع من أنواع الضرائب خلال فترة التقرير. يعرض هذا التقرير الأعمدة التالية: تاريخ البداية Date Start: تاريخ البداية. تاريخ النهاية Date End: تاريخ النهاية. عنوان الضريبة Tax Title: نوع الضريبة. رقم الطلب No. of Orders: عدد الطلبيات من تاريخ البداية إلى تاريخ النهاية. الإجمالي Total: مجموع الضريبة المدفوعة من قبل الزبائن. تقرير الشحن Shipping Report يسمح هذا التقرير بإظهار طرق الشحن المختلفة المُختارة من قبل الزبائن، ويُبين هذا التقرير المبالغ الإجمالية المدفوعة لقاء كل طريقة من طرق الشحن المختلفة خلال مدة التقرير. يعرض هذا التقرير الأعمدة التالية: تاريخ البداية Date Start: تاريخ البداية. تاريخ النهاية Date End: تاريخ النهاية. عنوان الشحن Shipping Title: طريقة شحن المنتجات في الطلبيات الموافقة. رقم الطلب No. of Orders: عدد الطلبيات من تاريخ البداية إلى تاريخ النهاية. الإجمالي Total: مجموع المبالغ المدفوعة لقاء الشحن. تقرير إرجاع المنتجات Returns Report يسمح هذا التقرير بعرض بيانات المرتجعات حيث يعرض عدد طلبات الإرجاع التي تمت خلال فترة التقرير. يعرض هذا التقرير الأعمدة التالية: تاريخ البداية Date Start: تاريخ البداية. تاريخ النهاية Date End: تاريخ النهاية. رقم الإرجاع No. Returns: عدد طلبات الإرجاع بين تاريخ البداية وتاريخ النهاية. تقرير قسائم التخفيض Sale Coupon Report يسمح هذا التقرير بمتابعة استخدام قسائم التخفيض في المتجر. يُبين التقرير إجمالي مبالغ التخفيضات من أجل كل تخفيض مُعرّف في المتجر. يعرض هذا التقرير الأعمدة التالية: اسم التخفيض Coupon name: اسم التخفيض. الرمز Code: رمز التخفيض. الطلبات Orders: عدد الطلبيات التي استخدمت قسيمة التخفيض. الإجمالي Total: المبلغ الإجمالي للتخفيض الناتج (رقم سالب). تقرير المنتجات التي تمت مشاهدتها Products Viewed Report يُعطي هذا التقرير فكرة عن المنتجات الأكثر مشاهدًة، ويعرض هذا التقرير الأعمدة التالية: اسم المنتج Product Name: اسم المنتج. النوع Model: نوع المنتج. عدد المشاهدات Viewed: عدد المشاهدات الكلي للمنتج. النسبة Percentage: النسبة المئوية لمشاهدات هذا المنتج موازنة مع باقي المنتجات. يؤدي النقر على الزر "استعادة الافتراضي" إلى حذف بيانات هذا التقرير والبدء بإحصاء المشاهدات من جديد. يُمكن الاستفادة من هذا التقرير للتعرف على المنتجات ذات المشاهدات القليلة وبالتالي محاولة رفع مشاهداتها عن طريق الإجابة على الأسئلة التالية: هل تم الإعلان عن هذا المنتج على مواقع أخرى؟ هل تم تضمين صورة المنتج في لافتات المنتج على الصفحة الرئيسية؟ هل تمت إضافة المنتجات إلى المنتجات ذات الصلة بصفحة منتج؟ هل تم منحهم سعرًا مخفضًا خاصًا لمجموعة من العملاء من خلال رسالة إخبارية؟ تقرير المنتجات التي تم شراؤها Products purchased report يُعطي هذا التقرير إجماليات المنتجات المباعة. يُبين التقرير الكمية المباعة من كل منتج والمبالغ الإجمالية الناتجة. يعرض هذا التقرير الأعمدة التالية: اسم المنتج Product Name: اسم المنتج. النوع Model: نوع المنتج. الكمية Qty: العدد المباع. الإجمالي Total: الإجمالي. تقرير المتواجدون الآن Customers Online يسمح هذا التقرير بإعطاء فكرة عن تفاعل العملاء الحالي مع صفحات الموقع إذ يُبين العملاء النشطون حاليًا والصفحات التي يتفاعلون معها. يعرض التقرير الأعمدة التالية: الأي بي - IP: عنوان المستخدم الذي يصل منه للمتجر. العميل Customer: اسم العميل. آخر صفحة تم زيارتها Last Page Visited: آخر صفحة زارها العميل. المرجع Referer: الصفحة السابقة المُزارة. آخر نقرة Last Click: تاريخ وتوقيت آخر نقرة للعميل. ملاحظة: لإظهار هذا التقرير، يجب تحديد "نعم" لحقل "المتواجدون الآن" في تبويب خيارات المتجر (من "الضبط" ثم "الإعدادات" ثم تحرير المتجر). تقرير آخر أحداث العملاء Customer Activity يسمح هذا التقرير بمعاينة نشاطات العملاء إذ يُبين نوع نشاط العميل مع تاريخ تسجيله في الموقع. يعرض التقرير الأعمدة التالية: ملاحظات Comment: نوع نشاط العميل. آي بي IP: عنوان العميل. تاريخ التسجيل Registration date: تاريخ التسجيل. تقرير طلبات العملاء Customer Order Reports يسمح هذا التقرير بمعاينة طلبات العملاء. يُبين التقرير عدد طلبات كل عميل والمبلغ الإجمالي الناتج مما يُعطي فكرة واضحة عن كل عميل. يعرض التقرير الأعمدة التالية: اسم العميل Customer Name: اسم العميل. البريد الالكتروني E-Mail: بريد العميل. مجموعة العميل Customer Group: مجموعة العميل. الحالة Status: حالة العميل (مسموح له الدخول للمتجر). رقم الطلب No. Orders: العدد الكلي للطلبيات. رقم المنتج No. Products: العدد الكلي للمنتجات لطلبيات العميل. الإجمالي Total: المبلغ الإجمالي لطلبيات العميل. تقرير نقاط المكافآت للعملاء Customer Reward Points Report يسمح هذا التقرير بمعاينة نقاط مكافآت العملاء إذ يُبين عدد نقاط المكافآت التي حصل عليها كل عميل، إضافًة إلى عدد طلبياته والإجمالي الناتج. يعرض التقرير الأعمدة التالية: اسم العميل Customer Name: اسم العميل. البريد الالكتروني E-Mail: بريد العميل. مجموعة العميل Customer Group: مجموعة العميل. الحالة Status: حالة العميل (مسموح له الدخول للمتجر). نقاط المكافآت Reward Points: مجموع نقاط المكافآت التي حصل عليها العميل. رقم الطلب No. Orders: العدد الكلي للطلبيات. رقم المنتج No. Products: العدد الكلي للمنتجات لطلبيات العميل. الإجمالي Total: المبلغ الإجمالي لطلبيات العميل. تقرير رصيد العميل Customer Credit Report يسمح هذا التقرير بمعاينة أرصدة العملاء إذ يُبين المبلغ الإجمالي لطلبيات كل عميل. يعرض التقرير الأعمدة التالية: اسم العميل Customer Name: اسم العميل. البريد الالكتروني E-Mail: بريد العميل. مجموعة العميل Customer Group: مجموعة العميل. الحالة Status: حالة العميل (مسموح له الدخول للمتجر). الإجمالي Total: المبلغ الإجمالي لطلبيات العميل. خاتمة عرضنا في هذا الدرس للتقارير الإحصائية التي يوفرها أوبن كارت بشكل افتراضي مما يوفر لمدير النظام جميع الاحصائيات اللازمة لإدارة المتجر واتخاذ القرارات المناسبة. نعرض في الدرس القادم لطرق الدفع والشحن المتوفرة في أوبن كارت. اقرأ أيضًا 12 قاعدة بسيطة لتحسين معدلات التحويل إلى مواقع التجارة الإلكترونية أساسيات تمويل المتاجر الإلكترونية اعتماد المنتج وكيف يمكن تحسينه للزيادة من المبيعات كيف تستخدم المحتوى في زيادة مبيعات تجارتك الإلكترونية
-
بعد الانتهاء من الإعدادات الأساسية للمتجر التي عرضناها في دروسنا السابقة، فإن أحد أهم الأمور الواجب تتبعها هو مبيعات المتجر. تتسابق المتاجر المتنافسة في سوق التجارة الإلكترونية لإيجاد الطرق المبتكرة لتحسين المبيعات عن طريق تقديم الحسومات التشجيعية أو عن طريق الحملات الترويجية المختلفة. ترتكز الحملات الترويجية على الويب بشكل أساسي على وضع لافتات إعلانية في مواقع مختلفة ومن ثم تتبع المبيعات الناجمة عنها. يُمكن فهم المطلوب من خلال المثال التالي: لنفترض اقتراب تاريخ مناسبة ما وبأننا نريد الترويج لمنتجات معينة من خلال حملة ترويجية في هذه المناسبة، لذا نُصمم مجموعة من اللافتات الإعلانية لوضعها في مجموعة من مواقع التواصل الاجتماعي تناسب تلك المناسبة بالطبع، لن تعرض مواقع الجهات الخارجية اللافتات مجانًا بل سيتعين على المتجر الدفع وفقًا لشروط الموقع. يكون من المهم جدًا تتبع المبيعات الناتجة عن كل لافتة موضوعة في موقع ما لاتخاذ القرار المناسب بمتابعة الإعلان في هذا الموقع أم لا. يساعد متجر أوبن كارت بإضافة ومتابعة حملات التسويق وهذا ما سنعرضه في مقالنا هذا. هذا المقال جزء من سلسلة تعريفية بلوحة تحكم متجر أوبن كارت، إليك فهرس مقالات كامل السلسلة: مدخل إلى متجر أوبن كارت وكيفية تثبيته إدارة الأقسام والمنتجات في متجر أوبن كارت التعرف على إعدادات واجهة متجر أوبن كارت تعلم كيفية ضبط متجر أوبن كارت شرح الإضافات والقوالب في لوحة تحكم متجر أوبن كارت نظرة على خيارات التسويق التي يوفرها متجر أوبن كارت التقارير والإحصائيات: نافذة على أداء متجر أوبن كارت إعدادات الدفع والشحن في متجر أوبن كارت تتبع نظام التسويق يُستحسن عادًة إنشاء حملة تسويقية جديدة عند إضافة لافتة banner إعلانية للمتجر على أي وسيلة تواصل على الويب وتضمين رابط الحملة URL في اللافتة والذي سيُستخدم لتتبع عدد النقرات ومصدرها. مثلًا: لنفرض أن التسويق (الدعاية) سيبدأ على ثلاث منصات مختلفة، يُمكن إنشاء حملة تسويقية لكل منصة (وتضمين الرابط الموافق في كل منها) مما يسمح بمتابعة النقرات التي تأتي من كل منصة. تُميز كل حملة بشيفرة تتبع مختلفة تُضاف إلى نهاية كل رابط للحملة وهو الأمر الذي يسمح بمتابعة كل حملة، ويُمكن فتح صفحة "تتبع نظام التسويق" من الخيار "التسويق" في "لوحة التحكم" ومن ثم "التسويق": تتضمن صفحة "تتبع نظام التسويق" الحقول التالية: اسم الحملة Campaign Name: يجب كتابة اسم للحملة التسويقية. وصف الحملة Campaign Description: يُمكن كتابة وصف للحملة. شفرة التتبع Tracking Code: تولّد هذه الشفرة تلقائيًا، كما يُمكن تعديلها لوضع رقم مخصص أسهل مما يؤدي إلى تعديل الروابط الظاهرة في الحقل "مثال". مثال Example: تظهر روابط الحملة في هذا الحقل (لاحظ انتهاء الروابط بشفرة التتبع). العمولات Affiliates يهدف نظام العمولة إلى زيادة عدد زوار المتجر وذلك عن طريق منح عمولات للعملاء الذين يُساعدون في توجيه الأشخاص الآخرين إلى زيارة المتجر والشراء منه، حيث يُمنح هؤلاء العملاء العمولات المُحدّدة وذلك لكل حركة مبيع ناجمة عن تحويل تنقلات الأشخاص إلى المتجر. يُمكن إنشاء مجموعات مختلفة من العملاء، ويسمح الخيار "العملاء" من لوحة التحكم ثم "مجموعات العملاء" بالانتقال إلى صفحة "مجموعة العميل" والتي تُظهر مجموعة العملاء الافتراضية "عملاء التجزئة": يُمكن مثلًا إنشاء مجموعة عملاء جديدة ("عملاء العمولة"): نُحدّد نسبة العمولة للعملاء من هذه المجموعة من التبويب "خيارات" في صفحة المتجر الحالي والتي نصل إليها من الخيار "الضبط" في لوحة التحكم ثم "الإعدادات" ثم "المتاجر": لإضافة عميل جديد إلى مجموعة عملاء، يجب الانتقال لصفحة "العملاء" من الخيار "العملاء" في لوحة التحكم ثم "العملاء". تحوي صفحة العملاء تبويبين، الأول هو التبويب "عام" والذي يسمح بإدخال بيانات العميل المختلفة: والثاني هو التبويب "نظام العمولة" والذي يسمح بإدخال تفاصيل العمولة والدفع: يُمكن لزوار المتجر طلب أن يكونوا عملاء وذلك من الخيار "نظام العمولة" تحت "إضافات" في الشريط أسفل واجهة المتجر: يؤدي النقر على "نظام العمولة" إلى فتح صفحة "برنامج نظام العمولة": تُشجع هذه الصفحة زوار المتجر على الاشتراك في نظام العمولة لربح إيرادات عن طريق وضعهم روابط لمنتجات المتجر في صفحات الويب المختلفة التي يملكونها، وسيكسب المشتركون العمولة عند قيام أي شخص وصل للمتجر عن طريق هذه الروابط بإتمام عملية شراء من المتجر. يُمكن التسجيل في نظام العمولة بالنقر على الزر "متابعة" في قسم "تسجيل جديد في نظام العمولة": في حال تسجيل الطلب بنجاح، تظهر الرسالة التالية: سيظهر طلب العميل الجديد لمدير النظام في صفحة " عملاء منتظرين موافقة التسجيل" والتي نصل إليها من الخيار "العملاء" في لوحة التحكم ثم "الموافقة للعملاء". يُمكن بالطبع لمدير المتجر أن يوافق أو يحظر العميل كما يُمكن له أن يُعدّل بياناته. ملاحظة: يجب أن يدخل العميل في حسابه إلى "الدخول لبرنامج نظام العمولة" ومن ثم إلى صفحة "شفرة التتبع في نظام العمولة" لمعرفة شفرة التتبع الخاصة به والتي يجب أن يضيفها إلى كل الروابط التي سيضعها (وبهذا يتمكن أوبن كارت من متابعة روابطه): قسائم التخفيض Coupons يُمكن إنشاء قسائم تخفيض وتخصيصها لمنتجات أو أقسام معينة وذلك كنوع من الدعابة والتسويق، ونفعل ذلك من صفحة "قسيمة التخفيض" والتي نصل إليها من خيار "التسويق" في لوحة التحكم ثم "قسائم التخفيض". يحوي التبويب "عام" في صفحة "قسيمة التخفيض" الحقول التالية: اسم القسيمة Coupon Name: يجب إدخال اسم للقسيمة. الرمز Code: يجب إدخال رمز ما، وهو الرمز الذي سيُدخله العميل للحصول على التخفيض. النوع Type: نسبة مئوية أم رقم ثابت. الخصم Discount: قيمة النسبة المئوية أو قيمة مبلغ الخصم. المبلغ الإجمالي Total Amount: يُمكن تحديد مبلغ يجب الوصول إليه في سلة الشراء للاستفادة من الخصم. تسجيل دخول العميل Customer Login: لتحديد هل يجب أن يقوم العميل بتسجيل الدخول للحصول على الخصم أم لا. شحن مجاني Free Shipping: نعم أم لا. المنتجات Products: يُمكن تحديد المنتجات الممكن استخدام قسيمة التخفيض معها. أما إذا ترك هذا الحقل فارغًا يكون التخفيض صالحًا لجميع المنتجات. الأقسام Category: يُمكن اختيار بعض الأقسام ليكون التخفيض متاحًا لمنتجاتها. تاريخ البداية Date Start: تاريخ بداية صلاحية الكوبون. تاريخ النهاية Date End: تاريخ نهاية صلاحية الكوبون. عدد مرات الاستخدام للكوبون Uses per Coupon: يُمكن تحديد عدد معين أو تركه فارغًا ليكون الكوبون صالحًا للاستخدام عدد غير محدود من المرات. عدد مرات الاستخدام للعميل Uses per Customer: يُمكن تحديد عدد معين أو تركه فارغًا ليكون الكوبون صالحًا للاستخدام من قبل نفس العميل عدد غير محدود من المرات. الحالة Status: تعطيل أم تمكين. يحوي التبويب "السجل" Coupon History في صفحة "قسيمة التخفيض" قائمة بجميع استخدامات الكوبون في المتجر تُظهر الحقول التالية: رقم الطلب OrderID العميل Customer المبلغ Amount تاريخ الإضافة DateAdded يجب على مدير النظام تمكين " قسائم التخفيض" في واجهة المتجر وذلك من الخيار "الإضافات" في لوحة التحكم ثم "الإضافات" ثم اختيار من القائمة " اختيار نوع الإضافة " الخيار "إجماليات الطلب" يُمكن للعميل استخدام قسيمة تخفيض من واجهة المتجر وذلك بإدخال رقم قسيمة التخفيض بعد إضافة منتج إلى سلة الشراء: ومن ثم النقر على الزر "اعتمد التخفيض" مما يؤدي إلى تخفيض الإجمالي: البريد Mail تُستخدم هذه الميزة لإرسال رسائل إخبارية أو معلومات عن العروض الخاصة أو لتوصيل أي نوع من معلومات المتجر لمجموعات مختارة من العملاء. يُمكن فتح صفحة "إرسال بريد" من الخيار "التسويق" ثم "إرسال بريد": خاتمة عرضنا في هذا الدرس للإمكانات المختلفة التي يوفرها أوبن كارت من أجل عملية التسويق وتتبع الحملات الترويجية. نعرض في الدرس القادم التقارير الكثيرة التي يوفرها أوبن كارت مما يسمح بالحصول على مختلف المعلومات والإحصائيات المطلوبة لإدارة المتجر. اقرأ أيضًا عناصر التصميم التسويقية التي يحتاجها كل موقع تجارة إلكترونية كيف تزيد مبيعات متجرك اﻹلكتروني باستخدام حملات التسويق بالبريد اﻹلكتروني التسويق والمزيج التسويقي لتوضيح رؤيتك ومهمتك وأهدافك لمحة عامة عن الإعلانات الإلكترونية
-
يلعب التحريك Animation دورًا كبيرًا في رفع جاذبية تطبيقات ومواقع الويب للمستخدمين الذين أصبحوا يتوقعون دومًا الحصول على واجهات استخدام تفاعلية عالية التجاوب؛ إلا أن تحريك واجهات الاستخدام ليس أمرًا مباشرًا وسهلًا، حيث يستلزم تحديد ما يجب تحريكه وما تأثير هذا التحريك على انطباع وتجربة المستخدمين. يُستخدم التحريك لإضفاء الحياة على المشاريع. يجب أن يدعم التحريك تفاعل المستخدم. يجب الانتباه لتكلفة تحريك الخصائص والتي قد تختلف من خاصيةٍ لأخرى. أساسيات التحريك نعرض فيما يلي أهم القضايا الواجب الانتباه إليها عند التحريك: اختيار الخصائص المناسبة للتحريك يُضيف التحريك كثيرًا من المتعة للمستخدمين ويرفع من تفاعلهم مع المشروع؛ حيث يُمكن عمليًا تحريك أي شيء، مثل العرض والارتفاع والموضع والألوان والخلفيات؛ ولكن يجب الانتباه في نفس الوقت إلى تأثيرات التحريك على الأداء وانعكاساتها على هوية التطبيق، حيث يُمكن أن يؤثر التحريك المتقطع أو المُختار بصورةٍ سيئة على تردِّي تجربة الاستخدام مما يستلزم الانتباه جيدًا إلى حُسن اختيار التحريك المُناسب والفعّال. استخدام التحريك لدعم التفاعل يجب استخدام التحريك بصورةٍ مدروسة بهدف تعزيز تفاعل المستخدمين (وليس فقط لمجرد إمكانية التحريك)، وتجنبًا لمضايقتهم أو إعاقتهم. يُمكن مثلًا استخدام توهجٍ خفيف، أو حركة ارتدادٍ بسيطة لإعلام المستخدم بتلَقّي أفعاله، مثل النقر على أيقونة قائمة، أو السحب لفتح شريط تمرير، أو النقر على زر. يجب تجنُّب التحريك الذي يقطع أو يُعرقل نشاط المستخدم دون أي داعٍ. تجنب تحريك الخصائص المكلفة يُعدّ التحريك الذي يؤدي إلى تقطُّعاتٍ في الصفحة من أسوأ أنواع التحريك، والذي يُحبط المستخدمين ويُشعرهم بعدم الرضا لدرجة أنهم يتمنون بألّا يوجد أي تحريكٍ على الإطلاق. يُمكن أن تكون بعض الخصائص أكثر تكلفةً من غيرها عند تغييرها، كما يُمكن أن يؤدي هذا التغيير إلى ظهور التقطُّعات في الصفحة؛ حيث يُمكن مثلًا أن يتطلب تغيير ظل صندوق box-shadow لعنصرٍ ما عملية طلاء paint أكثر تكلفةً بكثير من تغيير لون نصه. وبالمثل، من المرجح أن يكون تغيير عرض width عنصر ما أكثر تكلفةً من تغيير تحويلاته transform. نعرض المزيد من الإرشادات حول أداء التحريك في الفقرة الأخيرة من هذه المقالة. يُمكن الالتزام فقط بالتحويلات transforms وتعديلات الشفافية opacity واستخدام "سوف يُعدّل" will-change في حال عدم الرغبة بقراءة المزيد والخوض في التفصيلات. يُمكن معرفة ماذا ينشُط تمامًا عند تحريك أي خاصية بالرجوع إلى مُشغّلات أنماط CSS. التحريك باستخدام أنماط CSS موازنة مع استخدام JavaScript يُمكن التحريك، إما باستخدام أنماط CSS، أو JavaScript؛ حيث يعتمد قرار الاختيار بين واحدٍ منهما على الارتباطات الأخرى للمشروع وعلى أنواع التأثيرات المطلوبة. يُستخدم تحريك CSS لتنفيذ الانتقالات البسيطة من النمط "لقطة واحدة one-shot"، مثل تبديل حالات عناصر الواجهة. يُستخدم تحريك JavaScript للحصول على تأثيراتٍ متقدمة، مثل الارتداد أو التوقف أو الإيقاف المؤقت أو الإرجاع أو الإبطاء. يُمكن استخدام واجهة برمجة التطبيقات للتحريك Web Animations API أو أي إطار عمل حديث مناسب عند اختيار التحريك باستخدام JavaScript. يُمكن إنشاء معظم عمليات التحريك الأساسية باستخدام CSS أو JavaScript، لكن يختلف الجهد والزمن اللازمين لإنشاء التحريك حسب الطريقة المختارة (راجع الفقرة الأخيرة من هذه المقالة)؛ حيث يوجد لكل طريقةٍ محاسنها ومساوئها، نعرض فيما يلي الإرشادات العامة: تُستخدم CSS عندما يكون لعناصر الواجهة حالات أقل محتواة ضمن نفس العنصر؛ حيث تكون الانتقالات والتحريك مثالية لجلب قائمة انتقال إلى جهةٍ معينة مثلًا أو إظهار تلميحٍ ما. يُمكن اللجوء إلى JavaScript للتحكم بالحالات إلا أن التحريك نفسه يكون في CSS. تُستخدم JavaScript عند الحاجة للتحكم الواسع في التحريك. تُعدّ واجهة برمجة التطبيقات Web Animations API المنهج المُعتمد على المعايير القياسية والمتاح حاليًا في معظم المتصفحات الحديثة، مما يوفر كائناتٍ حقيقية مثالية للتطبيقات المعقدة الموجهة بالكائنات. تُعدّ JavaScript مفيدةً أيضًا عند الحاجة إلى إيقاف التحريك، أو إيقافه مؤقتًا، أو إبطائه، أو عكسه. يُمكن استخدام إطار التحريك للطلب requestAnimationFrame مباشرًة عند الحاجة لتنسيق مشهدٍ كاملٍ يدويًا. يُعدّ ذلك منهجًا متقدمًا في JavaScript، إلا أنه يكون مفيدًا عند إنشاء لعبة أو الرسم على لوحة HTML canvas. بالمقابل، في حال استخدام إطار عمل JavaScript الذي يتضمن وظائف التحريك، مثل دالة التحريك .animate() في jQuery، فقد يكون من الأنسب الالتزام بذلك في التحريك عمومًا. التحريك باستخدام CSS يُعدّ التحريك باستخدام CSS أبسط طرق تحريك شيءٍ ما على الشاشة، حيث يوصف هذا الأسلوب بأنه تصريحي لأنه يُحدّد ما المطلوب حدوثه. يُبين المثال التالي تحريك صندوقٍ باستخدام CSS بمقدار 100px في كلا المحورين X و Y، حيث ضُبط زمن الانتقال ليأخذ 500 ميلي ثانية (نصف ثانية). تتغير القيمة transform عند إضافة الصف move ويبدأ الانتقال. .box { transform: translate(0, 0); transition: transform 500ms; } .box.move { transform: translate(100px, 100px); } يُمكن تجريب المثال. يوجد إضافًة إلى مدة الانتقال خياراتٍ للتخفيف easing، والتي تُساهم في جعل التحريك يبدو طبيعيًا. يُمكن الرجوع إلى أساسيات التخفيف لمزيدٍ من التفاصيل. في حال إنشاء صفوفٍ مستقلة في CSS لإدارة التحريك كما هو الحال في المثال أعلاه، يُمكن استخدام JavaScript لتبديل حالة التحريك نعم/لا on/off. box.classList.add('move'); يوفِّر ذلك توازنًا جيدًا للتطبيقات؛ إذ يُمكن للمطور التركيز على إدارة الحالة باستخدام JavaScript، وتعيين الصفوف المناسبة للعناصر المستهدفة ببساطة، وترك المتصفح يتعامل مع التحريك. يُمكن في حال اعتماد هذا المنهج الاستماع إلى أحداث نهاية الانتقال transitionend للعنصر، وذلك في حال قبول التخلي عن دعم الإصدارات الأقدم من Internet Explorer، حيث كان الإصدار 10 هو الإصدار الأول لدعم هذه الأحداث. دعمت جميع المتصفحات الأخرى هذه الأحداث منذ فترة. تكون شيفرة JavaScript المطلوبة للاستماع إلى حدث انتهاء الانتقال كما يلي: var box = document.querySelector('.box'); box.addEventListener('transitionend', onTransitionEnd, false); function onTransitionEnd() { //معالجة إنهاء الانتقال } يُمكن استخدام التحريك في CSS إضافًة إلى استخدام الانتقالات للحصول على مزيدٍ من التحكم في الإطارات الرئيسية للتحريك الفردي والمُدّد الزمنية والتكرارات. ملاحظة: يُعدّ الإطار الرئيسي keyframe مصطلحًا قديمًا من مصطلحات الرسوم المتحركة المرسومة يدويًا. يُنشئ رسامو الرسوم المتحركة إطاراتٍ مُحدّدةً لجزءٍ من العمل، تُدعى الإطارات الرئيسية، والتي من شأنها أن تلتقط أشياءً مثل الجزء الأكثر تطرفًا في حركةٍ ما، ثم يشرعون في رسم جميع الإطارات الفردية بين الإطارات الرئيسية. يسلك التحريك في CSS سلوكًا مشابهًا؛ حيث يُعلَم المتصفح ببعض قيم خصائص CSS في نقاط مُحدّدة ويُطلب منه ملء القيم الناقصة. يُمكن مثلًا تحريك صندوق المثال السابق بنفس الطريقة مع انتقالات وبتكرارٍ لا نهائي، ولكن بدون أي تفاعلٍ للمستخدم مثل النقر. كما يُمكن تغيير عدة خصائص في نفس الوقت: .box { /* اختيار التحريك */ animation-name: movingBox; /* مدّة التحريك */ animation-duration: 1300ms; /* عدد مرات التحريك */ animation-iteration-count: infinite; /* تبديل اتجاه التحريك عند كل دورة فردية */ animation-direction: alternate; } @keyframes movingBox { 0% { transform: translate(0, 0); opacity: 0.3; } 25% { opacity: 0.9; } 50% { transform: translate(100px, 100px); opacity: 0.2; } 100% { transform: translate(30px, 30px); opacity: 0.8; } } يُمكن تجريب المثال. يُمكن تعريف التحريك نفسه بصورةٍ مستقلة عن العنصر الهدف، ويُمكن استخدام خاصية اسم التحريك animation-name لاختيار التحريك المطلوب. يجب إضافة بادئات البائع vendor prefixes إذا أردنا أن يعمل تحريك CSS على المتصفحات القديمة. ويُمكن للعديد من الأدوات أن تُساعد في إنشاء إصدارات CSS مع البادئة المطلوبة، مما يسمح للمطوّر بكتابة الإصدار دون البادئات في ملفات المصدر الخاصة به. التحريك باستخدام JavaScript وواجهة برمجة التطبيقات Web Animations API يُعدّ إنشاء التحريك باستخدام JavaScript أكثر تعقيدًا موازنًة مع كتابة الانتقالات أو التحريك في CSS، إلا أنه يوفر قوةً أكبر للمطورين. يُمكن استخدام واجهة برمجة التطبيقات Web Animations API إما لتحريك خصائص CSS معينة، أو لإنشاء كائناتٍ ذات تأثيرات مركبة. يكون استخدام JavaScript للتحريك حتميًا مع كتابة التعليمات سطريًا inline ضمن الشيفرة، كما يُمكن تغليفها داخل كائناتٍ أخرى. تُبيّن الشيفرة التالية كيفية إنشاء نفس تحريك CSS المُوضح في المثال السابق: var target = document.querySelector('.box'); var player = target.animate([ {transform: 'translate(0)'}, {transform: 'translate(100px, 100px)'} ], 500); player.addEventListener('finish', function() { target.style.transform = 'translate(100px, 100px)'; }); تنحصر المهمة الأساسية للتحريك باستخدام Web Animation في تعديل كيفية تقديم وعرض العنصر للمستخدم؛ أما في حال الرغبة ببقاء العنصر في المكان الذي انتقل إليه، فيجب تعديل أنماطه عند انتهاء التحريك كما في المثال السابق. تُعدّ واجهة برمجة التطبيقات Web Animations API معيارًا جديدًا نسبيًا من W3C، وهو مدعومٌ بصورةٍ أساسية في معظم المتصفحات الحديثة؛ أما بالنسبة للمتصفحات الحديثة غير الداعمة، فيُمكن استخدام المشروع من النوع "نقص الدعم" polyfill المُتاح على github؛ وهو مشروع JavaScript يوفر ميزات Web Animation. توفّر JavaScript للمطور تحكمًا كاملًا في أنماط العنصر عند أي خطوة؛ أي أنه يُمكن إبطاء التحريك أو إيقافه مؤقتًا أو توقيفه أو عكسه من خلال التعامل مع العناصر بصورةٍ مناسبة، ويكون هذا مفيدًا جدًا في بناء التطبيقات المعقدة كائنية التوجه؛ حيث يتمكن المطور من تغليف سلوك التحريك بصورةٍ مناسبة. التحريك والأداء يجب الحفاظ على 60 إطارًا في الثانية عند التحريك دومًا؛ حيث تؤدي أي قيمةٍ أقل من ذلك إلى ظهور التقطيع، أو توقُّف التحريك واللذان يكونان واضحين للمستخدمين مما يؤدي إلى تردّي تجربة الاستخدام. يجب الحرص على ألّا يُسبب التحريك أية مشاكل في الأداء؛ حيث يجب معرفة تأثير أي خاصية في أنماط CSS على الأداء. يجب الانتباه إلى أن جميع الخصائص التي تُغيُّر في هندسة الصفحة (التخطيط) أو تتسب في الطلاء تكون مُكلفةً على نحوٍ خاص. يجب الالتزام بتعديل التحويلات والشفافية ما أمكن ذلك. يُمكن استخدام سوف يُعدّل will-change للتأكد من معرفة المتصفح ما يُخطط لتحريكه. لا يكون تحريك الخصائص مجاني، كما أن تحريك بعض الخصائص أقل كلفةً من غيرها؛ حيث يُعدّل مثلًا تحريك العرض width والارتفاع height لعنصرٍ من هندسته، ويُمكن أن يؤدي ذلك إلى تحريك أو تغيير حجوم عناصرٍ أخرى على الصفحة. تُدعى هذه العملية بالتخطيط أو إعادة التدفق في بعض المتصفحات مثل Firefox المعتمدة على محرك المتصفحات Gecko؛ وهي عمليةٌ مكلفةٌ لاسيما إذا احتوت الصفحة على عناصر كثيرة. كلما يُشغّل التخطيط تحتاج الصفحة أو جزءٌ منها إلى إعادة الطلاء والذي يكون أكثر كلفًة من عملية التخطيط نفسها. يجب تجنُّب تحريك الخصائص التي تؤدي إلى تنشيط التخطيط أو الطلاء ما أمكن ذلك؛ وهذا يعني قصر التحريك على الشفافية opacity أو التحويلات transform بالنسبة لمعظم المتصفحات الحديثة، واللتان يتمكن المتصفح من تحسينها بدرجة عالية. لا يُشكّل التعامل مع التحريك باستخدام JavaScript أو CSS فرقًا بالنسبة للأداء. يُمكن الرجوع إلى CSS Triggers للحصول على قائمةٍ كاملة لما يُنشّط تشغيله عند استخدام خصائص CSS الفردية، كما يُمكن الرجوع للمرجع الكامل لإنشاء تحريك عالي الأداء في عناصر HTML5. استخدام خاصية will-change تُعلّم الخاصية will-change المتصفح بالنية في تعديل خاصية عنصر، مما يسمح للمتصفح بوضع التحسينات الأكثر ملاءمةً في مكانها قبل إجراء التعديل. ومع ذلك، لا يجب الإفراط في استخدام الخاصية will-change؛ لأن ذلك يؤدي إلى إضاعة الموارد ومزيدًا من مشاكل الأداء. تنص أحد القواعد التجريبية الأساسية على أنه إذا كان تنشيط التحريك سيبدأ خلال 200 ميلي ثانية القادمة، إما عن طريق تفاعل المستخدم أو بسبب حالة التطبيق، فإن وضع will-change يُعدّ فكرةً جيدة. يجب تمكين will-change في معظم الحالات لكل خاصيةٍ يُخطط لتحريكها لاحقًا. فعلى سبيل المثال، ستكون إضافة will-change للتحويلات والشفافية في أمثلتنا السابقة على النحو التالي: .box { will-change: transform, opacity; } ستُجري المتصفحات التي تدعم هذه الخاصية (حاليًا معظم المتصفحات الحديثة) التحسينات المناسبة في الخلفية لدعم تعديل هذه الخصائص أو تحريكها. أداء CSS موازنة مع أداء JavaScript يوجد العديد من الصفحات والتعليقات في عالم الويب التي تناقش المزايا النسبية للتحريك باستخدام CSS و JavaScript من منظور الأداء. فيما يلي بعض النقاط التي يجب الانتباه لها: يُدعَم التحريك المعتمد على أنماط CSS و Web Animations بصورةٍ أساسية ويُعالج ضمن خيطٍ thread منفصل يُعرف باسم "الخيط المُركَّب compositor thread"؛ والذي يختلف عن "الخيط الرئيسي main thread" للمتصفح، الذي يُنفذّ التصميم والتخطيط والطلاء وسكريبت جافا؛ مما يعني أنه إذا شغَّل المتصفح بعض المهام المكلفة على الخيط الرئيسي، يبقى التحريك مستمرًا دون أي مقاطعة. يُمكن في كثيرٍ من الحالات معالجة التعديلات الأخرى على التحويلات والشفافية باستخدام الخيط المُركّب. إذا أدى أي تحريكٍ إلى تشغيل الطلاء أو التخطيط أو كليهما، فسيُعهد إلى "الخيط الرئيسي" مهمة تنفيذ العمل وذلك في حالة التحريك المُستند إلى CSS أو JavaScript. يُمكن أن يؤدي الحمل الزائد للتخطيط أو الطلاء إلى بطء أي عملٍ مرتبطٍ بتنفيذ CSS أو JavaScript، مما يجعل المسألة موضع نقاش. يُمكن العودة إلى CSS Triggers لمزيدٍ من المعلومات حول العمل المُنّشط عند تحريك خاصيةٍ ما. ترجمة -وبتصرف- للمقالات التالية: Animations للمؤلف: Paul Lewis. CSS Versus JavaScript Animations للمؤلفين: Paul Lewis و Sam Thorogood. Animations and Performance للمؤلفين: Paul Lewis و Sam Thorogood. اقرأ أيضًا أيّهما أفضل للتحريك Animations؟ جافاسكربت أم CSS؟ خاصيات الحركات الحركات المتعددة المتزامنة الانتقالات وجافاسكربت
-
تُعدّ مسألة تصنيف العملاء أي تجزئتهم إلى مجموعات متشابهة في سلوكها (عمليات الشراء والتسوق) من المسائل الهامة في عالم التسويق وذلك بهدف إعداد حملات تسويقية مختلفة مناسبة لكل مجموعة من المجموعات المُستهدفة. سنعرض في هذه المقالة استخدام خوارزميات العنقدة Clustering لاستكشاف مجموعات العملاء أو الزبائن المختلفة، ويُمكن تنزيل بيانات التدريب والشيفرة البرمجية من الملف المضغوط (والذي تجده أيضًا بنهاية المقال)، لتتمكن من فهم المحتوى أكثر. نستخدم في هذه المقالة التعليمية مجموعة بيانات حول 200 زبون تتألف من عمودين: الدخل السنوي للزبون بآلاف الدولارات Annual Income. تقييم الزبون Spending Score وهو رقم يتراوح بين 1 و 100 ويعكس مدى ولاء الزبون للمتجر والمبالغ التي أنفقها في الشراء منه (100 يعني الزبون الأكثر انفاقًا). يُمكن تنزيل هذه البيانات المتاحة على موقع Kaggle أو من الرابط هنا. ما هي العنقدة Clustering العنقدة هي عملية تجزئة (تقسيم) مجموعة من البيانات إلى عناقيد clusters (مجموعات) وبحيث تكون العناصر الموجودة في عنقود واحد متشابهة فيما بينها وأقل تشابهًا مع عناصر العناقيد الأخرى. تندرج خوارزميات العنقدة ضمن خوارزميات التعلم الآلي المدعوة "ليست تحت الإشراف" unsupervised بمعنى أن البيانات المُقدّمة في البداية لا تحوي أي تسميات labels أو تصنيفات بشكل مُسبق. سنرى مثًلا أن مسألة تحديد عدد العناقيد هو مسألة مهمة يجب الاعتناء بها إذ لا نعرف مُسبقًا ما هو عدد العناقيد الأمثلي. نعرض في هذه المقالة نوعين أساسيين من خوارزميات العنقدة: خوارزميات التجزئة Partitioning: تبدأ هذه الخوارزميات بتجزئة عناصر البيانات إلى k عنقود (مختارة بشكل عشوائي) ومن ثم تُكرر تعديل هذه المجموعات وصولًا إلى حل جيد. من أشهر هذه الخوارزميات الخوارزمية المدعوة k-means (أي k وسطي). الخوارزميات التكتلية Agglomerative: تبني هذه الخوارزمية هرمية من العناقيد حيث تبدأ بوضع كل عنصر من عناصر البيانات في عنقود مستقل ثم تكرر دمج العناقيد المتشابهة وصولًا إلى عنقود واحد في نهاية المطاف. الخوارزمية K-Means تُعدّ الخوارزمية K-Means من أشهر وأبسط خوارزميات العنقدة بالتجزئة: دخل الخوارزمية: عدد العناقيد المطلوب k بيانات التدريب وهي عبارة عن مجموعة من العناصر (أشعة رقمية): {x1, x2, . . . , xN} حيث xi هو شعاع من الأرقام. خرج الخوارزمية: تُسندّ الخوارزمية كل عنصر من عناصر الدخل إلى أحد العناقيد (التي عددها k). المعالجة: تختار الخوارزمية أولًا k شعاع من أشعة الدخل بشكل عشوائي كمراكز العناقيد. تُكرر الخوارزمية ما يلي وصولًا إلى التقارب: إسناد كل شعاع من أشعة الدخل إلى المركز الأقرب حساب المركز الجديد لكل عنقود يعني التقارب عدم انتقال أي شعاع من عنقوده الحالي الموضوع فيه إلى عنقود آخر. يُبين الشكل التالي المراحل الأساسية للخوارزمية: لفهم مراحل الخوارزمية نعرض أولًا خطوات تنفيذها على المثال التعليمي التالي: ليكن لدينا مجموعة العناصر العشرة التالية: D = { (5,3), (10,15), (15,12), (24,10), (30,45), (85,70), (71,80), (60,78), (55,52), (80,91) } وبفرض أننا نريد تقسيمها إلى عنقودين (k=2). لنختار مثلًا العنصر الأول كمركز للعنقود الأول والعنصر الثاني مركزًا للعنقود الثاني أي: c1(x) = 5, c1(y)=3 c2(x) = 10 , c2(y)=15 نحسب الآن بُعد (المسافة الإقليدية euclidean distance) كل عنصر من عناصر البيانات عن كل من المركزين ونُسند العنصر إلى المركز الأقرب. يكون لدينا: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } رقم العنصر المسافة الإقليدية عن المركز الأول المسافة الإقليدية عن المركز الثاني العنقود المُسند إليه 1 (5,3) 0 13 C1 2 (10,15) 13 0 C2 3 (15,12) 13.45 5.83 C2 4 (24,10) 20.24 14.86 C2 5 (30,45) 48.87 36 C2 6 (85,70) 104.35 93 C2 7 (71,80) 101.41 89 C2 8 (60,78) 93 80 C2 9 (55,52) 70 58 C2 10 (80,91) 115.52 103.32 C2 نحسب الآن مركزي العنقودين فنحصل على: c1(x) = 5, c1(y)=3 c2(x) = (10 + 15 + 24 + 30 + 85 + 71 + 60 + 55 + 80) / 9 = 47.77 c2(y) = (15 + 12 + 10 + 45 + 70 + 80 + 78 + 52 + 91) / 9 = 50.33 نُعيد العملية لنحصل على: رقم العنصر المسافة الإقليدية عن المركز الأول المسافة الإقليدية عن المركز الثاني العنقود المُسند إليه 1 (5,3) 0 63.79 C1 2 (10,15) 13 51.71 C1 3 (15,12) 13.45 50.42 C1 4 (24,10) 20.24 46.81 C1 5 (30,45) 48.87 18.55 C2 6 (85,70) 104.35 42.1 C2 7 (71,80) 101.41 37.68 C2 8 (60,78) 93 30.25 C2 9 (55,52) 70 7.42 C2 10 (80,91) 115.52 51.89 C2 نحسب الآن مركزي العنقودين الجديدين فنحصل على: c1(x) = (5, 10, 15, 24) / 4 = 13.5 c1(y) = (3, 15, 12, 10) / 4 = 10.0 c2(x) = (30 + 85 + 71 + 60 + 55 + 80) / 6 = 63.5 c2(y) = (45 + 70 + 80 + 78 + 52 +91) / 6 = 69.33 نُعيد العملية مرة أخرى لنحصل على: رقم العنصر المسافة الإقليدية عن المركز الأول المسافة الإقليدية عن المركز الثاني العنقود المُسند إليه 1 (5,3) 11.01 88.44 C1 2 (10,15) 6.1 76.24 C1 3 (15,12) 2.5 75.09 C1 4 (24,10) 10.5 71.27 C1 5 (30,45) 38.69 41.4 C1 6 (85,70) 93.33 21.51 C2 7 (71,80) 90.58 13.04 C2 8 (60,78) 82.37 9.34 C2 9 (55,52) 59.04 19.3 C2 10 (80,91) 104.8 27.23 C2 نحسب الآن مركزي العنقودين الجديدين فنحصل على: c1(x) = (5, 10, 15, 24, 30) / 5 = 16.8 c1(y) = (3, 15, 12, 10, 45) / 5 = 17.0 c2(x) = (85 + 71 + 60 + 55 + 80) / 5 = 70.2 c2(y) = (70 + 80 + 78 + 52 + 91) / 5 = 74.2 نُعيد العملية فلا يتغير إسناد أي عنصر مما يعني التقارب وثبات المراكز والعناقيد clusters. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن إعداد المشروع يحتاج تنفذ شيفرات هذه المقالة بيئةً برمجيةً للغة بايثون الإصدار 3.8. ويجب أن تتضمن هذه البيئة البرمجية مدير الحِزم pip لتثبيت الحِزم، ومُنشئ البيئات الافتراضية venv لإنشاء بيئاتٍ افتراضيةٍ. نستخدم محرر الشيفرات البرمجية Jupyter Notebooks، وهو مفيد جدًا لتجربة وتشغيل الأمثلة البرمجية بطريقةٍ تفاعليةٍ، حيث نستطيع من خلاله تشغيل كتلًا صغيرةً من الشيفرات البرمجية ورؤية النتائج بسرعة، مما يُسهّل علينا اختبار الشيفرات البرمجية وتصحيحها. نحتاج أولًا لتثبيت بعض التبعيات، وذلك لإنشاء مساحة عملٍ للاحتفاظ بملفاتنا قبل أن نتمكن من تطوير برنامجنا. نُنشئ مجلدًا جديدًا خاصًا بمشروعنا وندخل إليه هكذا: mkdir clustering cd clustering نُنفذّ الأمر التالي لإنشاء البيئة الافتراضية: python -m venv clustering ومن ثم الأمر التالي في Linux لتنشيط البيئة الافتراضية: source clustering/bin/activate أما في Windows، فيكون أمر التنشيط: "clustering/Scripts/activate.bat" نستخدم إصداراتٍ محددةٍ من المكتبات اللازمة، من خلال إنشاء ملف requirements.txt في مجلد المشروع، وسيُحدِّد هذا الملف المتطلبات والإصدارات التي سنحتاج إليها. نفتح الملف requirements.txt في محرر النصوص، ونُضيف الأسطر التالية، وذلك لتحديد المكتبات التي نريدها وإصداراتها: jupyter==1.0.0 numpy==1.21.5 scikit-learn==1.0.1 scipy==1.7.3 pandas==1.3.5 matplotlib==3.5.1 نحفظ التغييرات التي طرأت على الملف ونخرج من محرر النصوص، ثم نُثَبت هذه المكتبات بالأمر التالي: (clustering) $ pip install -r requirements.txt بعد تثبيتنا لهذه التبعيات، نُصبح جاهزين لبدء العمل على مشروعنا. كتابة شيفرة تطبيق العنقدة للعملاء نُشغّل محرر الشيفرات البرمجية Jupyter Notebook بمجرد اكتمال عملية التثبيت. هكذا: (clustering) $ jupyter notebook ثم نُنشئ ملفًا جديدًا في داخل المحرر ونُسمّه باسم clust مثلًا. تنفيذ المثال التعليمي نبدأ أولًا بإنشاء بيانات المثال التعليمي السابق ورسمها باستخدام المكتبة matplotlib: # المكتبة الرقمية import numpy as np # مكتبة الرسم import matplotlib.pyplot as plt # إنشاء البيانات X = np.array([[5,3], [10,15], [15,12], [24,10], [30,45], [85,70], [71,80], [60,78], [55,52], [80,91],]) # الرسم plt.scatter(X[:,0],X[:,1]) plt.show() مما يُظهر: تُبين الشيفرة التالية استخدام الصف KMeans من مكتبة العنقدة sklearn.cluster. نُنشئ أولًا غرض (نموذج model) من هذا الصف مع تحديد عدد العناقيد المطلوبة. تُنفذّ الطريقة fit خوارزمية KMeans على بيانات التدريب لإيجاد العناقيد المطلوبة. تُرقّم الخوارزمية العناقيد بدءًا من الصفر (تسميات labels). يُمكن طبعًا طباعة مراكز العناقيد. # KMeans from sklearn.cluster import KMeans # إنشاء غرض من الصف # تحديد عدد العناقيد المطلوب kmeans = KMeans(n_clusters=2) # الملائمة مع البيانات kmeans.fit(X) # طباعة المراكز print(kmeans.cluster_centers_) # طباعة تسميات العناقيد print(kmeans.labels_) يكون الخرج: [[70.2 74.2] [16.8 17. ]] [1 1 1 1 1 0 0 0 0 0] يُمكن الآن استخدام النموذج المُتعلم السابق للتنبؤ بعنقود أي مثال جديد وذلك باستخدام الطريقة predict كما تُبين الشيفرة التالية: # التنبؤ print(kmeans.predict([[10,10]])) حيث يكون الخرج مثلًا: [1] يُمكن أيضًا رسم نقاط التدريب مع مراكزها بلون مميز كما تُبين الشيفرة التالية: # الرسم مع المراكز plt.scatter(X[:,0],X[:,1], c=kmeans.labels_, cmap='rainbow') plt.scatter(X[:,0], X[:,1], c=kmeans.labels_, cmap='rainbow') plt.scatter(kmeans.cluster_centers_[:,0] ,kmeans.cluster_centers_[:,1], color='black') يكون الخرج: ننتقل الآن لمعالجة مسألتنا الأساسية وهي عنقدة الزبائن. تعرض الشيفرة التالية تحميل البيانات من الملف shopping-data.csv ووضعها في إطار بيانات من المكتبة pandas. # مكتبة إطار البيانات import pandas as pd # تحميل البيانات customer_data = pd.read_csv('shopping-data.csv') # إظهار ترويسة البيانات customer_data.head() تظهر أوائل البيانات: نحذف في الشيفرة التالية رقم الزبون من إطار البيانات كي لا يدخل في عملية حساب العناقيد. ثم نُنشئ نموذجًا متعلمًا من الصف KMeans مع عدد العناقيد مساويًا لخمسه (نعرض لاحقًا كيفية تحديدنا لهذا الرقم): # حذف رقم الزبون data = customer_data.iloc[:, 1:3].values # إنشاء النموذج المتعلم kmeans = KMeans(n_clusters=5) # الملائمة مع البيانات kmeans.fit(data) # طباعة المراكز print(kmeans.cluster_centers_) # طباعة التسميات print(kmeans.labels_) يكون الإظهار: [[88.2 17.11428571] [55.2962963 49.51851852] [25.72727273 79.36363636] [86.53846154 82.12820513] [26.30434783 20.91304348]] [4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 2 4 1 4 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 0 3 1 3 0 3 0 3 1 3 0 3 0 3 0 3 0 3 1 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3 0 3] يُمكن الآن أن نرسم النقاط مع المراكز باستخدام الشيفرة التالية: # الرسم plt.scatter(data[:,0],data[:,1], c=kmeans.labels_, cmap='rainbow') plt.scatter(data[:,0], data[:,1], c=kmeans.labels_, cmap='rainbow') plt.scatter(kmeans.cluster_centers_[:,0] ,kmeans.cluster_centers_[:,1], color='black') plt.show() مما يُعطي: تفسير نتائج العنقدة تقييمها يُمكن لنا بمعاينة الشكل السابق استنتاج ما يلي (وهو الهدف الأساسي من عملية العنقدة): الزبائن في أعلى اليمين (نقاط البيانات الصفراء) هم الزبائن ذوو الرواتب المرتفعة والإنفاق المرتفع. هؤلاء هم الزبائن الواجب استهدافهم دومًا والمحافظة عليهم. الزبائن في أعلى اليسار (نقاط البيانات الخضراء) هم الزبائن ذوو الرواتب المنخفضة والإنفاق المرتفع. هؤلاء هم الزبائن الواجب العناية بهم واستهدافهم بحملات التخفيضات مثلًا. الزبائن في أسفل اليمين (نقاط البيانات البنفسجية) هم الزبائن ذوو الرواتب المرتفعة والإنفاق المنخفض. هؤلاء هم الزبائن الواجب جذبهم بالطرق التسويقية ما أمكن ذلك. الزبائن في أسفل اليسار (نقاط البيانات الحمراء) هم الزبائن ذوو الرواتب المنخفضة والإنفاق المنخفض. لا داع لإضاعة الكثير من الوقت والجهد معهم. الزبائن في الوسط (نقاط البيانات الزرقاء) هم الزبائن أصحاب الدخل المتوسط والإنفاق المتوسط. يُمكن استهدافهم أيضًا لاسيما أن عددهم كبيرًا كما يُبين الشكل السابق. يُمكن تقييم نتائج العنقدة باستخدام المعامل المدعو Silhouette Coefficient، ويُحسب هذا المعامل من أجل عنصر بيانات x كما يلي: حيث: a هي وسطي المسافات بين x وبين العناصر الموجودة في نفس العنقود الموجود فيه العنصر x. b هي وسطي المسافات بين x وبين العناصر الموجودة في العناقيد القريبة من عنقود x. كما يُبين الشكل التالي: يُمكن ملاحظة ما يلي حول هذا المعامل: أفضل قيمة له هي 1 وأسوأ قيمة له هي -1. تُشير القيمة 0 إلى وجد تراكب overlapping في العناقيد. تدل القيمة السالبة على وجود العنصر x في عنقود خاطئ إذ يوجد عنقود آخر أقرب إلى x. يكون المعامل silhouette_score لمجموعة من البيانات وسطي قيمة المعامل لكل منها أي: يُمكن تضمين حساب هذا المعامل من sklearn.metrics كما تُبين الشيفرة التالية: from sklearn.metrics import silhouette_score cluster_labels = kmeans.fit_predict(data) # حساب المعامل silhouette_avg = silhouette_score(data, cluster_labels) print(silhouette_avg) يكون لطريقة حساب المعامل silhouette_score معاملي دخل الأول هو البيانات والثاني هو تسميات العناقيد الناتجة عن استدعاء الطريقة fit_predict أولًا. يكون الناتج في مثالنا: 0.553931997444648 إيجاد عدد العناقيد الأمثلي يُمكن استخدام المعامل Silhouette Coefficient لإيجاد عدد العناقيد الأمثلي المناسب لبيانات التدريب وذلك بحساب المعامل مع قيم مختلفة لعدد العناقيد ومن ثم اختيار العدد الذي يُعطي قيمة أعظمية للمعامل كما تُبين الشيفرة التالية: # مجموعة القيم الممكنة range_n_clusters = [2, 3, 4, 5, 6, 7] for n_clusters in range_n_clusters: clusterer = KMeans(n_clusters=n_clusters) cluster_labels = clusterer.fit_predict(data) # حساب المعامل silhouette_avg = silhouette_score(data, cluster_labels) print( "For n =", n_clusters, "silhouette_score is :", silhouette_avg, ) مما يُظهر المعامل من أجل كل قيمة محتملة لعدد العناقيد: For n = 2 silhouette_score is : 0.2968969162503008 For n = 3 silhouette_score is : 0.46761358158775435 For n = 4 silhouette_score is : 0.4931963109249047 For n = 5 silhouette_score is : 0.553931997444648 For n = 6 silhouette_score is : 0.5376203956398481 For n = 7 silhouette_score is : 0.5270287298101395 وبالتالي نلاحظ أن القيمة الأمثلية هي خمسة عناقيد. الخوارزميات التكتلية تمتاز الخوارزميات التكتلية بأنها توفر طريقة معاينة بسيطة لإيجاد عدد العناقيد الأمثلي عن طريق رسم شجرة دمج العناقيد مع بعضها البعض dendrogram: دخل الخوارزمية: بيانات التدريب وهي عبارة عن مجموعة من الأشعة الرقمية: {x1, x2, . . . , xN} حيث xi هو شعاع من الأرقام. خرج الخوارزمية: شجرة دمج العناقيد مع بعضها البعض dendrogram. المعالجة: تبدأ الخوارزمية بوضع كل عنصر من عناصر البيانات في عنقود. تُكرر الخوارزمية ما يلي وصولًا إلى عنقود وحيد: دمج أقرب عنقودين مع بعضهما البعض توجد عدة طرق لإيجاد أقرب عنقودين، من أبسطها الطريقة المسماة بالربط البسيط Single Linkage والتي تحسب المسافة بين عنقودين كما يلي: المسافة بين عنقودين هي أصغر مسافة بين عنصرين من هذين العنقودين. نستخدم فيما يلي الخوارزمية التكتلية مع البيانات التعليمية ومن ثم مع بيانات الزبائن. تعرض الشيفرة التالية طريقة بسيطة لتسمية نقاط البيانات التعليمية (العشرة) لتسهيل عملية المشاهدة والمتابعة: # التسميات : 2,1, ..., 10 labels = range(1, 11) plt.subplots_adjust(bottom=0.1) plt.scatter(X[:,0],X[:,1]) # تسمية النقاط for label, x, y in zip(labels, X[:, 0], X[:, 1]): plt.annotate( label, xy=(x, y), xytext=(-3, 3), textcoords='offset points', ha='right', va='bottom') plt.show() يكون الخرج: نبدأ أولًا بالشيفرة اللازمة لرسم شجرة الدمج dendrogram من أجل إيجاد عدد العناقيد الأمثل: # المكتبات اللازمة from scipy.cluster.hierarchy import dendrogram, linkage # اختيار الربط البسيط linked = linkage(X, 'single') # التسميات: 2,1, .. ,10 labelList = range(1, 11) # dendrogram dendrogram(linked, orientation='top', labels=labelList, distance_sort='descending', show_leaf_counts=True) plt.show() نُعاين شجرة الدمج الناتجة والتي تُبين أن عدد العناقيد المُمكن هو عنقودين: نستدعي الآن الدالة AgglomerativeClustering مع طلب عدد العناقيد مساويًا إلى 2: from sklearn.cluster import AgglomerativeClustering # العنقدة التكتلية cluster = AgglomerativeClustering(n_clusters=2) # الملائمة مع البيانات cluster.fit_predict(X) والتي تُظهر تسميات عنقود كل عنصر: array([1, 1, 1, 1, 0, 0, 0, 0, 0, 0], dtype=int64) يُمكن أيضًا رسم العناقيد: # الرسم plt.scatter(X[:,0],X[:,1], c=cluster.labels_, cmap='rainbow') plt.show() يكون الإظهار: ننتقل الآن إلى مسألة الزبائن باستخدام شيفرة مماثلة: # نوع الربط linked = linkage(data, 'ward') # dendrogram dendrogram(linked, orientation='top', distance_sort='descending', show_leaf_counts=True) # الرسم plt.title("Customer Dendograms") plt.show() يُمكن معاينة شجرة الدمج الناتجة: والتي تُبين أن عدد العناقيد المناسب هو 5. نستدعي الدالة AgglomerativeClustering في الشيفرة التالية: cluster = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward') cluster.fit_predict(data) # الرسم plt.scatter(data[:,0], data[:,1], c=cluster.labels_, cmap='rainbow') plt.show() ويكون الخرج: وهو، بالطبع، يُشابه ما حصلنا عليه سابقًا مع الخوارزمية KMeans. الخلاصة عرضنا في هذه المقالة خطوات بناء نموذج تعلّم لعنقدة مجموعة من البيانات مع آليات اختيار عدد العناقيد المناسب للمسألة. يُمكن تجربة المثال كاملًا من موقع Google Colab من الرابط، ولا تنس الاطلاع على ملف بيانات التدريب والشيفرة البرمجية. اقرأ أيضًا تعقيد الخوارزميات Algorithms Complexity أمثلة عن أنواع الخوارزميات مدخل إلى تعلم الآلة (Machine learning) في PHP