تحليل البيانات باستخدام بايثون

تحليل البيانات باستخدام بايثون – سجلات الوفيات والاصابات بفيروس كورونا كمثال

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

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

ينبغي على من يريد تطبيق الجانب العملي من المقال أن يكون على دراية بأساسيات بايثون ومكتبات خاصة مثل pandas  و numpy و matplotlib بالاضافة إلى معرفته باستخدام أداة jupyter.

لن نتطرق في هذا المقال إلى طُرق متقدمة او مُعقدة في التحليل، إنما سنُركز على مهارات تحليل البيانات باستخدام بايثون مثل:

1- كيفية استيراد البيانات.

2- كيفية معالجة البيانات وتحضيرها لمرحلة التحليل.

3- الحصول على معلومات أساسية عن البيانات.

4- اظهار معلومات من البيانات على شكل رسومات بيانية.

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

مكتبات علم البيانات بالبايثون | 5 مكتبات مشهورة

مكتبة Numpy – الخطوة الأولى في علم البيانات بلغة البايثون

مكتبة Pandas – الخطوة الثانية في علم البيانات بلغة البايثون – الجزء الأول

مكتبة Pandas – الخطوة الثانية في علم البيانات بلغة البايثون – الجزء الثاني

مكتبة Matplotlib – الخطوة الثالثة في علم البيانات بالبايثون

نظرة عامة على البيانات

يتكون ملف البيانات الذي نتعامل معه في هذا المقال من 8 أعمدة وعدد سجلات يتغير مع كل يوم في ظل تسجيل حالات جديدة بالمرض ووجود وفيات يوميًا. الملف هنا هو حتى تاريخ 25 مارس لسنة 2020، لذا وجب الانتباه إلى أن النتائج ستكون مختلفة عند تطبيقك لأمثلة المقال اذا استخدمت ملف يحتوي على بيانات أحدث أو مختلفة.

تم الحصول على البيانات من موقع المركز الأوروبي للوقاية من الأمراض ومكافحتها ECDC  وذلك عبر بوابة البيانات العامة من خلال الرابط التالي:

الاحصاءات اليومية لعدد الاصابات والوفيات بمرض كورونا (Covid-19) حول العالم

خصائص البيانات (الأعمدة)

الخاصيةالتفاصيل
DateRepتاريخ السِجل
Dayاليوم (أعداد من بداية الشهر إلى نهايته)
Monthالشهر
Yearالعام
Casesعدد حالات الاصابة بفيروس كورونا
Deathsعدد الوفيات بفيروس كورونا
Countries and territoriesالدولة
Pop_Data.2018عدد السكان حتى عام 2018

آلية التحليل

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

بعد أن يتم تجهيز البيانات وتحويلها للشكل المطلوب، تبدأ عملية التحليل واستخراج المعلومات منها عبر تطبيق الدوال الاحصائية والخوارزميات الخاصة وعمليات الإظهار المرئي Data Visualization.

تحليل البيانات باستخدام بايثون – المرحلة الأولى  (قراءة البيانات)

بعد تنزيل الملف من الرابط المذكور في الأعلى، نُنشى مجلد للعمل وليكن باسم corona data analysis ثم نحفظ الملف بداخله. نُشغل أداة Jupyter وننشى مستند جديد لتحليل البيانات باسم corona data analysis doc. في البداية نقوم باستيراد المكتبات التي سنحتاجها للعمل:

import pandas as pd
from pandas import DataFrame, Series
import numpy as np
import matplotlib.pyplot as plt
from pylab import rcParams
import seaborn as sb
from datetime import date

سنحتاج أيضًا قبل البدء بالعمل إلى تجهيز بعض الاعدادات التي لها بالعمل كالتالي:

%matplotlib inline
rcParams['figure.figsize'] = 10,10
rcParams['font.size'] = 15
sb.set_style('whitegrid')
sns.set_palette("pastel")

من خلال matplotlib inline سنتمكن من اظهار الرسومات البيانية في نفس المستند، ثم بعد ذلك نُحدد أبعاد الرسوم البيانات وحجم الخط ثم نقوم باختيار تنسيق الرسومات من خلال دالة set_style.

