ما هو تحليل البيانات؟ دليل عملي لتصوير البيانات باستخدام بايثون وNumpy وPandas وMatplotlib وSeaborn

دقائق القراءة: 10

مقدمة: لماذا يُعد تحليل البيانات مهارة أساسية اليوم؟

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

في الواقع، يجمع تحليل البيانات بين جانبين مهمين:

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

في هذا الدليل ستتعرّف إلى الأساسيات التي يحتاجها أي مبتدئ أو ممارس يريد فهم مسار العمل في تحليل البيانات باستخدام لغة Python، ومكتبات Numpy وPandas وMatplotlib وSeaborn.

غلاف تعليمي يشرح تحليل البيانات وتصوير البيانات باستخدام بايثون ومكتبات Numpy وPandas وMatplotlib وSeaborn

ما المقصود بالحوسبة العددية في تحليل البيانات؟

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

وهنا تظهر أهمية مكتبة Numpy، لأنها توفر بنية قوية للتعامل مع المصفوفات والعمليات العددية بسرعة تفوق القوائم التقليدية في Python.

رسم توضيحي يشرح الحوسبة العددية واستخدام مكتبة Numpy في لغة بايثون

مثال بسيط: التنبؤ بإنتاج محصول اعتماداً على المناخ

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

yield_of_apples = w1 * temperature + w2 * rainfall + w3 * humidity

هذه المعادلة لا تمثل الواقع بالكامل، لكنها نموذج أولي مفيد لتوضيح الفكرة. بعد تحليل البيانات التاريخية قد نختار قيماً تقريبية للأوزان:

w1, w2, w3 = 0.3, 0.2, 0.5

وبعد ذلك يمكن إدخال بيانات منطقة معيّنة:

kanto_temp = 73
kanto_rainfall = 67
kanto_humidity = 43

kanto_yield_apples = kanto_temp * w1 + kanto_rainfall * w2 + kanto_humidity * w3
print("The expected yield of apples in Kanto region is {} tons per hectare.".format(kanto_yield_apples))

هذه الطريقة تعمل، لكنها تصبح مرهقة حين نريد التوسع والتعامل مع عدة مناطق أو آلاف السجلات.

كيف نحول القوائم إلى مصفوفات باستخدام Numpy؟

بدلاً من تمثيل بيانات كل منطقة في متغيرات منفصلة، يمكننا وضعها داخل قائمة:

kanto = [73, 67, 43]
johto = [91, 88, 64]
hoenn = [87, 134, 58]
sinnoh = [102, 43, 37]
unova = [69, 96, 70]
weights = [w1, w2, w3]

ثم يمكن إنشاء دالة لحساب الناتج:

def crop_yield(region, weights):
    result = 0
    for x, w in zip(region, weights):
        result += x * w
    return result

لكن في Numpy تصبح العملية أبسط وأسرع. أولاً نثبت المكتبة ثم نستوردها:

!pip install numpy --upgrade --quiet
import numpy as np

بعدها نحوّل القوائم إلى مصفوفات:

kanto = np.array([73, 67, 43])
weights = np.array([0.3, 0.2, 0.5])

وبذلك يمكننا تنفيذ الضرب النقطي مباشرة عبر الدالة np.dot():

np.dot(kanto, weights)

كما يمكن الوصول إلى النتيجة نفسها عبر ضرب العناصر ثم جمعها:

(kanto * weights).sum()

لماذا تُعد مصفوفات Numpy أفضل من القوائم؟

  • تسمح بكتابة تعبيرات رياضية أوضح وأقصر.
  • توفر أداءً أعلى بكثير عند العمل على بيانات ضخمة.
  • تدعم عمليات متجهية ومصفوفية جاهزة دون الحاجة إلى حلقات يدوية كثيرة.

فعند مقارنة for loop مع np.dot() على مليون عنصر، تكون Numpy أسرع بفارق كبير، وهذا فارق حاسم في التطبيقات الواقعية.

المصفوفات متعددة الأبعاد في Numpy

عند التعامل مع أكثر من سجل، يمكن جمع البيانات كلها في مصفوفة ثنائية الأبعاد:

climate_data = np.array([
    [73, 67, 43],
    [91, 88, 64],
    [87, 134, 58],
    [102, 43, 37],
    [69, 96, 70]
])

