تطبيق عملي لعملية [استخراج، تحويل، تحميل] باستخدام البايثون

الأربعاء 09 ربيع الأول 1444ھ الأربعاء 5 أكتوبر 2022م
فيسبوك
تويتر
واتساب
تيليجرام
لينكدإن
المحتوى

المحتوى

مقدمة

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

أهداف الدرس

ماذا نريد أن نفعل؟

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

الخطوة الأولى: استدعاء المكتبات اللازمة

Step One: Import Necessary Libraries
				
					import glob                         # To select files that encompass data. لتحديد الملفات المراد استخراج البيانات منها 
import pandas as pd                 # To read CSV and JSON files. لقراءة ملفات السي إس في والجيسون
import xml.etree.ElementTree as ET  # To read XML files. لقراءة ملفات الإكس إم إل
from datetime import datetime       # To log the dates of ETL steps. لتسجيل توقيت العمليات
				
			

الخطوة الثانية: استخراج البيانات من مصادر متعددة

Step Two: Extract Data From Various Sources

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

نقوم الآن بإنشاء الملفات والوظائف التي سوف نستخدمها في عملية الـ ETL

إن الكود البرمجي في الأسفل مسؤول عن إنشاء ملفين. الملف الأول هو ملف سنقوم بتسجيل تواريخ ومواعيد العمليات فيه. والملف الثاني هو الملف الذي سوف نضع فيه البيانات بعد جمعها وتحويلها

				
					logfile    = "logfile.txt"            # The event logs will be written in this file. سوف يتم تسجيل مواعيد العمليات في هذا الملف
targetfile = "transformed_data.csv"   # The final file that includes all of the processed data. الملف النهائي الذي يحتوي على البيانات المعالجة
				
			

استخراج البيانات من ملفات السي إس في

Function 1: CSV Data Extraction
				
					# CSV extraction code is straightforward — نستطيع كتابة كود استخراج البيانات من السي اس في بطريقة مباشرة
def extract_from_csv(file_to_process):
    dataframe = pd.read_csv(file_to_process)
    return dataframe
				
			

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

Function 2: JSON Data Extraction
				
					# JSON extraction is also straightforward — استخراج البيانات من ملف الجيسون أيضا يمكن تطبيقه بطريقة مباشرة
def extract_from_json(file_to_process):
    dataframe = pd.read_json(file_to_process, lines=True)
    return dataframe
				
			

استخراج البيانات من ملفات الإكس إم إل

Function 3: XML Data Extraction
				
					# In XML files, we need to be more specific in our code to extract correct information.
# عند استخراج البيانات من ملفات الإكس إم إل، نحتاج إلى كتابة أكواد محددة تتناسب مع البيانات المتواجدة في ملف الإكس إم إل 

def extract_from_xml(file_to_process):
    dataframe = pd.DataFrame(columns=["name", "height", "weight"])
    tree = ET.parse(file_to_process)
    root = tree.getroot()
    for person in root:
        name = person.find("name").text
        height = float(person.find("height").text)
        weight = float(person.find("weight").text)
        xml_df = pd.DataFrame({"name":[name], "height":[height], "weight":[weight]})
        dataframe = pd.concat([dataframe,xml_df],ignore_index = True)
    return dataframe
				
			

عملية الاستخراج

Function 4: Extract Process
				
					# We will define a function that runs all the previous extractions functions 
# سنقوم بتعريف وظيفة تقوم بتشغيل جميع الوظائف التي تم تعريفها مسبقا
def extract(): 
    
    #  We will create an empty dataframe to hold extracted data
    #  سنقوم بعمل إطار بيانات فارغ ونقوم بجمع البيانات فيه
    extracted_data = pd.DataFrame(columns=['name','height','weight']) # The dataframe has 3 columns - اطار البيانات الذي نريد وضع البيانات فيه يحتوي على ثلاثة أعمدة
    
    # We loop through all the csv files in the working directory
    # نقوم بزيارة جميع ملفات السي إس في الموجودة في مسار العمل (أي المسار الذي فيه الملفات حاليا)
    for csvfile in glob.glob("*.csv"): 
        
        # We read the csv file, and add its data to the 'extracted_data' dataframe
        # 'extracted_data' نقوم بقراءة البيانات وإضافتها إلى إطار البيانات الذي نريد تجميع البيانات فيه
        extracted_data = pd.concat([extracted_data, extract_from_csv(csvfile)], ignore_index=True) 
        
    # We repeat the same process for json and xml files
    # نقوم بإعادة نفس العملية لملفات الجيسون والإكس إم إل
    for jsonfile in glob.glob("*.json"):
        extracted_data = pd.concat([extracted_data, extract_from_json(jsonfile)], ignore_index=True)
        
    for xmlfile in glob.glob("*.xml"):
        extracted_data = pd.concat([extracted_data, extract_from_xml(xmlfile)], ignore_index=True)
        
    return extracted_data
				
			
				
					# if you don't know what is your current working directory, run this line