لقراءة البيانات وحفظها في اطار البيانات نستخدم دالة read_csv الموجودة في مكتبة Pandas، وللحصول على عينة من البيانات بعد قراءتها نستخدم دالة head التابعة لاطار البيانات والتي ستعيد لنا أول 5 سجلات من البيانات، ويُمكننا استخدام دالة sample للحصول على عينة عشوائية.

corona = pd.read_csv('COVID-19-geographic-disbtribution-worldwide.csv',parse_dates=True) 

corona.head()

corona.sample(5)

تحليل البيانات باستخدام بايثون – المرحلة الثانية (تحضير البيانات)

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

  1. ازالة عمودي DateRep و GeoId باعتبار أنهما أعمدة مُكررة.
  2. التأكد من عدم وجود قيم فارغة في البيانات.
  3. تحويل عمود “احصائية السكان Pop_Data.2018” إلى قيم عددية صغيرة بقِيم مقاربة، فمثلًا 3562065 الى 3.5 مليون تقريبًا.
  4. تغيير اسماء بعض الأعمدة.
  5. إزالة كافة السجلات الصفرية، وأعني هنا السجلات التي ليس لها قيمة لكل دولة (عدد الاصابات والوفيات تساوي 0) والتي تكون قبل أول حالة اصابة في الدولة.

الهدف من الخطوة الأخيرة هو الحصول على معدلات صحيحة لعدد الوفيات والإصابات بعد تسجيل أول حالة اصابة بالفيروس في كل دولة. فمثلًا، حتى يكون متوسط عدد الاصابات أو الوفيات لدولة أفغانستان، يجب علينا ازالة السجلات الصفرية الخاصة بها قبل تاريخ 25/2/2020 وهو تاريخ تسجيل أول حالة اصابة، وسيتم تنفيذ ذلك على كل الدُول.

1- ازالة عمودي DateRep و GeoId باعتبار أنهما أعمدة مُكررة

corona.drop(['DateRep','GeoId'],axis=1,inplace=True)
corona.head()
تحليل بيانات فيروس كورونا - ازالة بعض الأعمدة
تحليل بيانات فيروس كورونا – ازالة بعض الأعمدة

2- التأكد من عدم وجود قيم فارغة في البيانات

حتى تاريخ 25/3/2020، وهو تاريخ أخر نسخة للبيانات والتي استخدمناها في هذا المقال، لم نجد قيم فارغة في البيانات إلا في عمود احصائية السكان.

corona.isna().any()

لإزالة القيم الفارغة يُوجد العديد من الطُرق والخيارات المتاحة. في حالتنا لن نستطيع حذف السجلات التي لديها قيم فارغة في عمود احصائية السكان، والسبب في ذلك يعود لوجود بيانات مهمة في تلك السجلات والتي لها علاقة بعدد الاصابات والوفيات في بعض الدول. لذلك سنعتمد تغيير القيمة الفارغة الى صفر باستخدام دالة fillna كما يلي:

corona['Pop_Data.2018'].fillna(0,inplace=True)
corona.isna().any()
تحليل بيانات فيروس كورونا - فحص وجود قيم فارغة
تحليل بيانات فيروس كورونا – فحص وجود قيم فارغة وازالتها

3- تحويل عمود “احصائية السكان Pop_Data.2018” إلى قيم عددية صغيرة

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

corona['Pop_Data.2018'] = (corona['Pop_Data.2018']/float(1000000)).round(2)
corona.sample(5)
تحليل بيانات فيروس كورونا - تغيير قيم عمود احصائية السكان وتقريبه
تحليل بيانات فيروس كورونا – تغيير قيم عمود احصائية السكان وتقريبه

4- تغيير اسماء بعض الأعمدة

باستخدام دالة rename يُمكننا تغيير أسماء الأعمدة التي نريدها، وذلك عبر تمرير الأسماء القديمة والجديدة كقاموس dictionary كما يلي:

corona.rename({'Pop_Data.2018':'Population', 
               'Countries and territories':'Countries'},
              axis=1, inplace=True)