كل صف يمثل منطقة، وكل عمود يمثل متغيراً مناخياً. ويمكن معرفة شكل المصفوفة عبر الخاصية .shape:

climate_data.shape
weights.shape

شرح بصري لأبعاد مصفوفات Numpy وكيفية قراءة خاصية shape

كذلك يمكن فحص نوع البيانات عبر .dtype، وهي خاصية مهمة لأن عناصر مصفوفة Numpy يجب أن تكون من نوع متجانس غالباً.

الضرب المصفوفي لحساب النتائج دفعة واحدة

إذا كانت لدينا مصفوفة بحجم 5x3 ومتجه أوزان بطول 3، فيمكن ضربهما مصفوَفياً للحصول على نتائج كل المناطق مرة واحدة:

np.matmul(climate_data, weights)
climate_data @ weights

رسم يوضح الضرب المصفوفي في Numpy بين بيانات مناخية ومتجه أوزان

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

قراءة ملفات CSV والتعامل معها باستخدام Numpy

صيغة CSV من أكثر الصيغ شيوعاً لتخزين البيانات الجدولية. يمكن قراءة ملف باستخدام الدالة np.genfromtxt():

import urllib.request
urllib.request.urlretrieve(
    'https://hub.jovian.ml/wp-content/uploads/2020/08/climate.csv',
    'climate.txt'
)

climate_data = np.genfromtxt('climate.txt', delimiter=',', skip_header=1)

بعد تحميل البيانات يمكن حساب الإنتاج المتوقع كاملاً:

weights = np.array([0.3, 0.2, 0.5])
yields = climate_data @ weights

ثم إلحاق النتائج كعمود جديد باستخدام np.concatenate() بعد إعادة تشكيل المتجه عبر reshape():

climate_results = np.concatenate((climate_data, yields.reshape(10000, 1)), axis=1)

مخطط يشرح دمج الأعمدة في Numpy باستخدام concatenate مع axis يساوي 1

وأخيراً يمكن حفظ النتائج:

np.savetxt(
    'climate_results.txt',
    climate_results,
    fmt='%.2f',
    delimiter=',',
    header='temperature,rainfall,humidity,yeild_apples',
    comments=''
)

عمليات Numpy الأساسية: الحسابات وBroadcasting والمقارنة

العمليات الحسابية

تدعم مصفوفات Numpy عمليات مثل + و- و* و/ و%، سواء مع قيمة مفردة أو مع مصفوفة أخرى متوافقة في الشكل.

arr2 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 1, 2, 3]])
arr3 = np.array([[11, 12, 13, 14], [15, 16, 17, 18], [19, 11, 12, 13]])

arr2 + 3
arr3 - arr2
arr2 / 2
arr2 * arr3
arr2 % 4

ما هو Broadcasting؟

تسمح هذه الآلية بتنفيذ عمليات بين مصفوفتين مختلفتي الأبعاد إذا كان شكلهما متوافقاً. مثال ذلك:

arr2 = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 1, 2, 3]])
arr4 = np.array([4, 5, 6, 7])
arr2 + arr4

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

رسم توضيحي لمفهوم Broadcasting في Numpy عند إجراء العمليات بين مصفوفات مختلفة الأبعاد

عمليات المقارنة

يمكن مقارنة العناصر باستخدام == و!= و>= و< وغيرها، وتكون النتيجة مصفوفة من القيم المنطقية:

arr1 = np.array([[1, 2, 3], [3, 4, 5]])
arr2 = np.array([[2, 2, 3], [1, 2, 5]])

arr1 == arr2
(arr1 == arr2).sum()

هذا النوع من العمليات أساسي في التنظيف، والفلترة، والتحقق من الشروط داخل البيانات.

الفهرسة والاقتطاع في مصفوفات Numpy

تدعم Numpy فهرسة متعددة الأبعاد بطريقة مرنة، ما يسمح باستخراج عنصر أو نطاق محدد بسهولة:

arr3 = np.array([
    [[11, 12, 13, 14], [13, 14, 15, 19]],
    [[15, 16, 17, 21], [63, 92, 36, 18]],
    [[98, 32, 81, 23], [17, 18, 19.5, 43]]
])

arr3[1, 1, 2]
arr3[1:, 0:1, :2]
arr3[1:, 1, :3]

