لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 02/23/22 في كل الموقع
-
تُعدّ مسألة تصنيف العملاء أي تجزئتهم إلى مجموعات متشابهة في سلوكها (عمليات الشراء والتسوق) من المسائل الهامة في عالم التسويق وذلك بهدف إعداد حملات تسويقية مختلفة مناسبة لكل مجموعة من المجموعات المُستهدفة. سنعرض في هذه المقالة استخدام خوارزميات العنقدة 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) في PHP1 نقطة
-
سلام عليكم ارجو المساعد السؤال هو عبارة عن برنامج يقوم بتوليد ارقام عشوائيه مكون من 100 خانه او اكثر انا اعراف كيف اقوم بتوليد ارقام عشوائيه ولكن اقص عدد من الخانات 15 مشكلة هي توليد عدد الخانات 100 اي عدد كبير وإجراء عمليات حاسبية عليه1 نقطة
-
السلام عليكم هل هناك امكانية لتشغيل دالتين بالترتيب بحيث لا تبدأ الأولى حتى تكتمل الثانية ؟ تعبت في البحث عن طريقة للقيام بهذا ..1 نقطة
-
تحيه طيبه للجميع استعمل كلاس البحث من فلاتر SearchDelegate واقوم بجلب البيانات الى هذا الكلاس من خلال الدالة التأليه: var listsearch=[]; Future getdata() async { apiURL = 'https://**********************}'; var response = await http.post(Uri.parse(apiURL)); var responsebody=jsonDecode(response.body); for (int i=0 ; i < responsebody.length ; i++){ listsearch.add(responsebody[i]['name']); } print(listsearch) ; } مشكلتي الان انني فقط استطيع تمرير قيمة name من خلال القائمة listsearch.add(responsebody[i]['name']); ثم انقل هذا ليسته الى كلاس SearchDelegate ولكني احتاج أيضا الى تمرير id كيف ممكن أقوم بتمرير قيمتين الى كلاس البحث ؟ هل يملك احد فكره لفعل ذلك؟ أيضا في كلاس SearchDelegate class DataSerch extends SearchDelegate<String> { List<dynamic>list; DataSerch({this.list}); @override List<Widget> buildActions(BuildContext context) { return [IconButton(icon: Icon(Icons.clear), onPressed: () { query=''; }) ]; } @override Widget buildLeading(BuildContext context) { return IconButton( icon: Icon(Icons.arrow_back), onPressed: () { close(context, null); }); } @override Widget buildResults(BuildContext context) { return Text(query); } @override Widget buildSuggestions(BuildContext context) { var seachlist=query.isEmpty?list :list.where((p) => p.startsWith(query)).toList(); return ListView.builder(itemCount: seachlist.length, itemBuilder: (context, i) { return ListTile(leading: Icon(Icons.memory),title: Text(seachlist[i]), onTap: (){ query=seachlist[i]; showResults(context); }, ); }); } } كيف ممكن امرر id الذي تم الضغط عليه (فعليا المستخدم سوف يضغط على الاسم ولكن كل اسم مرتبط ب id في قاعدة البيانات) ارغب بتمرير id الى showResults وليس الاسم الفكرة انني لن أقوم بعرض البيانات الى المستخدم في النتيجة النهائية بعد الضغط على الاسم من خلال الاسم او لن اجلب البيانات للمستخدم في الاخير من خلال الاسم ارغب بجلب البيانات من خلال id لذلك احتاج الى جلب id ونقله1 نقطة
-
#include<iostream> using namespace std; int Size = 10; int a[10], top = -1; int pop(); void del_pop(int[], int i); void push(int[], int); void delprime(int a[]); int main() { int i, k; for (i = 0; i < Size; i++) { cin >> k; push(a, k); } delprime(a); for (i = 0; i < Size; i++){cout << pop() << endl;} } void push(int a[], int k) { if (top == Size - 1)cout << "Stack overflow"; else a[++top] = k; } int pop() { return a[top--]; } void del_pop(int a[], int i) { int top2 = -1, m[10]; while (top >= 0) { if (i != a[top]) { m[++top2] = a[top]; } else Size--; top--; } while (top2 >= 0) { a[++top] = m[top2--]; } } void delprime(int a[]) { int i,flag = 0; while (top >= 0) { for (i = 2; i <= a[top] / 2; i++) { if (a[top] % i == 0) { flag = 1; break; } } if (flag == 0) { del_pop(a, a[top]); } top--; } } هذا برنامج يقوم بحذف الاعداد الأولية من مكدس لكن عند بعد استدعاء دالة حذف الأعداد الأولية تتغير كل القيم للصفر في حلقة التكرار التي تستدعي الدالة pop #include<iostream> using namespace std; int Size = 10; int a[10], top = -1; int pop(); void del_pop(int[], int i); void push(int[], int); void delprime(int a[]); int main() { int i, k; for (i = 0; i < Size; i++) { cin >> k; push(a, k); } delprime(a); } void push(int a[], int k) { if (top == Size - 1)cout << "Stack overflow"; else a[++top] = k; } int pop()1 نقطة
-
المشكلة كما ذكرت ان showAdmobBanner لا استدعيها في نفس Activity1 نقطة
-
ماهو الفرق بين الكود التالي: request.POST.get('KEY') وهذا الكود: request.POST['KEY'] قمت بتجربة كلا الأمرين وحصلت على نفس النتيجة، لذلك كنت أتسأل عن الفرق بينهما؟1 نقطة
-
مرحبا اخي الكريم نعم انا ارغب بتمرير قيمة الـ id بجانب الاسم ولكني قمت بتجريب هذا الطريقة الذي اشرت اليها انت والمشكلة كانت ان القائمة تظهر الاسماء وال id في كلاس SearchDelegate1 نقطة
-
هل تقصد تمرير القيمة id , name الى نفس list كما يلي ؟ listsearch.add(responsebody[i]['id']); listsearch.add(responsebody[i]['name']);1 نقطة
-
الفكرة ببساطة هي : private void loadBannerAd () { ...//الدالة الأولى ... } private void showBannerAd () { ...//الدالة الثانية ... } عند استدعاء الدالة الثانية التي هي showBannerAd لا اريد ان تشتغل حتى تنتهي الأولى لأن الأولى تستغرق قليل من الوقت وبذلك قد لا يظهر الإعلان لأن التحميل لم يكتمل بعد !!!1 نقطة
-
لدي جدولين مختلفين كل جدول يحتوي على بيانات مختلفة ولكن المشكلة كل الجدولين تحتوي على عمود باسم (name) قمت بعمل inner join للجدولين في استعلام php حتى احصل على البيانات في فلاتر : <?php $id=$_GET['id']; $sql="SELECT * FROM Tabletop inner join Cat ON Tabletop.IDCat = Cat.id inner join Sub_Cat ON Tabletop.Id_Sub_Cat = Sub_Cat.id where Tabletop.id = ? " ; $stmt = $con->prepare($sql); $stmt->bind_param("s",$id); $stmt->execute(); $result = $stmt->get_result(); $array = array(); while ($row = mysqli_fetch_assoc($result)) { $array[] = $row; } echo ($result) ? json_encode(array("code" => 1, "result"=>$array)) : json_encode(array("code" => 0, "message"=>"Data not found !")); ?> المشكلة الان انني في خانة الاستعلام كيف ممكن ارجع قيم الاستعلام في فلاتر لكل العمودين بحيث اطلب منه جلب عمود الاسم للجدول الأول ثم جلب عمود الاسم للجدول الثاني بمعنى احتاج لعمل تفرقه بينهم/ مع العلم لا يمكنني تغير اسم العمود الان في قاعدة البيانات رح يسبب مشكلة كبيره الامر. Future<String> GateDate() async { var response = await http.get( Uri.parse('https://*************test.php'), headers: {"Accept": "application/json"}); setState(() { var convertDataToJson = json.decode(response.body); data = convertDataToJson['result']; if (data != null) { //table -1 var GetName = data[0]['name']; // Table-2 var GetNameTwo = data[0]['name']; } }); } هل يوجد حل لهذا المشكلة من خلال فلاتر؟1 نقطة
-
الحل يكمن في استعلام SQL حيث يمكنك وضع اسم مستعار لكل من الحقلين الذين لهما نفس الاسم $sql=" SELECT cat1.name AS name1, cat2.name AS name2, FROM Tabletop inner join Cat cat1 ON Tabletop.IDCat = cat1.id inner join Sub_Cat cat2 ON Tabletop.Id_Sub_Cat = cat2.id where Tabletop.id = ? " ; ثم في Flutter if (data != null) { //table -1 name1 var GetName = data[0]['name1']; // Table-2 name2 var GetNameTwo = data[0]['name2']; }1 نقطة
-
1 نقطة
-
<div class="footer" > <img src="images/تتتتتتتتتت.png" alt="" width="100%" > <div data-aos="fade-up" data-aos-anchor-placement="bottom-bottom" > <img src="images/2p.png" alt="" class="p2" width="100%"> </div> </div> <script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>1 نقطة
-
يمكنك تثبيت قيمة الحقل عن طريق : from django.core.exceptions import ValidationError def validate_length(value,length=6): if len(str(value))!=length: raise ValidationError(u'%s is not the correct length' % value) from django.db import models class MyModel(models.Model): constraint_length_charField = models.CharField(validators=[validate_length] , max_length = 6) حيثُ أن تم تثبيت القيمه في داله و من ثم استدعاؤها في النموذج model الخاص بك من أجل التحقق منها و قد تلاحظ انه قد تم كتابة الأمر max_length مجدداً و ذلك حتى لا تحدث مشكله عن كتابة الأمرين python manage.py makemigrations / python manage.py migrate أي يجب تحديد قيمة الحقل في كلاً من : length في الداله المطلوب التحقق منها و max_length في الحقل1 نقطة
-
كيف لي ان ادخل عالم البرمجة بصورة صحيحة مع العلم اني لا امتلك اي خبرة و معرفة بالكومبيوتر1 نقطة
-
انا حملت مشروع دجانغو من موقع githup لكن وجددت انه صعب عليه كمبتدئ لانه كان يحتوي على كلاسات كثيرة و مرتبط ببعضه البعض و دوال لم اعرف وظائفها فهل يوجد موقع فيه مشاريع بسيطة للمبتدئين ؟1 نقطة
-
السلام عليكم ورحمة الله أردت أن أعمل مشروع صغير بالجافا سكريبت عند الضغط على أي مكا في ا body يتم تشغيل الدوال في الجافا سكريبت ولكن ذلك لا يعمل أرجو حل المشكلة HTML <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="main.js"></script> </body> </html> جافا سكربت document.body.addEventListener('click', function() { welcome('Nawwar') }) function welcome(names){ console.log('welcome' + names) }1 نقطة
-
Schema::create('materials', function (Blueprint $table) { $table->id(); $table->string("MaterialName"); $table->foreignId('categories_id')->constrained('categories'); $table->foreignId('Unit_id')->constrained('units'); $table->float("pricebuy"); $table->float("prices sale"); $table->timestamps(); }); $MaterialName = $request->MaterialName ; $categories_id = $request->categories_id ; $Unit_id =$request->Units ; $pricebuy =$request->pricebuy ; $prices_sale = $request->prices_sale ; Materials::create( [ "MaterialName"=> $MaterialName ,"categories_id" =>$categories_id , "Unit_id" => $Unit_id , "pricebuy" => $pricebuy , "prices_sale"=> $prices_sale ] ); ابغا ادخل الحقول بالقاعدة وهي عبارة عن مصفوفه categories_id "Unit_id" كيف ادخلهم رافض معي يطلع لي Array to string conversion1 نقطة
-
يمكنك استخدام Django Signals و هي يوجد بها العديد من الخصائص التي تسمح بإستقبال الإشارات على سبيل المثال : عند إستقبال إشارة إنشاء مستخدم جديد في قاعدة البيانات قم بإنشاء صفحة شخصية خاصة بذلك المستخدم و ذلك يتم عن طريق استخدام أوامر الإستدعاء from django.db.models.signals import post_save from django.dispatch import receiver ثم نقوم بكتابة class الصفحة الشخصية للمستخدم تتضمن بعض البيانات الاختياريه مثل الاسم , العنوان , رقم الهاتف و غيرها ثم نضع django signals بعد ال class كالآتي بالعلم أن ال class الذي وضعنا بعده نموذج الإشارات هو Profile : @receiver(post_save , sender = User) def create_user_profile(sender , instance , created , **kwargs ): if created : Profile.objects.create(user = instance) فهناك العديد من الأوامر المستخدمه في نظام الإشارات في django لتتناسب مع كل فكرة يتم تطبيقها على سبيل المثال : pre_save : تستخدم في حال الرغبة في تنفيذ شيء قبل حفظ النموذج post_save : تستخدم في حال الرغبة في تنفيذ شيء بعد حفظ النموذج pre_delete : تستخدم في حال الرغبة في تنفيذ شيء قبل مسحة ( قبل حذف المستخدم قم بحذف المنشورات المتعلقه به ) m2m_changed : تستخدم في تتبع التغييرات في العلاقات المتعدده مثل ManyToManyField و يوجد بها العديد من الأدوات ( pre_add , post_add , pre_remove , post_remove , pre_clear , post_clear ) و غيرها من الأدوات لتسهيل تنفيذ الإشارات في حال حدوث أي تغيير في العلاقة1 نقطة
-
1 نقطة
-
<form class="card" action="{{route("Materials.store")}}" method="POST"> @csrf <div class="card-header"> <h3 class="card-title">Suppliers </h3> </div> <div class="card-body"> <div class="row"> <div class="col-md-12"> <div class="form-group"> <label>Material Name</label> <input class="form-control " type="text" placeholder="" name="MaterialName"> </div> <div class="form-group"> <label>Purchasing price </label> <input class="form-control " type="number" placeholder="" name="pricebuy"> </div> <div class="form-group"> <label>selling price </label> <input class="form-control " type="number" placeholder="" name="prices sale "> </div> <div class="form-group"> <label>Categories </label> <select multiple class="form-control select2bs4 select2-hidden-accessible" style="width: 100%;" aria-hidden="true" name="categories_id[]"> @foreach($Categories as $Categories ) <option value=" {{$Categories->id }}"> {{$Categories->CategoryName }}</option> @endforeach </select> </div> <div class="form-group"> <label>Units </label> <select multiple class="form-control select2bs4 select2-hidden-accessible" style="width: 100%;" aria-hidden="true" name="Units[]"> @foreach($Units as $Units ) <option value=" {{$Units->id }}"> {{$Units->UnitName }}</option> @endforeach </select> </div> <button type="submit" class="btn btn-success col fileinput-button dz-clickable"> <i class="fas fa-plus"></i> <span>Add </span> </button> </div> </div> </div> </form>1 نقطة
-
السلام عليكم, عندما نحدد الارقام المسموحة كالمثال هذا (١-٢) لماذا النتيجة true؟ const msg = 'Hello there! My name is Ibrahim and my age is 20'; const regex = /age is [1-2]+/; const check_criteria = regex.test(msg); console.log(check_criteria); output: true1 نقطة
-
لأن التعبير يطلب أن يحتوي النص على الجملة "age is" وبعدها عدد واحد أو أكثر شرط أن تكون هذه الأعداد إما 1 أو 2، التعبير في الجملة لديك طابق القسم التالي : 'Hello there! My name is Ibrahim and my age is 20' ^^^^^^^^^^^ أي طابق الجملة وبعدها عدد واحد، يمكنك استبدال "+" أي واحد أو أكثر، بـ "{1,2}" أي عدد مكون من خانة واحدة أو اثنين فيصبح التعبير كالتالي: const regex = /age is [1-2]{1,2}/; الجمل التالية كلها تطابق التعبير: 'Hello there! My name is Ibrahim and my age is 21' ^^^^^^^^^^^^ 'Hello there! My name is Ibrahim and my age is 11' ^^^^^^^^^^^^ 'Hello there! My name is Ibrahim and my age is 125' ^^^^^^^^^^^^1 نقطة
-
يُمكنك معرفة عدد العناصر الموجودة في أحد الجداول بإستخدام الدالة count مُباشرة بدون إستعمال مرشحات على الشكل التالي: table.query.count() أو session.query(Table).count() # Table # هو اسم النموذج الخاص بك مُلاحظة: الطريقة أعلاه قد تكون بطيئة نوعًا ما في بعض نُظم قواعد البيانات مثل MySql. للحصول على نتيجة أسرع يُمكن استخدام: from sqlalchemy import func session.query(func.count(Table.id)).scalar()1 نقطة
-
يُمكنك إستخدام Django signals والتي هي عبارة عن إشارات تسمح بإرسال تنبيهات عندَ حُدوث إجراءات معينة من بين تلك الإشارات نجد: post_save: تُستدعى هذه الإشارة بعد حفظ الكائن في قاعدة البيانات أي بعد حدوث الدالة save. pre_save: تُستدعى هذه الإشارة قبل حفظ الكائن في قاعدة البيانات اي قبل حدوث الدالة save. لتشغيل الأكواد عند إنشاء كائن جديد من النموذج Model نقوم بإنشاء signal من نوع post_save: from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=Model) def run_code(sender, instance, created, **kwargs): # نتحقق أولا من أن الكائن جديد if created: # هنا نضع الأكواد التي نُريد تشغيلها عندما يتم إنشاء # كائن جديد1 نقطة
-
يمكن أيضاً حساب عدد مرات إمكانية قسمة العدد على 10 حيث أن كل خانة للعدد العشري من مضاعفات 10 int counter = 0; int x = input // عدد نريد حساب عدد خاناته int temp = x ; // نسخة مؤقتة while(temp>0) { counter ++; temp = temp / 10; } System.out.println(counter);1 نقطة
-
لمعرفة عدد الخانات في عددٍ ما في لغة جافا يوجد عدة طرق مثلًأ تحويل العدد إلى نص من خلال الدالة String.valueOf ومن ثم الحصول على طول النص كما يظهر لنا في المثال int length = String.valueOf(number).length(); أخذ لوغاريتم العدد للأساس عشرة مع إضافة 1 , فإن كان مثلًا العدد 5520 , فإن اللوغاريتم للأساس عشرة بعد التقريب سيكون 3, نضيف 1 يصبح 4 وهو عدد الخانات int length = (int) (Math.log10(number) + 1); بالنسبة لتمثيل الأعداد فيمكنك تمثيلها في مصفوفة أو قائمة حسب الرغبة, المصفوفة أسرع في الوصول بينما القائمة تمكنك من إضافة العناصر دون تحديد الطول, حيث في المصفوفة تكون محكومًا بطول المصفوفة فإن إفترضنا المصفوفة طولها 5 لا يمكنك إضافة أكثر من 5 عناصر, بينما القائمة غير محكومة بطولٍ معين ولكنها على الجانب الأخر أبطأ من المصفوفة1 نقطة
-
حاول استخدام الاسلوب FOO__in=... جرب الكود Post.objects.filter(tags__in=[<id1>]) يمكن ايضا ان تجرب هذا الكود Post.objects.filter(tags_id=self.kwargs.get('pk'))1 نقطة
-
يمكنك استخدام معرف المنتج ID نفسه الموجود في حقل قاعدة البيانات الذي يتم توليده تلقائياً auto increment عند تحديد حقل ID ك primary key بالضبط، وهكذا لن تكون مسؤول عن إدارة عملية توليد الأرقام العشوائية للمنتجات لأنها طريقة خطأ، الأرقام التسلسلية لا تتكرر وهي المناسبة في حالتك.1 نقطة
-
هذا خطأ ، يمكنك الاعتماد على id الخاص بكل منتج بشكل طبيعي ، عن أي حماية تقصد ، و ماذا سيستفيد من يعرض رقم المنتج , لا داعي لأمور تعقيدية تعقد عمل البرنامج معك , أهتم بحماية الباك أند و حماية المدفوعات هذا سيفي بالغرض و بالإجابة عن سؤال صحيح يمكنك توليد code معين لكل منتج باستخدام mt_rand بهذا الشكل mt_rand(1, 9999);1 نقطة