corona.head()
تحليل بيانات فيروس كورونا - تغيير اسماء الأعمدة
تحليل بيانات فيروس كورونا – تغيير اسماء الأعمدة

5- إزالة كافة السجلات الصفرية

هذه الخطوة تتضمن عدة عمليات داخلية لتنفيذها، وهي كالتالي:

  1. تجزئة اطار البيانات الرئيسي إلى مجموعة اطارات بيانات فرعية حسب الدولة.
  2. الحصول على فهرس index لأول يوم تُسجل فيه اصابات بالفيروس في كل اطار فرعي، وحفظ قيمة الفهرس في متغير باسم first_infected_day.
  3. حذف السجلات الصفرية في كل الاطار الفرعي التي تكون فيها عدد الاصابات والوفيات صفر وتكون فهارسها قبل first_infected_day.
  4. اعادة تجميع الاطارات الفرعية في اطار بيانات واحد باسم corona_updated.

الدالة drop_zero_days ستقوم بالخطوات رقم 1 و 2 و 3، بينما ستتولى دالة concatenate_countries_dfs بتجميع الاطارات الفرعية:

def drop_zero_days(data,country):
    df = data[data['Countries'] == country].reset_index(drop=True)
    first_infected_day = df[df['Cases'] != 0 ].tail(1).index[0]
    result = df.drop(df.index[first_infected_day+1:])
    return result

def concatenate_countries_dfs(dfs):
    df = DataFrame()
    for d in dfs :
        df = pd.concat([df,d],ignore_index=True)
    return df

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

coutries = corona['Countries'].unique()

corona_dfs_list = []

for country in coutries:
    df = drop_zero_days(corona, country)
    if len(df) != 0:
        corona_dfs_list.append(df)

بعد أن حصلنا على قائمة الاطارات الفرعية، نستدعي دالة concatenate_countries_dfs لتجميعها في إطار واحد باسم corona_updated:

corona_updated = concatenate_countries_dfs(corona_dfs_list)
corona_updated
تحليل بيانات فيروس كورونا - ازالة السجلات الصفرية
تحليل بيانات فيروس كورونا – ازالة السجلات الصفرية

إلى هنا نكون انتهينا من مرحلة تجهيز البيانات، ونستطيع الانتقال لمرحلة استكشاف البيانات ومن ثم تحليلها.

تحليل البيانات باستخدام بايثون – المرحلة الثالثة (استكشاف البيانات)

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

لحسن الحظ أن مكتبة Pandas الرائعة تُوفر الكثير من الدوال التي تساعدنا في الحصول على المعلومات السابقة. للحصول على معلومات عن الخصائص في اطار البيانات، نستخدم الدالة info والتي تُعيد لنا أسماء الأعمدة وعدد السجلات في اطار البيانات وحجم الاطار في الذاكرة ومعلومات أخرى:

corona_updated.info()
تحليل بيانات فيروس كورونا - الحصول على معلومات عن اطار البيانات
تحليل بيانات فيروس كورونا – الحصول على معلومات عن اطار البيانات

تقدم لنا دالة describe الكثير من المعلومات الاحصائية عن البيانات:

corona_updated.describe()
تحليل بيانات فيروس كورونا - الحصول على معلومات احصائية في اطار البيانات
تحليل بيانات فيروس كورونا – الحصول على معلومات احصائية في اطار البيانات

من خلال المعلومات التي ظهرت لنا، عرفنا أن أكبر عدد للوفيات منذ بدء تفشي وباء فيروس كورونا كان 795 في يوم واحد لأحد الدول، ولكن لا نعلم أي دولة إلى الأن. كذلك بالنسبة لعدد حالات الاصابة، فأكبر عدد وصل الى 15141 اصابة في يوم واحد.

كذلك من خلال المعلومات السابقة، تبين لنا وجود قيمة غير منطقية لأقل عدد اصابات، حيث نجد أن الدالة describe أرجعت قيمة -9 لأقل قيمة في عمود Cases. لمعرفة أي دولة سُجل لها أكبر عدد وفيات حتى تاريخ 25/3/2020 وأي دولة وصل فيها عدد الاصابات لأكبر قيمة بالاضافة لمعرفة السجل الذي يحتوي على قيمة غير منطقية في عمود عدد حالات الاصابة:

corona_updated[corona_updated['Deaths'] == 795]

corona_updated[corona_updated['Cases'] == 15141]

corona_updated[corona_updated['Cases'].eq(float(-9))]
تحليل بيانات فيروس كورونا - ايجاد بعض المعلومات
تحليل بيانات فيروس كورونا – ايجاد بعض المعلومات

يُمكن الحصول على المعلومات السابقة بطريقة أخرى، وسنذكرها في شُروحات أخرى.

للحصول على عدد السجلات لكل دولة على حدة، نستخدم دالة value_counts ونُطبقها على عمود الدُول كما يلي:

corona_updated['Countries'].value_counts()
تحليل بيانات فيروس كورونا - عدد السجلات لكل دولة
تحليل بيانات فيروس كورونا – عدد السجلات لكل دولة

سنجد هنا أن للصين يُوجد 83 سِجل تليها اليابان بـ 71 سِجل ثم باقي الدُول.

لمعرفة درجة الارتباط بين خصائص البيانات نستدعي دالة corr لإطار البيانات corona_updated كما يلي:

corona_updated.corr()

وستكون النتيجة عبارة عن قيم درجة الارتباط بين الخصائص. نلاحظ أنه يوجد ارتباط قوي بين عمود عدد الوفيات وعمود عدد الإصابات:

تحليل بيانات فيروس كورونا - درجة الارتباط بين الخصائص
تحليل بيانات فيروس كورونا – درجة الارتباط بين الخصائص

تحليل البيانات باستخدام بايثون – المرحلة الرابعة (تحليل البيانات)

يجب علينا قبل البدء بتحليل البيانات، وبعد أن تعرفنا سريعا على البيانات، أن نُحدد مجموعة من الأسئلة التي تُمثل “المشكلة”. الاجابة على هذه الأسئلة ستكون من خلال عملية التحليل. الأسئلة التي نفترضها هي كالتالي:

  1. ما هو معدل عدد الإصابات والوفيات اليومي على مستوى العالم منذ بدء تفشي الفيروس؟
  2. ما هو معدل عدد الإصابات والوفيات اليومي  حسب الدُول؟
  3. كم يبلغ مجموع الاصابات والوفيات الشهري على مستوى العالم؟
  4. كم يبلغ مجموع الاصابات والوفيات شهريا حسب كل دولة؟
  5. من هي أعلى 5 دُول في عدد الوفيات والاصابات منذ بداية تفشي الفيروس؟
  6. السلسلة الزمنية لعدد الوفيات والاصابات

1- ما هو معدل عدد الإصابات والوفيات اليومي على مستوى العالم منذ بدء تفشي الفيروس؟

في ظل هذه الأزمة الصعبة التي تمر على العالم، قد يسأل الكثير السؤال التالي: ما هو المعدل اليومي للوفيات والاصابات بالفيروس على مستوى العالم؟ ايجاد اجابة على هذا السؤال ستعطي تصورًا أدق عن حجم الوباء.

في البداية لابد أن نوضح آلية احتساب المعدل اليومي للاصابات وعدد الوفيات. يتم احتساب المعدل اليومي للوفيات عبر ايجاد مجموع عدد الوفيات على مستوى العالم وتقسيم قيمة المجموع على عدد أيام الأزمة والتي بدأت بتاريخ 1/12/2019 وحتى وقت تجهيز هذا المقال.

d1 = date(2020,3,25)
d2 = date(2019,12,1)
corona_days = (d1-d2).days

corona_gloabl_deaths_avg = corona_updated['Deaths'].sum() / corona_days
corona_gloabl_cases_avg = corona_updated['Cases'].sum() / corona_days
print(corona_gloabl_deaths_avg,corona_gloabl_cases_avg)

لإظهار المعلومات السابقة على شكل بياني من نوع bar:

x = ['Deaths Global Average','Cases Global Average']
y = [corona_gloabl_deaths_avg,corona_gloabl_cases_avg]