صورة تعليمية تشرح الفهرسة والاقتطاع في مصفوفات Numpy متعددة الأبعاد

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

طرق إضافية لإنشاء مصفوفات في Numpy

توفر المكتبة دوال مفيدة لإنشاء مصفوفات جاهزة:

np.zeros((3, 2))
np.ones([2, 2, 3])
np.eye(3)
np.random.rand(5)
np.random.randn(2, 3)
np.full([2, 3], 42)
np.arange(10, 90, 3)
np.linspace(3, 27, 9)

هذه الأدوات مهمة عند بناء عينات تجريبية، أو تهيئة أوزان، أو إعداد بيانات لاختبار الخوارزميات.

تحليل البيانات الجدولية باستخدام Pandas

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

صورة توضيحية لبدء تحليل البيانات الجدولية باستخدام مكتبة Pandas في بايثون

قراءة ملف CSV إلى DataFrame

!pip install pandas --upgrade --quiet
import pandas as pd
from urllib.request import urlretrieve

urlretrieve(
    'https://hub.jovian.ml/wp-content/uploads/2020/09/italy-covid-daywise.csv',
    'italy-covid-daywise.csv'
)

covid_df = pd.read_csv('italy-covid-daywise.csv')

يتم تخزين البيانات هنا داخل كائن DataFrame، وهو البنية الأشهر في Pandas.

استكشاف البنية العامة للبيانات

يمكن فهم الملف سريعاً عبر الأوامر التالية:

covid_df.info()
covid_df.describe()
covid_df.columns
covid_df.shape

هذه الأساليب تمنحك نظرة أولية مهمة حول أنواع الأعمدة، وعدد القيم غير الفارغة، والإحصاءات الأساسية، وأبعاد الجدول.

الوصول إلى الأعمدة والصفوف والقيم

covid_df['new_cases']
covid_df.at[246, 'new_cases']
covid_df.loc[243]
covid_df.head(5)
covid_df.tail(4)
covid_df.sample(10)

يمثل كل عمود كائناً من نوع Series، وهو مناسب للعمليات التحليلية السريعة على مستوى عمود واحد.

التعامل مع القيم المفقودة NaN

في البيانات الواقعية ستواجه قيماً مفقودة أو غير متاحة. في هذا المثال، بعض قيم new_tests غير موجودة، ولذلك تظهر كـ NaN وليس 0. والفرق بينهما جوهري:

  • 0 يعني أن القيمة موجودة وتساوي صفراً.
  • NaN يعني أن القيمة غير معروفة أو مفقودة.

يمكن إيجاد أول قيمة صالحة باستخدام:

covid_df.new_tests.first_valid_index()

تحليل البيانات داخل Pandas

حساب المؤشرات الأساسية

total_cases = covid_df.new_cases.sum()
total_deaths = covid_df.new_deaths.sum()
death_rate = covid_df.new_deaths.sum() / covid_df.new_cases.sum()

هذه العمليات البسيطة توضح مدى قوة Pandas في الاشتغال على الأعمدة كما لو كانت كيانات تحليلية مستقلة.

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

إذا أردنا استخراج الأيام التي تجاوز فيها عدد الإصابات 1000 حالة:

high_cases_df = covid_df[covid_df.new_cases > 1000]

كما يمكن صياغة شروط أكثر تعقيداً تشمل أكثر من عمود أو ناتج عملية حسابية.

إضافة أعمدة جديدة وإزالتها

covid_df['positive_rate'] = covid_df.new_cases / covid_df.new_tests
covid_df.drop(columns=['positive_rate'], inplace=True)

هذه الخطوة شائعة جداً عند اشتقاق مؤشرات جديدة من الأعمدة الأصلية.

ترتيب الصفوف حسب القيم

covid_df.sort_values('new_cases', ascending=False).head(10)

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

معالجة التواريخ في Pandas

الأعمدة الزمنية تمنح التحليل بعداً إضافياً. في البداية يكون عمود التاريخ من نوع object، لذلك يجب تحويله:

covid_df['date'] = pd.to_datetime(covid_df.date)

بعد ذلك يمكن استخراج أجزاء التاريخ:

