المشاركات

التحليل الإستكشافي لبيانات طلاب

درس عملي

من أهم الخطوات وأولها عند البدء بتحليل البيانات أو التنقيب عنها هو إجراء عمليات تحليل استكشافية على البيانات لفهم طبيعتها وللحصول على فكرة أولية عما تحتويه هذه البيانات وما هو الهدف المراد تحقيقه من التحليل أو التنقيب. لذلك، نقدم لكم في نمذجيات هذا الدرس العملي الذي يحتوي شرحاً مختصراً عن كيفية استيراد البيانات واستكشافها باستخدام لغة البايثون ومكتباتها المتخصصة في هذا المجال وعبر استخدام الأداة الرائعة جوبيتر.

من المهم قبل البدء بأي عملية استكشاف بيانات أن نتعرف على مصدر هذه البيانات، حتى نفهم السياق الذي وُجدت فيه، وبذلك نستطيع التعرف على الأهداف المراد تحقيقها من الاستكشاف. البيانات المستخدمة في هذا الدرس جُمعت من نظام كالبورد 360 وهو نظام خاص بإدارة التعليم الكترونياً، وهي عبارة عن بيانات مجموعة من الطلاب هدفها توقع أداء الطلاب وفقاً لمجموعة من الخصائص عددها 16.

خصائص البيانات

قبل البدء في شرح البيانات التي سنعمل عليها، من المهم توضيح بعض المفاهيم:

  • خصائص البيانات: هي مجموع الأعمدة أو السمات التي تُشكل سجل البيانات، وفي حالتنا هذه فإن جميع السجلات الموجودة تتشارك نفس مُسميات الخصائص والسمات.
  • أنواع البيانات: لكل خاصية في البيانات نوع معين لا يتغير، وتكون الخاصية أحد أربع أنواع:
    1. إسمية (Nominal).
    2. ترتيبية (Ordinal).
    3. مجال (Range).
    4. نسبة (Ratio).
  • بعض المصادر تُشير إلى الأنواع الإسمية والترتيبية معاً بالخصائص الفئوية (Categorical) أو النوعية (Qualitative) ويُشار الى خصائص المجال والنسبة الى الخصائص الكمية (Quantitive) أو الرقمية (Numeric).
  • إطار البيانات (Dataframe): هو مصطلح برمجي خاص بمكتبة Pandas في لغة البايثون، وهو المُتغير الذي يحتفظ بالبيانات عند استيرادها من ملفات خارجية مثل csv او xls ويُمَّكْنُنَا من التعامل مع البيانات ومعالجتها.

خصائص بيانات الطلاب المُستخدمة في هذا الدرس:

الخاصية الوصف طبيعة الخاصية مجال القيم
Gender جنس الطالب ترتيبية  Male , Female
Nationality الجنسية اسمية  Kuwait, Lebanon, Egypt, SaudiArabia, USA, Jordan, Venezuela, Iran, Tunis, Morocco, Syria, Palestine, Iraq, Lybia
Place of birth مكان الميلاد اسمية  Kuwait, Lebanon, Egypt, SaudiArabia, USA, Jordan, Venezuela, Iran, Tunis, Morocco, Syria, Palestine, Iraq, Lybia
Educational Stages مستوى الطالب ترتيبية  lowerlevel, MiddleSchool, HighSchool
Grade Levels الصف ترتيبية  G-01, G-02, G-03, G-04, G-05, G-06, G-07, G-08, G-09, G-10, G-11, G-12
Section ID الشعبة ترتيبية A, B, C
Topic المادة اسمية  English, Spanish, French, Arabic, IT, Math, Chemistry, Biology, Science, History, Quran, Geology
Semester الفصل الدراسي ترتيبية First, Second
Relation ولي الأمر اسمية mom, father
Raised hand عدد مرات رفع اليد في الصف رقمية – مجال 0-100
Visited resources عدد زيارات الطالب لمحتوى المادة رقمية – مجال 0-100
 Viewing announcements  عدد مرات تصفح الطالب للاعلانات  رقمية – مجال  0-100
 Discussion groups  عدد مرات مشاركة الطالب في مجموعات النقاش  رقمية – مجال  0-100
 Parent Answering Survey  هل شارك ولي الامر في الاستبانة ترتيبية  Yes, No