# إن كنت لا تعلم ماهو مسار العمل الحالي لديك، شغل الكود الذي بالأسفل
!pwd
# Make sure to place data files in the same working directory path
# تأكد من أن جميع ملفات البيانات موجودة في مسار العمل الذي ظهر لك
				
			
/Users/salahkaf/Desktop

الخطوة الثالثة: إجراء التحويلات اللازمة على البيانات

Step Three: Transform Data

عملية التحويل

Function 5: Transform Process
				
					def transform(data):
    
        # Convert the datatype of the column into float
        # سنقوم بتحويل نوع عمودي الطول والوزن إلى النوع فلوت (أرقام تحتوي على فواصل)
        data[['height','weight']] = data[['height','weight']].astype(float) 
        
        # Convert pounds to kilograms and round off to two decimals(one pound is 0.453592 kilograms)
        # نقوم بضرب الوزن بقيمة 0.453592 ثم نقرب الرقم إلى أقرب جزء من مئة
        data['weight'] = round(data.weight * 0.453592,2)
        return data
				
			

الخطوة الرابعة: تحميل البيانات

Step Four: Load Data

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

Function 6: Load Process
				
					def load(targetfile,data_to_load): 
    # We take the final dataframe that includes the combined and transformed data, and save it in the target file
    #  سوف نقوم بأخذ إطار البيانات الذي يحتوي على البيانات المجمعة والمحولة، وحفظه في ملف السي إس في المنشأ سابقا 
    data_to_load.to_csv(targetfile) 
				
			

الخطوة الخامسة: تنفيذ عملية الـ ETL

Step Five: Deploy ETL

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

عملية التسجيل

Function 7: Logging Process
				
					# We will define a logging function to keep tracking ETL steps
# هذه الوظيفة ستقوم بتسجيل توقيت حدوث كل عملية من عمليات الـإي تي إل

def log(message):
    timestamp_format = '%Y-%h-%d-%H:%M:%S' # Year-Monthname-Day-Hour-Minute-Second
    now = datetime.now() # get current timestamp - أخذ الوقت الحالي
    timestamp = now.strftime(timestamp_format)
    
    # We create a txt file to write the loggings in it.
    # نقوم بكتابة التواريخ والأوقات في ملف التكست المنشأ سابقا 
    with open("logfile.txt","a") as log:
        log.write(timestamp + ',' + message + '\n')

				
			

بدأ عملية الإي تي إل

ETL starts
				
					log("ETL Job Started") # Log the start time — تسجيل وقت البداية
				
			
				
					log("Extract phase Started") # Log 'the extraction has started' — تسجيل أن عملية الاستخراج بدأت
extracted_data = extract()
log("Extract phase Ended") # Log 'the extraction has ended' — تسجيل أن عملية الاستخراج انتهت

display(extracted_data.head()) 
				
			
weight
height
name
172.99
1.82
Ahmed
0
156.49
1.73
Salah
1
203.03
1.71
Khalid
2
142.34
1.48
Nasser
3
184.3
1.75
Abdallah
4

نلاحظ أن البيانات قد استخرجت، ولكن ما زلنا نحتاج إلى تحويل عمود الوزن

				
					log("Transform phase Started") # Log 'the transformation has started' — تسجيل أن عملية التحويل بدأت
transformed_data = transform(extracted_data) 
log("Transform phase Ended") # Log 'the transformation has ended' — تسجيل أن عملية التحويل انتهت
transformed_data.head()
				
			
weight
height
name
78.47
1.82
Ahmed
0
70.98
1.73
Salah
1
92.09
1.71
Khalid
2
64.56
1.48
Nasser
3
83.60
1.75
Abdallah
4

الآن نحتاج فقط إلى حفظ إطار البيانات الجديد في ملف سي إس في لكي نستطيع لاحقا رفعه على قاعدة البيانات

				
					log("Load phase Started") # Log 'the loading has started' — تسجيل أن عملية التحميل بدأت
load(targetfile,transformed_data)
log("Load phase Ended") # Log 'the loading has ended' — تسجيل أن عملية التحميل انتهت
				
			
				
					log("ETL Job Ended") # Log 'the ETL has ended' — تسجيل أن عملية الإي تي إل انتهت

				
			

نستطيع الآن التحقق من النتائج

				
					display(transformed_data.head())
display(transformed_data.tail())
				
			
weight
height
name
78.47
1.82
Ahmed
0
70.98
1.73
Salah
1
92.09
1.71
Khalid
2
64.56
1.48
Nasser
3
83.60
1.75
Abdallah
4
weight
height
name
60.89
1.78
Hazem
34
78.19
1.72
Fahad
35
68.34
1.68
Yaqoub
36
60.53
1.58
Shahad
37
65.38
1.55
Maha
38
				
					display(transformed_data.describe().T)