covid_df['year'] = pd.DatetimeIndex(covid_df.date).year
covid_df['month'] = pd.DatetimeIndex(covid_df.date).month
covid_df['day'] = pd.DatetimeIndex(covid_df.date).day
covid_df['weekday'] = pd.DatetimeIndex(covid_df.date).weekday

هذه المعلومات مفيدة جداً عند تحليل الأداء شهرياً أو أسبوعياً أو مقارنة أيام الأسبوع ببعضها.

التجميع والدمج والتراكم في Pandas

التجميع باستخدام groupby()

covid_month_df = covid_df.groupby('month')[['new_cases', 'new_deaths', 'new_tests']].sum()

التجميع الشهري أو السنوي يسهّل رؤية الاتجاهات الكبرى بدلاً من التشتت في البيانات اليومية.

المجاميع التراكمية

covid_df['total_cases'] = covid_df.new_cases.cumsum()
covid_df['total_deaths'] = covid_df.new_deaths.cumsum()
covid_df['total_tests'] = covid_df.new_tests.cumsum() + 935310

المجموع التراكمي مفيد لفهم تطور الحالة بمرور الزمن وليس فقط قراءة كل يوم بشكل معزول.

دمج البيانات من مصادر متعددة

غالباً لا تكفيك مجموعة بيانات واحدة. مثلاً، لحساب الإصابات لكل مليون نسمة، تحتاج إلى بيانات السكان:

locations_df = pd.read_csv('locations.csv')
covid_df['location'] = 'Italy'
merged_df = covid_df.merge(locations_df, on='location')

ثم يمكن اشتقاق مؤشرات إضافية:

merged_df['cases_per_million'] = merged_df.total_cases * 1e6 / merged_df.population
merged_df['deaths_per_million'] = merged_df.total_deaths * 1e6 / merged_df.population
merged_df['tests_per_million'] = merged_df.total_tests * 1e6 / merged_df.population

إعادة كتابة النتائج إلى ملف

result_df = merged_df[[
    'date', 'new_cases', 'total_cases', 'new_deaths', 'total_deaths',
    'new_tests', 'total_tests', 'cases_per_million',
    'deaths_per_million', 'tests_per_million'
]]

result_df.to_csv('results.csv', index=None)

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

تصوير البيانات باستخدام Matplotlib وSeaborn

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

واجهة تعليمية تشرح أساسيات تصوير البيانات في بايثون باستخدام Matplotlib وSeaborn

!pip install matplotlib seaborn --upgrade --quiet
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

المخططات الخطية Line Charts

المخطط الخطي من أكثر الرسوم استخداماً لعرض تغير قيمة عبر الزمن.

years = [2010, 2011, 2012, 2013, 2014, 2015]
yield_apples = [0.895, 0.91, 0.919, 0.926, 0.929, 0.931]

plt.plot(years, yield_apples)
plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')

ويمكن رسم أكثر من خط ومقارنتهما داخل الشكل نفسه:

years = range(2000, 2012)
apples = [0.895, 0.91, 0.919, 0.926, 0.929, 0.931, 0.934, 0.936, 0.937, 0.9375, 0.9372, 0.939]
oranges = [0.962, 0.941, 0.930, 0.923, 0.918, 0.908, 0.907, 0.904, 0.901, 0.898, 0.9, 0.896]

plt.plot(years, apples, marker='o')
plt.plot(years, oranges, marker='x')
plt.xlabel('Year')
plt.ylabel('Yield (tons per hectare)')
plt.title('Crop Yields in Kanto')
plt.legend(['Apples', 'Oranges'])

تحسين الشكل العام باستخدام Seaborn

sns.set_style('whitegrid')

تمنح هذه الخطوة الرسوم مظهراً أنظف وأسهل للقراءة، وهو أمر مهم عند إعداد تقارير مهنية أو محتوى تعليمي.

المخططات المبعثرة Scatter Plots

تُستخدم المخططات المبعثرة لفهم العلاقة بين متغيرين. مثال مشهور على ذلك مجموعة بيانات iris:

flowers_df = sns.load_dataset('iris')
sns.scatterplot(x=flowers_df.sepal_length, y=flowers_df.sepal_width)

ويمكن تحسين القراءة بإضافة hue لتمييز الفئات:

sns.scatterplot(
    x=flowers_df.sepal_length,
    y=flowers_df.sepal_width,
    hue=flowers_df.species,
    s=100
)