Parent School Satisfaction رضى ولي الامر عن المدرسة ترتيبية  Yes, No
Student Absence Days عدد ايام غياب الطالب ترتيبية above-7, under-7
Grade/Mark درجة الطالب ترتيبية

L (low level)
M (middle level)
H (high level)

تستطيع الحصول على نُسخة من البيانات بصيغة csv من خلال الرابط التالي:

https://www.kaggle.com/aljarah/xAPI-Edu-Data

الجانب العملي باستخدام جوبيتر

أولاً: استيراد المكتبات والبيانات

في البداية نقوم باستيراد المكتبات اللازمة للعمل:

In [1]:
%matplotlib inline
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
المكتبة Pandas مُختصة بالتعامل مع البيانات من حيث الاستيراد والجلب وإجراء عمليات تنظيف البيانات Data Munging ومعالجة البيانات. مكتبة Numpy هي مكتبة رياضية مُختصة بالحوسبة العلمية وعمليات الجبر الخطي والمصفوفات وبعض العمليات الرياضية الخاصة. مكتبتي Seaborn و Matplotlib هما مكتبتان مختصتان في الإظهار المرئي.

لإجراء عملية استيراد البيانات من ملف csv نستخدم  الدالة read_csv الخاصة بمكتبة Pandas. نتيجة استدعاء الدالة عبارة عن إطار البيانات والذي سنسميه اختصاراً بـ df (مُعامل encoding يُستخدم لتحديد الترميز عند قراءة البيانات):

In [2]:
df = pd.read_csv("xAPI-Edu-Data.csv",encoding='utf-8')
 إذا كانت البيانات محفوظة لديك بشكل مُختلف عن صيغة csv فلا تقلق، فمكتبة Pandas تُقدم تشكيلة واسعة من دوال استيراد وقراءة البيانات التي تكون بصيغة json، excel، html أو حتى أن تكون البيانات في قاعدة بيانات.

ثانيا: التعرف على البيانات

