تنظيف البيانات وهندسة السمات
طبّق قائمة التحقق المتقدمة للتنظيف، وأنشئ سمات للتواريخ وأعمدة للنسب، وتحقق من مجموعة البيانات المنظّفة باستخدام التأكيدات
تنظيف البيانات وهندسة السمات درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Pandas & NumPy Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
<p>استكمالًا لمشروع التخرج، حمّلوا نقطة التحقق النظيفة المحفوظة بصيغة Parquet في الخطوة السابقة. يفصل ذلك مرحلة التنظيف عن إدخال البيانات، إذ يمكنكم تكرار العمل على منطق التنظيف دون إعادة تشغيل عمليات الدمج والتحليل البطيئة. اقرأوا ملف clean_orders بصيغة Parquet وتحققوا من توافق عدد الصفوف وأنواع البيانات مع التوقعات الواردة في ملخص التدقيق. يحافظ ملف Parquet على جميع أنواع البيانات، بما فيها الأعمدة الفئوية، لذا لا حاجة إلى إعادة تحويل الأنواع.</p>
استكمالًا للمشروع الختامي، حمّل نقطة التحقق النظيفة بصيغة Parquet التي حُفظت في الخطوة السابقة. يفصل ذلك مرحلة التنظيف عن مرحلة إدخال البيانات، بحيث يمكنك تحسين منطق التنظيف دون إعادة تشغيل عمليات الدمج والتحليل البطيئة. اقرأ clean_orders بصيغة Parquet، وتحقق من أن عدد الصفوف وأنواع البيانات dtypes يطابقان التوقعات الواردة في ملخص التدقيق. يحافظ ملف Parquet على جميع أنواع البيانات، بما فيها الأعمدة الفئوية، لذا لا حاجة إلى إعادة تحويل الأنواع.
import pandas as pd
# Load from checkpoint
df = pd.read_parquet('output/clean_orders.parquet')
print(f'Loaded: {df.shape}')
print(df.dtypes)
print(f'Date range: {df["order_date"].min().date()} to {df["order_date"].max().date()}')تطبيق قائمة تدقيق التنظيف المتقدمة
بعد تحميل مجموعة البيانات المدمجة، طبّقوا قائمة تدقيق التنظيف المتقدمة: أزيلوا التكرارات المطابقة تمامًا والتكرارات الجزئية في order_id، وحدّدوا القيم الشاذة في unit_price باستخدام حدود IQR، ووحّدوا قيم category غير المتسقة (مثل 'Electronics' و'electronics' و'ELECTRONIC')، وتحققوا من أن quantity × unit_price موجب دائمًا للطلبات العادية. كل خطوة عبارة عن دالة تقبل DataFrame وتعيده، مما يجعل خط الأنابيب قابلًا للاختبار والتراجع.
import pandas as pd
import numpy as np
def remove_duplicates(df):
n_before = len(df)
df = df.drop_duplicates(subset=['order_id'], keep='first')
print(f'Duplicates removed: {n_before - len(df)}')
return df
def standardise_categories(df):
df['category'] = (df['category']
.astype(str)
.str.strip()
.str.title())
return df
def cap_price_outliers(df):
q1, q3 = df['unit_price'].quantile([0.25, 0.75])
iqr = q3 - q1
upper = q3 + 3 * iqr
df['unit_price'] = df['unit_price'].clip(upper=upper)
return df
df = remove_duplicates(df)
df = standardise_categories(df)
df = cap_price_outliers(df)
print('Cleaning complete.')هندسة ميزات التاريخ
استخرجوا الميزات الزمنية من تاريخ الطلب باستخدام أداة الوصول .dt. أنشئوا الأعمدة year وmonth وquarter وday_of_week وweek_of_year. تدعم هذه الميزات تحليلات groupby (مثل الإيرادات الشهرية)، وعمليات التصفية المستندة إلى الوقت (الربع الثالث فقط)، والتصورات البيانية. أنشئوا أيضًا عمودًا نصيًا باسم year_month (مثل '2024-06') ليكون تسمية مقروءة للفترة على محاور المخططات.
import pandas as pd
df['year'] = df['order_date'].dt.year
df['month'] = df['order_date'].dt.month
df['quarter'] = df['order_date'].dt.quarter
df['day_of_week'] = df['order_date'].dt.dayofweek # 0=Monday
df['week'] = df['order_date'].dt.isocalendar().week.astype('int32')
df['year_month'] = df['order_date'].dt.to_period('M').astype(str)
print('Date features created:')
print(df[['order_date', 'year', 'month', 'quarter', 'year_month']].head())حساب إيرادات بند الطلب
أهم ميزة أساسية في مجموعة بيانات المبيعات هي إيرادات بند الطلب: revenue = quantity × unit_price. أنشئوا ذلك في عمود جديد. وأنشئوا أيضًا عمود gross_margin إذا كانت بيانات التكلفة متاحة: margin = (price - cost) / price. تُعد هذه الأعمدة المشتقة أساس جميع مؤشرات الإيرادات الرئيسية. استخدموا دائمًا عمليات الأعمدة المتجهة بدلًا من الحلقات، إذ إن إسنادًا واحدًا إلى العمود بأكمله أسرع بكثير من التكرار صفًا صفًا.
import pandas as pd
# Line-item revenue
df['revenue'] = (df['quantity'] * df['unit_price']).astype('float32')
# Gross margin (if unit_cost column exists)
if 'unit_cost' in df.columns:
df['gross_margin'] = (df['unit_price'] - df['unit_cost']) / df['unit_price']
# Discount flag: orders with more than 20% off list price
if 'list_price' in df.columns:
df['is_discounted'] = df['unit_price'] < df['list_price'] * 0.8
print('Revenue stats:')
print(df['revenue'].describe().round(2))إسناد مجموعات العملاء
مجموعة العملاء هي مجموعة من العملاء الذين يشتركون في سمة معينة، وعادةً ما تكون الفترة الزمنية التي أجروا فيها أول عملية شراء. أسندوا كل عميل إلى مجموعة اكتسابه من خلال العثور على تاريخ طلبه الأول. استخدموا groupby('customer_id')['order_date'].min() لحساب تاريخ الطلب الأول لكل عميل، ثم أنشئوا عمود cohort_month بتحويله إلى فترة سنة-شهر. وتمثّل تسمية المجموعة هذه الأساس لمصفوفة الاحتفاظ في الدرس التالي.
import pandas as pd
# First purchase date per customer
first_purchase = (
df.groupby('customer_id')['order_date']
.min()
.dt.to_period('M')
.astype(str)
.rename('cohort_month')
)
# Merge back onto orders
df = df.merge(first_purchase, on='customer_id', how='left')
print('Cohort distribution (top 5):')
print(df['cohort_month'].value_counts().head())
print(f'Distinct cohorts: {df["cohort_month"].nunique()}')ميزات القيمة الدائمة للعميل
احسبوا الميزات التلخيصية على مستوى العميل: إجمالي الطلبات، وإجمالي الإيرادات، ومتوسط قيمة الطلب، وعدد الأيام منذ أول وآخر عملية شراء، وعدد الفئات المختلفة التي تم شراؤها. ادمجوا هذه الميزات مرة أخرى مع DataFrame الرئيسي بوصفها أعمدة إثراء على مستوى العميل. تُستخدم هذه الميزات في تقسيم العملاء (مثل العملاء ذوي القيمة المرتفعة والمنخفضة) ومدخلات نماذج التعلم الآلي التي تتنبأ باحتمال فقدان العميل أو زيادة مبيعاته.
import pandas as pd
customer_stats = df.groupby('customer_id').agg(
total_orders=('order_id', 'nunique'),
total_revenue=('revenue', 'sum'),
avg_order_value=('revenue', 'mean'),
categories_purchased=('category', 'nunique'),
first_order=('order_date', 'min'),
last_order=('order_date', 'max')
).reset_index()
customer_stats['days_as_customer'] = (
(customer_stats['last_order'] - customer_stats['first_order'])
.dt.days
)
print(customer_stats.describe().round(2))التحقق من المخطط باستخدام التأكيدات
بعد هندسة الميزات، شغّلوا تأكيدات التحقق من المخطط للتأكد من أن البيانات تستوفي التوقعات قبل تمريرها إلى مرحلة التحليل. تحققوا من وجود جميع الأعمدة المتوقعة، ومن أن الإيرادات غير سالبة للطلبات العادية، وأن cohort_month غير فارغ، وأن year_month يطابق سنة التحليل. تعمل هذه التأكيدات كعقد: فإذا فشل أي منها، يتوقف خط الأنابيب فورًا مع رسالة خطأ واضحة بدلًا من إنتاج نتائج خاطئة دون تنبيه.
import pandas as pd
def validate_clean_df(df):
required_cols = ['order_id', 'customer_id', 'revenue', 'year_month',
'cohort_month', 'category', 'region', 'order_date']
missing = [c for c in required_cols if c not in df.columns]
assert not missing, f'Missing columns: {missing}'
assert (df['revenue'] >= 0).all(), 'Negative revenue found'
assert df['cohort_month'].notna().all(), 'Null cohort_month values'
assert df['order_date'].notna().all(), 'Null order dates'
print(f'Validation passed: {len(df):,} rows, {len(df.columns)} columns')
validate_clean_df(df)معالجة الفئات منخفضة التكرار
في مجموعات البيانات الواقعية، تظهر بعض الفئات أو المناطق مرات قليلة فقط، وهو عدد لا يكفي لإجراء تحليل ذي معنى. استبدلوا القيم منخفضة التكرار بـ 'Other' لتجنب ازدحام المخططات بعشرات الفئات التي لا تحتوي إلا على طلب واحد. ومن الحدود العملية أن تُدمج القيم التي تظهر في أقل من 0.5% من الصفوف. وهذا مهم أيضًا للتعلم الآلي، إذ إن ترميز 200 فئة نادرة بطريقة one-hot يهدر الذاكرة ويضيف ضوضاء.
import pandas as pd
def collapse_rare_values(df, col, min_pct=0.005):
threshold = len(df) * min_pct
counts = df[col].value_counts()
rare = counts[counts < threshold].index
n_rare = len(rare)
df[col] = df[col].apply(lambda x: 'Other' if x in rare else x)
print(f'{col}: collapsed {n_rare} rare values into "Other"')
return df
df = collapse_rare_values(df, 'category', min_pct=0.005)
df = collapse_rare_values(df, 'region', min_pct=0.005)
print('Category distribution after collapsing:')
print(df['category'].value_counts())حفظ مجموعة البيانات بعد هندسة الميزات
احفظوا DataFrame المنظف بالكامل، وبعد هندسة ميزاته، كنقطة تحقق بصيغة Parquet. هذه هي مجموعة البيانات الجاهزة للتحليل، أي ناتج جميع خطوات إدخال البيانات وتنظيفها وهندسة ميزاتها. تقرأ مراحل خط الأنابيب اللاحقة (حساب مؤشرات الأداء الرئيسية، والتصور، وإعداد التقارير) من نقطة التحقق هذه. كما تمثّل نقطة التحقق مخرجًا يمكن تسليمه، إذ يمكن مشاركتها مع أعضاء الفريق أو تحميلها إلى بحيرة بيانات ليتمكن الآخرون من الاستعلام عنها باستخدام SQL أو Pandas.
import pandas as pd
# Convert category columns back to Categorical for memory efficiency
for col in ['category', 'region', 'acquisition_channel']:
if col in df.columns:
df[col] = df[col].astype('category')
# Save analysis-ready dataset
df.to_parquet('output/analysis_ready.parquet', index=False)
# Also save customer stats for segmentation
customer_stats.to_parquet('output/customer_stats.parquet', index=False)
print(f'Analysis-ready dataset: {df.shape}')
print(f'Memory usage: {df.memory_usage(deep=True).sum()/1e6:.1f} MB')ملخص هندسة الميزات
توازن هندسة الميزات الجيدة بين إضافة إشارات تنبؤية والحفاظ على قابلية خط الأنابيب للفهم والاختبار. وقد استندت الميزات التي أُنشئت في هذه المرحلة — الإيرادات، وأجزاء التاريخ، وcohort_month، وإحصاءات العملاء، والفئات المدمجة — إلى أهداف التحليل المحددة في إعداد المشروع. تجنبوا إغراء إنشاء عشرات الميزات بصورة افتراضية. اطرحوا السؤال التالي بشأن كل ميزة: هل ستُستخدم في مؤشر أداء رئيسي واحد على الأقل أو في تصور بياني؟ إذا لم تكن كذلك، فأجّلوها. حافظوا على أن تكون مجموعة البيانات الجاهزة للتحليل مختصرة وهادفة.
import pandas as pd
# Summary of engineered features
df = pd.read_parquet('output/analysis_ready.parquet')
original_cols = ['order_id', 'customer_id', 'order_date', 'quantity', 'unit_price']
engineered_cols = [c for c in df.columns if c not in original_cols]
print('Original columns:', original_cols)
print('Engineered features:', engineered_cols)
print(f'Total columns: {len(df.columns)}')
print(f'Total rows: {len(df):,}')توثيق القرارات في الشيفرة
أضيفوا، لكل قرار غير بديهي يتعلق بالتنظيف أو هندسة الميزات، تعليقًا يوضح السبب. فلن تتذكروا مستقبلًا (أو لن يتذكر أحد أعضاء الفريق) سبب ضبط معامل IQR على 3 بدلًا من 1.5، أو سبب استخدام 0.5% حدًا للفئات النادرة. تجعل التعليقات المضمنة وسجل القرارات (قائمة بسيطة في README الخاص بالمشروع أو في ملف Markdown) خط الأنابيب قابلًا للصيانة والتدقيق. فالشيفرة النظيفة والموثقة هي المخرج الحقيقي، أما ملفات النتائج فليست سوى أثر لها.
# Engineering decisions log
DECISIONS = '''
# Data Cleaning & Feature Engineering Decisions
## Duplicate handling
Kept first occurrence of duplicate order_id (most likely the original order).
## Outlier capping
Unit price capped at Q3 + 3*IQR (not 1.5*IQR) because price distribution
has legitimate high-value enterprise orders that should not be removed.
## Rare category threshold: 0.5%
Values below 0.5% of total orders collapsed to "Other" to keep charts readable
and avoid spurious significance in category-level tests.
## Cohort assignment
Cohort = first purchase calendar month (not signup month), because many users
sign up but do not purchase until months later.
'''
print(DECISIONS)تحقق سريع
اختبروا مدى فهمكم لمفاهيم تحليل البيانات الواردة في هذا الدرس.
مراجعة الدرس
تعلّمتم في هذا الدرس أن دوال التنظيف المعيارية (إزالة التكرارات، وتحديد القيم الشاذة، وتوحيد الفئات) تقبل DataFrame وتعيده لتسهيل الاختبار، وأن هندسة الميزات أنشأت أجزاء التاريخ، وإيرادات بنود الطلبات، ومجموعات العملاء، والإحصاءات التلخيصية، وأن تأكيدات التحقق من المخطط تحمي الانتقال من التنظيف إلى التحليل. سننتقل بعد ذلك إلى حساب مؤشرات الأداء الرئيسية للمشروع: الاحتفاظ الشهري بمجموعات العملاء، وإيرادات المنتجات، والمستخدمون النشطون المتحركون.
الأسئلة الشائعة
هل درس «تنظيف البيانات وهندسة السمات» مجاني؟
نعم — نص درس «تنظيف البيانات وهندسة السمات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
ماذا ستتعلم في «تنظيف البيانات وهندسة السمات»؟
طبّق قائمة التحقق المتقدمة للتنظيف، وأنشئ سمات للتواريخ وأعمدة للنسب، وتحقق من مجموعة البيانات المنظّفة باستخدام التأكيدات تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟
لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «تنظيف البيانات وهندسة السمات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟
نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- إعداد المشروع واستيعاب البيانات
- تنظيف البيانات وهندسة السمات
- التحليل وحساب مؤشرات الأداء الرئيسية
- التصور النهائي وتصدير التقرير