هذا النوع من الرسوم مفيد جداً في اكتشاف التجمعات والعلاقات غير الخطية والقيم الشاذة.

المدرجات التكرارية Histograms

إذا أردت فهم توزيع متغير معين، فالمدرج التكراري هو الخيار الأنسب:

plt.hist(flowers_df.sepal_width)

كما يمكن التحكم في عدد الصناديق bins أو حدودها:

plt.hist(flowers_df.sepal_width, bins=5)
plt.hist(flowers_df.sepal_width, bins=np.arange(2, 5, 0.25))

هذا يفيد في فهم مدى تركز القيم، وتحديد القمم، والكشف عن الانحراف في التوزيع.

المخططات الشريطية Bar Charts

المخطط الشريطي مناسب لمقارنة قيم منفصلة أو متوسطات عبر فئات محددة:

years = range(2000, 2006)
apples = [0.35, 0.6, 0.9, 0.8, 0.65, 0.8]
oranges = [0.4, 0.8, 0.9, 0.7, 0.6, 0.8]

plt.bar(years, oranges)

أما في Seaborn فيمكن حساب المتوسطات مباشرة:

tips_df = sns.load_dataset('tips')
sns.barplot(x='day', y='total_bill', data=tips_df)

وبإضافة hue يمكن المقارنة بين مجموعات فرعية مختلفة داخل الفئة نفسها.

الخرائط الحرارية Heatmaps

الخرائط الحرارية ممتازة لعرض البيانات الثنائية الأبعاد مثل الجداول والمحاور الزمنية:

flights_df = sns.load_dataset('flights').pivot('month', 'year', 'passengers')
plt.title('No. of Passengers (1000s)')
sns.heatmap(flights_df, fmt='d', annot=True, cmap='Blues')

تعطيك الخريطة الحرارية فهماً سريعاً لفترات الذروة والانخفاض من خلال اللون قبل حتى قراءة الأرقام.

عرض الصور باستخدام Matplotlib

يمكن كذلك استخدام Matplotlib لعرض الصور باعتبارها مصفوفات رقمية:

from urllib.request import urlretrieve
from PIL import Image

urlretrieve('https://i.imgur.com/SkPbq.jpg', 'chart.jpg')
img = Image.open('chart.jpg')
img_array = np.array(img)

plt.grid(False)
plt.title('A data science meme')
plt.axis('off')
plt.imshow(img)

هذه الفكرة مفيدة خصوصاً في تطبيقات الرؤية الحاسوبية ومعالجة الصور.

رسم عدة مخططات داخل شبكة واحدة

عند إعداد لوحة معلومات صغيرة أو مقارنة أكثر من رسم، يمكن استخدام plt.subplots():

fig, axes = plt.subplots(2, 3, figsize=(16, 8))

هذه التقنية مفيدة جداً في التقارير التحليلية لأنها تتيح جمع أكثر من منظور بصري داخل صفحة واحدة.

أفضل ممارسات عملية لتحليل البيانات وتصويرها

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

مقارنة سريعة بين المكتبات المستخدمة

المكتبة الاستخدام الأساسي أبرز نقطة قوة
Numpy الحوسبة العددية والمصفوفات سرعة عالية في العمليات الرياضية
Pandas تحليل البيانات الجدولية سهولة القراءة والفلترة والتجميع
Matplotlib الرسم البياني الأساسي مرونة كبيرة في التخصيص
Seaborn الرسوم الإحصائية المتقدمة مظهر أفضل وتكامل ممتاز مع Pandas

الخلاصة التقنية

تحليل البيانات ليس مجرد كتابة أوامر برمجية، بل هو منهجية تبدأ بفهم السؤال، ثم تجهيز البيانات، ثم تحليلها، وأخيراً عرض النتائج بصرياً بطريقة تدعم القرار. عملياً، يشكل الجمع بين Numpy وPandas وMatplotlib وSeaborn حزمة متكاملة لأي محلل بيانات يعمل بلغة Python. وإذا أتقنت هذه الأدوات، فستمتلك أساساً قوياً للانتقال إلى مراحل أكثر تقدماً مثل التعلم الآلي، ولوحات المعلومات التفاعلية، والتحليلات التنبؤية.

اترك تعليقاً

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