الخطوة الأولى للحصول على صورة مبدئية عن البيانات هي استخدام الدالة describe والتي تقوم بتنفيذ عمليات إحصائية سريعة على خصائص البيانات المحفوظة في إطار البيانات:
In [3]:
df.describe()
Out [3]:
raisedhands VisITedResources AnnouncementsView Discussion
count 480.000000 480.000000 480.000000 480.000000
mean 46.775000 54.797917 37.918750 43.283333
std 30.779223 33.080007 26.611244 27.637735
min 0.000000 0.000000 0.000000 1.000000
25% 15.750000 20.000000 14.000000 20.000000
50% 50.000000 65.000000 33.000000 39.000000
75% 75.000000 84.000000 58.000000 70.000000
max 100.000000 99.000000 98.000000 99.000000
لاحظ معي أن الخصائص ذات الطبيعة الرقمية هي التي تم التعامل معها فقط، ولكن نستطيع تحديد جميع الخصائص بغض النظر عن نوعها باستخدام المُعامل include بحيث يأخذ القيمة all، وفي هذه الحالة سيتم تنفيذ العمليات وفقا لطبيعة كل خاصية، والتي لا يمكن تنفيذها ستكون النتيجة NaN (مثل عملية الوسط الحسابي لا نستطيع اجراءها على خاصية من نوع نص):
In [4]:
df.describe(include='all')
Out [4]:
gender NationalITy PlaceofBirth StageID GradeID SectionID Topic Semester Relation raisedhands VisITedResources AnnouncementsView Discussion ParentAnsweringSurvey ParentschoolSatisfaction StudentAbsenceDays Class
count 480 480 480 480 480 480 480 480 480 480.000000 480.000000 480.000000 480.000000 480 480 480 480
unique 2 14 14 3 10 3 12 2 2 NaN NaN NaN NaN 2 2 2 3
top M KW KuwaIT MiddleSchool G-02 A IT F Father NaN NaN NaN NaN Yes Good Under-7 M
freq 305 179 180 248 147 283 95 245 283 NaN NaN NaN NaN 270 292 289 211
mean NaN NaN NaN NaN NaN NaN NaN NaN NaN 46.775000 54.797917 37.918750 43.283333 NaN NaN NaN NaN
std NaN NaN NaN NaN NaN NaN NaN NaN NaN 30.779223 33.080007 26.611244 27.637735 NaN NaN NaN NaN
min NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.000000 0.000000 0.000000 1.000000 NaN NaN NaN NaN
25% NaN NaN NaN NaN NaN NaN NaN NaN NaN 15.750000 20.000000 14.000000 20.000000 NaN NaN NaN NaN
50% NaN NaN NaN NaN NaN NaN NaN NaN NaN 50.000000 65.000000 33.000000 39.000000 NaN NaN NaN NaN
75% NaN NaN NaN NaN NaN NaN NaN NaN NaN 75.000000 84.000000 58.000000 70.000000 NaN NaN NaN NaN
max NaN NaN NaN NaN NaN NaN NaN NaN NaN 100.000000 99.000000 98.000000 99.000000 NaN NaN NaN NaN
بالإضافة لدالة describe السابقة، يمكننا استخدام الدالة info والتي تقوم بعرض معلومات مختصرة عن إطار البيانات:
In [5]:
df.info()
Out [5]:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 480 entries, 0 to 479
Data columns (total 17 columns):
gender                      480 non-null object
NationalITy                 480 non-null object
PlaceofBirth                480 non-null object
StageID                     480 non-null object
GradeID                     480 non-null object
SectionID                   480 non-null object
Topic                       480 non-null object
Semester                    480 non-null object
Relation                    480 non-null object
raisedhands                 480 non-null int64
VisITedResources            480 non-null int64
AnnouncementsView           480 non-null int64
Discussion                  480 non-null int64
ParentAnsweringSurvey       480 non-null object
ParentschoolSatisfaction    480 non-null object
StudentAbsenceDays          480 non-null object
Class                       480 non-null object
dtypes: int64(4), object(13)
memory usage: 63.8+ KB
النتيجة السابقة لدالة info تحتوي معلومات عن هيكلية البيانات لدينا، من حيث عدد السجلات، عدد الأعمدة، نوع كل عمود وعدد القيم فيه بالإضافة لحجم الذاكرة المستهلكة لصالح إطار البيانات.
لمعرفة أبعاد إطار البيانات الذي نتعامل معه بطريقة مباشرة، نستخدم الخاصية shape:
In [6]:
df.shape
Out [6]:
(480, 17)
النتيجة السابقة تعني أنه يوجد لدينا 480 سجل (صف) من البيانات و 17 عمود.
أثناء عملنا سنحتاج غالباً للاطلاع على عينة من البيانات. من الممكن الحصول على عينة عشوائية باستخدام الدالة sample مع تحديد عدد القيم التي تريدها. بالاضافة لذلك، نستطيع الحصول على أول/اخر سجلات في إطار البيانات باستخدام الدوال head و tail على الترتيب.
In [7]:
df.sample(3)
Out [7]:
gender NationalITy PlaceofBirth StageID GradeID SectionID Topic Semester Relation raisedhands VisITedResources AnnouncementsView Discussion ParentAnsweringSurvey ParentschoolSatisfaction StudentAbsenceDays Class
322 M Jordan Jordan lowerlevel G-02 A French F Father 10 15 10 21 No Bad Above-7 L
116 F KW KuwaIT lowerlevel G-02 C IT F Mum 77 80 12 19 Yes Good Above-7 M
299 M Jordan Jordan lowerlevel G-04 A Science S Father 32 14 32 29 No Good Above-7 M
In [8]:
df.head()
Out [8]:
gender NationalITy PlaceofBirth StageID GradeID SectionID Topic Semester Relation raisedhands VisITedResources AnnouncementsView Discussion ParentAnsweringSurvey ParentschoolSatisfaction StudentAbsenceDays Class
0 M KW KuwaIT lowerlevel G-04 A IT F Father 15 16 2 20 Yes Good Under-7 M
1 M KW KuwaIT lowerlevel G-04 A IT F Father 20 20 3 25 Yes Good Under-7 M
2 M KW KuwaIT lowerlevel G-04 A IT F Father 10 7 0 30 No Bad Above-7 L
3 M KW KuwaIT lowerlevel G-04 A IT F Father 30 25 5 35 No Bad Above-7 L
4 M KW KuwaIT lowerlevel G-04 A IT F Father 40 50 12 50 No Bad Above-7 M
In [9]:
df.tail()
Out [9]:
gender NationalITy PlaceofBirth StageID GradeID SectionID Topic Semester Relation raisedhands VisITedResources AnnouncementsView Discussion ParentAnsweringSurvey ParentschoolSatisfaction StudentAbsenceDays Class
475 F Jordan Jordan MiddleSchool G-08 A Chemistry S Father 5 4 5 8 No Bad Above-7 L
476 F Jordan Jordan MiddleSchool G-08 A Geology F Father 50 77 14 28 No Bad Under-7 M
477 F Jordan Jordan MiddleSchool G-08 A Geology S Father 55 74 25 29 No Bad Under-7 M
478 F Jordan Jordan MiddleSchool G-08 A History F Father 30 17 14 57 No Bad Above-7 L
479 F Jordan Jordan MiddleSchool G-08 A History S Father 35 14 23 62 No Bad Above-7 L
للتأكد من أن إطار البيانات لدينا لا يحتوي على قيم فارغة نستخدم الدالة isnull الخاصة بإطار البيانات بالطريقة التالية:
In [10]:
df.isnull().values.any()
Out [10]:
False
النتيجة السابقة تعني أنه لا يوجد أي قيمة فارغة لأي خاصية في البيانات، وفي حال وجود قيمة فارغة ستكون النتيجة True.
للقيام ببعض العمليات الإحصائية مباشرة على خاصية من الخواص، فمن الممكن استخدام دوال مكتبة Numpy مثل mean، max، min، std وغيرها كما في المثال التالي:
In [11]:
print(np.mean(df.raisedhands))
print(np.max(df.raisedhands))
print(np.min(df.raisedhands))
print(np.std(df.raisedhands))
Out [11]:
46.775
100
0
30.74714417632964

 ثالثا: الإستعلام عن البيانات

 من المهم جداً أثناء التعامل مع البيانات اجراء بعض عمليات الاستعلام وفق شروط ومحددات نريدها. فمثلاً، لو أردنا الاستعلام عن عدد الطلاب الذكور والاناث في البيانات نقوم باستخدام دالة value_counts والتي تقوم بتجميع قيم عمود مُعين وتحدد عدد التكرارات حسب كل مجموعة:
In [12]:
df["gender"].value_counts()
Out [12]:
M    305
F    175
Name: gender, dtype: int64
 للاستعلام عن سجلات في إطار البيانات وفق شروط معينة، فإن مكتبة Pandas تُقدم الدالة query الخاصة بإطار البيانات، وهي دالة تسهل عليك إجراء عمليات إستعلام وفق محددات وشروط. فمثلاً، لو أردنا الإستعلام عن الطالبات من دولة الكويت الذين كان عدد مرات رفع اليد في الفصل أكثر من 50 وبحيث نعرض خاصية الجنس وعدد مرات رفع اليد فقط، نستخدم الدالة query بالطريقة التالية:
In [13]:
df.query("gender == 'F' and Topic == 'IT' and raisedhands > 50" )[["gender","raisedhands"]]
Out [13]:
gender raisedhands
9 F 70
18 F 69
20 F 60
68 F 70
94 F 80
95 F 100
101 F 70
110 F 70
116 F 77
122 F 66
123 F 70
 في بعض الأحيان قد نحتاج لاستخدام متغيرات على مستوى الشيفرة البرمجية داخل جملة الشرط لدالة query. في هذه الحالة نستطيع الوصول للمتغيرات باستخدام الرمز الخاص @ ثم اسم المتغير داخل جملة الشرط كالتالي:
 df.query("gender == 'F' and Topic == 'IT' and raisedhands > @x " )[["gender","raisedhands"]]

 رابعاً: الإظهار المرئي

من أسرع الطرق التي تساعدنا في فهم البيانات والحصول على قراءات وملاحظات سريعة عنها هو استخدام تقنيات الإظهار المرئي للبيانات، وتتعدد الأشكال والرسومات البيانية والإحصائية التي يمكن إجراؤها. سنذكر تحت هذا العنوان بعضاً منها.