fig = plt.figure(figsize=(5,5))
ax = fig.add_axes([.1,.1,1,1])

ax.set_ylabel('Averages')
ax.set_title('Daily deaths and cases average gloabally')

ax.bar(x,y)
تحليل بيانات فيروس كورونا - المعدل اليومي للوفيات والاصابات عالميا
تحليل بيانات فيروس كورونا – المعدل اليومي للوفيات والاصابات عالميا

حتى تاريخ 25/3/2020 وصل معدل الوفيات اليومي من فيروس كورونا منذ بدء نفشيه إلى 161.43 حالة وفاة يوميًا على مستوى العالم ومعدل عدد الاصاابات إلى 3625.35 حالة اصابة يوميا، وهذه أرقام أقل ما يُقال عنها أنها مُرعبة.

2- ما هو معدل عدد الإصابات والوفيات اليومي  حسب الدُول؟

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

avg_by_country = corona_updated.groupby('Countries')[['Deaths','Cases']].agg([sum]).sort_values(by=('Deaths','sum'))
avg_by_country = avg_by_country / corona_days
avg_by_country

لاحظ أننا رتبنا النتيجة حسب مجموع عدد الوفيات بطريقة تصاعدية. للحصول على أعلى 5 معدلات يومية في الاصابات والوفيات واظهار ذلك على شكل bar chart نستخدم دالة tail ونمرر لها القيمة 5. في هذه الحالة، ولأن البيانات مُرتبة ترتيبًا تصاعديا، سنحصل على آخر 5 قيم في معدلات الوفيات بالطريقة التالية:

avg_by_country['Deaths']['sum'].tail(5).plot(kind='bar')
تحليل بيانات فيروس كورونا - أعلى خمسة معدلات يومية للوفاة
تحليل بيانات فيروس كورونا – أعلى خمسة معدلات يومية للوفاة

ونفس الأمر للحصول على معدل الاصابات اليومية لأعلى 5 دول:

avg_by_country['Cases']['sum'].tail(5).plot(kind='bar')
تحليل بيانات فيروس كورونا - معدلات الاصابة اليومية لأعلى 5 دول
تحليل بيانات فيروس كورونا – معدلات الاصابة اليومية لأعلى 5 دول

3- كم يبلغ مجموع الاصابات والوفيات الشهري على مستوى العالم؟

سنستخدم هنا نفس المفهوم السابق، وهو التجميع، ولكن هذه المرة حسب الشهر:

sum_by_month = corona_updated.groupby('Month')[['Deaths','Cases']].agg([sum]).sort_values(by=('Deaths','sum'))
sum_by_month 
تحليل بيانات فيروس كورونا - مجموع الوفيات والاصابات الشهري عالميا
تحليل بيانات فيروس كورونا – مجموع الوفيات والاصابات الشهري عالميا

لإظهار المعلومات السابقة بشكل رسومي، من الممكن أن نستخدم شكل جديد، وهو pie chart كما يلي:

x = sum_by_month.index.tolist()
y = sum_by_month['Deaths']['sum']

fig = plt.figure(figsize=(5,5))
ax = fig.add_axes([.1,.1,1,1])

ax.set_title('Sum of deaths by month')
ax.set_yticklabels(x)

ax.pie(y,labels=x,autopct='%1.1f%%')
تحليل بيانات فيروس كورونا - مجموع الوفيات شهريا
تحليل بيانات فيروس كورونا – مجموع الوفيات شهريا

وكذلك بالنسبة لمجموع الاصابات:

x = sum_by_month.index.tolist()
y = sum_by_month['Cases']['sum']

fig = plt.figure(figsize=(5,5))
ax = fig.add_axes([.1,.1,1,1])

ax.set_title('Sum of cases by month')
ax.set_yticklabels(x)

ax.pie(y,labels=x,autopct='%1.1f%%')
تحليل بيانات فيروس كورونا - مجموع الاصابات شهريا
تحليل بيانات فيروس كورونا – مجموع الاصابات شهريا

4- كم يبلغ مجموع الاصابات والوفيات شهريا حسب كل دولة؟