display(transformed_data.info())
				
			
max
75%
50%
25%
min
std
mean
count
1.90
1.75
1.70
1.620
1.44
0.107550
1.682564
39.0
height
115.35
78.33
67.72
60.675
51.39
13.865491
69.995641
39.0
weight
weight
height
39.0
39.0
count
69.995641
1.682564
mean
13.865491
0.107550
std
51.39
1.44
min
60.675
1.620
25%
67.72
1.70
50%
78.33
1.75
75%
115.35
1.90
max
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 39 entries, 0 to 38
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   name    39 non-null     object 
 1   height  39 non-null     float64
 2   weight  39 non-null     float64
dtypes: float64(2), object(1)
memory usage: 1.0+ KB
None

نستطيع أيضا التحقق من مواعيد العمليات وإذا ما اكتملت المهمات بالفعل

				
					# Open the file in "read" mode ('r') 
with open('logfile.txt', 'r') as text:
    textfile = text.read()
print(textfile)
				
			
2022-Oct-03-11:57:22,ETL Job Started
2022-Oct-03-11:57:22,Extract phase Started
2022-Oct-03-11:57:23,Extract phase Ended
2022-Oct-03-11:57:23,Transform phase Started
2022-Oct-03-11:57:23,Transform phase Ended
2022-Oct-03-11:57:23,Load phase Started
2022-Oct-03-11:57:23,Load phase Ended
2022-Oct-03-11:57:23,ETL Job Ended

خطوة إضافية: تحليل البيانات

Bonus Step: Analyze Data

الآن وبعد أن تم جمع البيانات في جدول واحد منظم. نستطيع إجراء بعض التحليلات الاسكتشافية والمعروفة بـ Exploratory Data Analysis (EDA)

				
					# We have the following list that identify the gender of each customer.
# لدينا الآن قائمة إضافية تحتوي على معلومات عن جنس العميل (ذكر أو أنثى)
gender = ['M','M','M','M','M','M','M','M','M','M','M','M','M','F','M','F','F','F','F','F','F','F','F','F','F','F','F'
         ,'F','M','M','F','M','M','F','M','M','M','F','F']

# We add the list as a column as follows
# نقوم بإضافة القائمة إلى الجدول كالتالي
transformed_data['gender'] = gender
transformed_data.sample(10) # We pull 10 random columns to check - نقوم بسحب عشرة أعمدة بشكل عشوائي للتأكد من صحة الكود

				
			
gender
weight
height
name
F
53.22
1.68
Najwa
13
M
78.19
1.72
Fahad
35
F
54.11
1.44
Hind
23
F
60.82
1.62
Noha
30
F
57.81
1.53
Kholod
33
M
64.56
1.48
Nasser
3
M
78.47
1.82
Ahmed
0
M
56.38
1.54
Talal
14
M
80.49
1.79
Mossab
29
M
60.89
1.78
Hazem
34
				
					# We will import two libraries to do EDA via plotting
# سنقوم باستداعاء مكتبتين إضافيتين من أجل تحليل استكشافي عن طريق الرسم

import matplotlib.pyplot as plt # Used for plotting - ستستخدم من أجل الرسم
import numpy as np # Used to specify yticks - ستستخدم من أجل تحديد مؤشرات خط ص (او المعروف بواي أكسيس)

# First we wrtie the plotting code - نقوم بكتابة كود الرسم
transformed_data.gender.value_counts().plot(kind = 'bar',figsize=(10,6), color = ['teal','darkred']) 
# Then, we specify labels - ثم نقوم بكتابة العناوين
plt.title("Customer's Gender Distribution") # Plot title - عنوان الرسمة
plt.xlabel('Gender') # X-axis title - عنوان خط س
plt.ylabel('Number of Customers'); # Y-axis title - عنوان خط ص
plt.yticks(np.arange(1, 25, 1)); # Specify number of ticks on y axis - تحديد عدد المؤشرات على خط ص

				
			

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

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

				
					import seaborn as sns # We import seaborn library to do box plot - نقوم باستدعاء مكتبة سيبورن من إجل رسم الرسم البياني المربع

plt.figure(figsize=(12,8)) # We specify the size of the figure نقوم بتحديد حجم الرسمة
plt.subplot(1,2,1) # We use subplot to split the plot into two subplots - سوف نقوم بفصل الرسمة إلى رسمتين مصغرتين ودمجهم سويا
sns.boxplot(x='gender',y='height', data=transformed_data) # Plot height relative to gender - رسم الطول بالنسبة للجنس
plt.title('Height per Gender')
plt.subplot(1,2,2)
sns.boxplot(x='gender', y='weight',data=transformed_data) # Plot weight relative to gender - رسم الوزن بالنسبة للطول
plt.title('Weight per Gender');
				
			

من هذا الرسم البياني نستطيع أن نستنتج أن قيمة أوزان العملاء الذكور وأطوالهم أعلى من العملاء الإناث. وهو استنتاج منطقي بناء على الأرقام.

ماذا تعلمنا؟

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

اترك تعليقاً

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