من المواضيع المهمة أثناء تحليل البيانات والتنقيب عنها هو معرفة درجة ارتباط خصائص البيانات ببعضها، وبإمكاننا استخدام دالة corr الخاصة بإطار البيانات للحصول على جدول يوضح درجة ارتباط الخصائص الرقمية ببعضها:

In [14]:
df.corr()
Out [14]:
raisedhands VisITedResources AnnouncementsView Discussion
raisedhands 1.000000 0.691572 0.643918 0.339386
VisITedResources 0.691572 1.000000 0.594500 0.243292
AnnouncementsView 0.643918 0.594500 1.000000 0.417290
Discussion 0.339386 0.243292 0.417290 1.000000

 

 

 

 

تتراوح درجة الارتباط من 0 الى 1 حيث كلما اقتربت الدرجة من القيمة 1 كلما زادت الارتباطية بين الخاصيتين وهذا يسمح لنا بالإستغناء عن أحدهما، وهذا الأمر يُفيد في موضوع إنقاص الأبعاد (Dimensionality Reduction)، وكلما اقتربت الدرجة الى القيمة 0 كلما نقصت الترابطية بين الخاصيتين واصبحا مستقلين عن بعضهما البعض بحيث لا نستطيع الاستغناء عن أحدهما.

لإظهار الجدول السابق بطريقة مرئية نقوم بما يلي:

In [15]:
corr = df.corr()   
fig, ax = plt.subplots(figsize=(10, 10))
ax.matshow(corr)  
plt.xticks(range(len(corr.columns)), corr.columns)  
plt.yticks(range(len(corr.columns)), corr.columns) 
Out [15]:
في الشكل السابق، كلما اقترب اللون الى الأسود كلما زادت الترابطية وكلما اقترب اللون الى الأبيض كلما قلت درجت الترابطية.
في كثير من التجارب نحتاج للحصول على شكل رسومي يوضح عدد تكرار السجلات لخاصية معينة (اسمية أو ترتيبية) حسب مجال القيم التي تحتويها. تُقدم مكتبة Seaborn الدالة countplot التي تقوم بذلك، فمثلاً، لو اردنا التعرف على أعداد الطلاب حسب الجنسيات، نقوم بالتالي:
In [16]:
fig = sns.countplot(x="NationalITy", data=df, palette="muted");
fig.set_xticklabels( fig.get_xticklabels() ,  rotation=70)
plt.show()
 
في المثال السابق، قمنا باستدعاء الدالة countplot ومررنا لها في البداية العمود الذي نريد إجراء عملية العد بناءا على قيمته وهو في حالتنا NationalITy ومن ثم نحدد إطار البيانات الذي نعمل عليه، وفي النهاية تختار مجموعة الألوان الخاصة بالشكل. الدالة set_xticklabels نستخدمها لإجراء عملية تدوير (70 درجة) لأسماء الجنسيات حتى لا تتداخل فيما بينها ويظهر الشكل بطريقة مُرتبة.
من خلال الشكل البياني السابق، وبالنظر السريع له، نحصل على معلومة مفادها أن أغلب الطلاب هم من دولة الكويت والأردن. المثال التالي يوضح كيفية إجراء نفس الأمر على خاصية درجة الطالب:
In [17]:
fig = sns.countplot(x="Class", data=df, palette="muted");
plt.show()
 
 ونلاحظ من الشكل أن أغلب الطلاب حصلوا على درجة متوسطة M في المواد بشكل عام، وعدد الطلاب الذين حصلوا على علامة عالية H هم أكثر بقليل من الطلاب الذين حصلوا على درجة متدنية L.
لعرض أعداد الطلاب حسب المواد مع تفصيل الأعداد حسب الدرجة نُمرر للدالة countplot المُعامل hue ونحدد اسم خاصية الدرجة كما يلي:
In [18]:
plt.subplots(figsize=(13,10))
fig = sns.countplot(x="Topic", data=df, palette="Set2",hue="Class");
fig.set_xticklabels( fig.get_xticklabels() ,  rotation=70)
plt.show()
 