سنستخدم هنا نفس طريقة التجميع، ولكن التجميع سيكون باستخدام أكثر من عمود. في البداية سنُجمع البيانات حسب الدولة، ثم حسب الشهر كما يلي:

sum_by_month_country = corona_updated.groupby(['Countries','Month'])[['Deaths','Cases']].agg([sum]).sort_index()

ستكون النتيجة عبارة عن اطار بيانات يتضمن كُل دولة ومجموع الوفيات والاصابات حسب الشهر. يُمكننا الاستعلام من النتيجة عن دولتي الصين وايطاليا كما يلي:

sum_by_month_country.loc[['China','Italy']]
تحليل بيانات فيروس كورونا - مجموع الوفيات والاصابات الشهرية حسب الدولة
تحليل بيانات فيروس كورونا – مجموع الوفيات والاصابات الشهرية حسب الدولة

5- من هي أعلى 5 دُول في عدد الوفيات والاصابات منذ بداية تفشي الفيروس؟

قد نكون أجبنا على هذا السؤال بشكل غير مباشر في النقطة رقم 2 السابقة والتي مثلت كيفية إيجاد المعدل اليومي للوفيات. هنا نُريد أن نعرف بالضبط أول 5 دُول تفشى فيها الفيروس وكان بها أكبر عدد من الوفيات والإصابات.

سنحتاج هنا الى تجميع البيانات حسب الدولة، ثم نستدعي دالة المجموع ونُطبقها على عمود الوفيات كما يلي:

corona_by_country = corona_updated.groupby('Countries')
deaths_by_country_sum = corona_by_country['Deaths'].sum()

للحصول على أول 5 دُول تحتل أعلى مجموع وفيات نستخدم دالة head  او tail حسب حالة الترتيب:

deaths_by_country_sum = deaths_by_country_sum.sort_values(ascending=False).head(5)

لإظهار المعلومات بشكل رُسومي كما يلي:

x = deaths_by_country_sum.index.tolist()
y = deaths_by_country_sum

fig = plt.figure(figsize=(10,10))
ax = fig.add_axes([.1,.1,1,1])

ax.set_xlabel('Country')
ax.set_ylabel('Total of Deaths')
ax.set_title('The number of Deaths by first 5 coutries')
ax.set_xticklabels(x,rotation=60,horizontalalignment='center')

ax.bar(x,y)
تحليل بيانات فيروس كورونا - أول 5 دول في مجموع الوفيات
تحليل بيانات فيروس كورونا – أول 5 دول في مجموع الوفيات

السلسلة الزمنية لعدد الوفيات

نعمل في هذا العنوان على إيجاد معلومات تُوضح كيفية انتشار المرض من حيث عدد الاصابات والوفيات زمنيًا. أبرز ما يُمثل هذا الأمر هو السلسلة الزمنية Time Series والتي يكون فيها محور x عبارة عن الزمن أو بيانات مُرتبة تُمثل الزمن.

سنعمل على بناء دالة تستقبل مُعامل واحد نصي يُعبر عن دولة ما، وعند استدعاء الدالة، تُقوم برسم السلسلة الزمنية لعدد الوفيات والاصابات للدولة التي حددناها. الشيفرة البرمجية الكاملة لهذه الدالة كما يلي:

def time_series_by_country(country):
    corona_by_day_ser = corona[corona['Countries']==country].sort_values(by=['Year','Month','Day']).reset_index(drop=True)
    x = corona_by_day_ser.index
    y = corona_by_day_ser[['Deaths','Cases']]

    max_deaths_v = y['Deaths'].max()
    max_deaths_i = corona_by_day_ser['Deaths'].idxmax()

    max_cases_v =  y['Cases'].max()
    max_cases_i = corona_by_day_ser['Cases'].idxmax()

    fig = plt.figure()
    ax = fig.add_axes([.1,.1,1,1])

    ax.set_xlabel('Over time')
    ax.set_ylabel('Total of Deaths & Cases')
    ax.set_title('Sum of global deaths & cases over the time')
    ax.set_xticklabels(' ')

    ax.annotate('Max Deaths \n {} deaths'.format(max_deaths_v),xy=(max_deaths_i,max_deaths_v),xytext=( int(max_deaths_i)+5  ,int(max_deaths_v) + 50),
               arrowprops=dict(facecolor='red',shrink=0.05))

    ax.annotate('Max Cases \n {} cases'.format(max_cases_v) ,xy=(max_cases_i,max_cases_v),xytext=( int(max_cases_i)+5  ,int(max_cases_v) + 50),
               arrowprops=dict(facecolor='red',shrink=0.05))

    ax.plot(x,y)