قد تكون الأعمدة البيانية في بعض الأحيان غير تفصيلية، لذلك، نستطيع استخدام ما يُسمى بأشكال السرب (Swarm Shapes) بحيث يتم رسم كل نقطة تُمثل سجل في البيانات على الشكل:
In [19]:
Raised_hand = sns.swarmplot(x="Class", y="raisedhands", data=df,  palette="muted")
plt.show()
 
من الشكل السابق يتضح لنا أن أغلب الطلاب الذين رفعوا أيديهم في الصف أكثر من 60 مرة حصلوا درجة عالية H، بينما أغلب الطلاب الذين حصلوا على درجة متدنية L لم تزد مرات رفع اليد في الصف عن 20 مرة، بينما الطلاب الذين حصلوا على درجة متوسطة توزعت مرات رفع اليد لديهم على مجال الخاصية.
تُقدم مكتبة Seaborn دالة أخرى تُسمى joinplot لرسم شكل بياني يوضح علاقة متغيرين مع بعضهم البعض:
In [20]:
fig = sns.jointplot(x="raisedhands", y="VisITedResources", data=df, kind="reg", size=8);
plt.show()
 
نلاحظ من الشكل وجود علاقة بين عدد مرات زيارة محتوى المواد وعدد مرات رفع اليد في الصف، حيث كلما زاد أحدهما زاد الأخر والعكس صحيح.
طرق الإظهار المرئي والأشكال التي يُمكن استخدامها كثيرة ومتنوعة، وهدفنا هو إعطاء لمحة سريعة عن أهم الأشكال المستخدمة وعرض الطريقة الأساسية لإستخدامها. يمكنكم تنزيل الكود وتجربته من هنا.

خاتمة

قدمنا في هذا الدرس مجموعة من الطرق العملية لاستيراد البيانات وإجراء بعض العمليات الإستكشافية عليها مثل العمليات الاحصائية، الاستعلام عن البيانات والإظهار المرئي، وتمكنا من خلال الدرس تطبيق هذه العمليات على بيانات لمجموعة من الطلاب وعرضنا لكم بعض القراءات والملاحظات التي حصلنا عليها باستخدام الطرق الاستكشافية.
التقنيات، العمليات والمكتبات المُستخدمة في هذا الدرس تم ذكرها على سبيل المثال وليس الحصر، حيث يوجد العديد من الطرق والمكتبات والتقنيات الأخرى التي لا مجال لذكرها هنا.
سيكون من الجيد مشاركتنا تجاربكم في إجراء عمليات إستكشاف البيانات عبر التعليقات في هذا الدرس.
الوسوم
اظهر المزيد

إبراهيم البحيصي

حاصل على بكالوريوس هندسة الحاسوب ثم ماجستير تكنولوجيا المعلومات من الجامعة الإسلامية بغزة. محب للبايثون وعلوم البيانات، كاتب ومترجم تقني.

مقالات ذات صلة

9 آراء على “التحليل الإستكشافي لبيانات طلاب”

    1. العفو د.فارس
      الدروس العملية في هكذا مواضيع مهمة جدا، ونحتاج لتقوية المحتوى العربي في هذا المجال لما له من فائدة على المستوى الأكاديمي والبحثي وكذلك المستوى التطبيقي في الشركات والمؤسسات.

      تحياتي العطرة.

  1. معلومات رائعة كعادة مواضيع نمذجيات

    كمبتدئ في مجال البيانات لدي تساؤل, هل يعجز مايكروسوفت اكسيل عن تقديم مثل هذه المخرجات؟

    1. شكرا لك رامي
      برنامج الإكسيل يقدم العديد من الخيارات التي تتيح لك إجراء عمليات استكشافية على البيانات وإجراء بعض العمليات الأخرى ولكن كل ذلك يندرج تحت المُهمة الرئيسية للإكسيل كأداة مكتبية عامة تقدم حلولا في جدولة البيانات وليس كأداة أو برنامج متخصص في علم البيانات.

      تحياتي

  2. بارك الله في علمكم ونفع بكم …..
    مشكور أخي الغالي مقال جدا رائع
    لو تكرمت عندي سؤال ….
    ماهي الأساسيات والمهارت التي يجب ان اركز عليها كباحث في هذا المجال ؟

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

إغلاق