في البداية نُعرف الدالة باسم time_series_by_country وتكون بمُعامل اسمه country سيُمثل اسم الدولة المُدخلة. نُعرف بعدها مُتغير باسم corona_by_day_ser وهو عبارة عن اطار بيانات يُمثل بيانات الدولة الُمدخلة مُرتبة حسب السنة ثم الشهر ثم اليوم مع إعادة تهيئة قيمة الفهرس ليكون مُرتبًا ترتيبًا تصاعديا يُماثل الترتيب الزمني للسجلات. سيكون مُحور x عبارة عن فهرس اطار البيانات للدولة، ومحور y عبارة عن عدد الوفيات والإصابات اليومية كما يلي:

    corona_by_day_ser = corona[corona['Countries']==country].sort_values(by=['Year','Month','Day']).reset_index(drop=True) #.sort_values(by=['Deaths']).reset_index(drop=True)
    x = corona_by_day_ser.index
    y = corona_by_day_ser[['Deaths','Cases']]

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

    max_deaths_v = y['Deaths'].max()
    max_deaths_i = corona_by_day_ser['Deaths'].idxmax()

    max_cases_v =  y['Cases'].max()
    max_cases_i = corona_by_day_ser['Cases'].idxmax()

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

    fig = plt.figure()
    ax = fig.add_axes([.1,.1,1,1])

    ax.set_xlabel('Over time')
    ax.set_ylabel('Total of Deaths & Cases')
    ax.set_title('Sum of global deaths & cases over the time')
    ax.set_xticklabels(' ')

    ax.annotate('Max Deaths \n {} deaths'.format(max_deaths_v),xy=(max_deaths_i,max_deaths_v),xytext=( int(max_deaths_i)+5  ,int(max_deaths_v) + 50),
               arrowprops=dict(facecolor='red',shrink=0.05))

    ax.annotate('Max Cases \n {} cases'.format(max_cases_v) ,xy=(max_cases_i,max_cases_v),xytext=( int(max_cases_i)+5  ,int(max_cases_v) + 50),
               arrowprops=dict(facecolor='red',shrink=0.05))

    ax.plot(x,y)

نستخدم الدالة annotate لإضافة النص على السلسة الزمنية والذي يُوضح القيمة الكُبرى لعدد الوفيات والإصابات.

عند استدعاء الدالة لدولة مثل الصين كما يلي:

time_series_by_country('China')

ستكون السلسلة الزمنية الخاصة بها كالتالي:

تحليل بيانات فيروس كورونا - السلسلة الزمنية للصين
تحليل بيانات فيروس كورونا – السلسلة الزمنية للصين

وستكون لإيطاليا وايران كما يلي:

تحليل بيانات فيروس كورونا - السلسلة الزمنية لإيران
تحليل بيانات فيروس كورونا – السلسلة الزمنية لإيران
تحليل بيانات فيروس كورونا - السلسلة الزمنية لإيطاليا
تحليل بيانات فيروس كورونا – السلسلة الزمنية لإيطاليا

إلى هنا نكون قد أتمننا عملية تحليل ملف البيانات الخاص بمرض كورونا. للحصول على مستند Jupyter الخاص بهذا المقال من خلال الرابط التالي:

مستند jupyter لتحليل بيانات فيروس كورونا

9 thoughts

  1. شكرًا جزيلًا على هذا المجهود وجعله الله في موازين حسناتك،، المثال رائع للمبتدئين ياليت كل فترة تشرح مثال متكامل نفس هذا المثال.

اترك تعليقاً

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