هندسة الميزات (Feature Engineering): كيف تستخرج بيانات جديدة من البيانات الحالية؟
هندسة الميزات (Feature Engineering): كيف تستخرج بيانات جديدة من البيانات الحالية؟
تُعد Feature Engineering من أكثر المراحل تأثيراً في نجاح أي مشروع Machine Learning أو تحليل تنبؤي متقدم. الفكرة الأساسية ليست جمع بيانات أكثر فقط، بل إعادة صياغة البيانات الحالية إلى إشارات أكثر وضوحاً للنموذج، بحيث تصبح الأنماط الخفية قابلة للتعلّم والاستنتاج بدقة أعلى.
في كثير من الحالات، يكون أداء النموذج المتوسط على بيانات مُهندسة جيداً أفضل من نموذج معقد جداً على بيانات خام. لهذا السبب ترتبط هندسة الميزات مباشرة بمراحل التحضير التي ناقشناها سابقاً في مدخل إلى علوم البيانات: كيف تحول الأرقام العشوائية إلى قرارات استراتيجية؟، كما تعتمد عملياً على تنظيف البيانات، وفهم البنية، واختيار التمثيل الأنسب لكل حقل.
ما المقصود بهندسة الميزات ولماذا هي حاسمة؟
المقصود بـ Feature هو متغير يُستخدم كمدخل للنموذج. أما Feature Engineering فهي عملية إنشاء متغيرات جديدة أو تحويل المتغيرات الحالية بحيث تعبّر بصورة أفضل عن السلوك الحقيقي للبيانات.
على سبيل المثال، تاريخ الشراء الخام قد لا يكون مفيداً بحد ذاته، لكن استخراج اليوم، الشهر، الموسم، أو الفرق الزمني منذ آخر عملية شراء، قد يكشف أنماطاً سلوكية قوية. كذلك فإن الراتب الشهري وقيمة القرض قد لا يكفيان منفردين، لكن نسبة debt_to_income قد تكون أكثر قدرة على تفسير المخاطر.
في بيئات
Big Data، لا تكمن الصعوبة في بناء الميزات فقط، بل في ضمان اتساق تعريفها بين بيئات التطوير والإنتاج. أي اختلاف في منطق احتساب الميزة بينNotebookوPipelineالإنتاجي قد يؤدي إلى انحراف تنبؤي خطير يعرف باسمTraining-Serving Skew.
الأساس الصحيح قبل بناء أي ميزة جديدة
قبل التفكير في الاشتقاق والتحويل، يجب أولاً فهم جودة البيانات الخام. إذا كانت القيم المفقودة، التكرارات، أو القيم الشاذة غير معالجة، فإن أي ميزة مشتقة ستعيد تضخيم الخطأ بدلاً من تقليله. لذلك من الطبيعي أن تسبق هذه المرحلة موضوعات مثل تنظيف البيانات (Data Cleaning): اكتشاف ومعالجة القيم المفقودة (Missing Values) ومعالجة البيانات المكررة والمشوهة (Duplicates & Outliers) باستخدام بايثون.
كما أن فهم بنية الجدول أمر محوري، خاصة عند التعامل مع DataFrame يحتوي على متغيرات عددية، نصية، زمنية، وتصنيفية. لهذا يفيد الرجوع إلى مكتبة Pandas (2): استكشاف هيكل البيانات وفهم DataFrame و Series قبل هندسة الميزات على مجموعات بيانات معقدة.
أشهر استراتيجيات هندسة الميزات
1) استخراج ميزات زمنية
الأعمدة الزمنية من أغنى المصادر لبناء ميزات عالية القيمة. من حقل واحد مثل order_date يمكن استخراج:
- اليوم والشهر والسنة.
- رقم الأسبوع.
- هل العملية تمت في عطلة نهاية الأسبوع.
- الفارق الزمني منذ آخر حدث
recency.
2) بناء النسب والمؤشرات المركبة
الميزات المركبة تعطي النموذج وصفاً أكثر ذكاءً من القيم المطلقة. بدلاً من مقارنة الإنفاق وحده، يمكن استخدام متوسط الإنفاق لكل معاملة أو نسبة الخصم إلى السعر الأصلي. هذا النوع من المشتقات مهم جداً في قطاعات التمويل، التجارة الإلكترونية، والعمليات التشغيلية.
3) الترميز للمتغيرات التصنيفية
المتغيرات النصية مثل المدينة أو نوع العميل لا يمكن للنموذج الاستفادة منها مباشرة غالباً. هنا نلجأ إلى تحويلها باستخدام One-Hot Encoding أو Target Encoding أو التجميع في فئات أعلى. الاختيار هنا يعتمد على عدد الفئات، حجم البيانات، ونوع النموذج المستخدم.
4) التجميع الإحصائي عبر الكيانات
عند وجود سجلات متعددة لكل عميل أو منتج، يمكن إنشاء ميزات تجميعية مثل متوسط الشراء، عدد الطلبات، أعلى قيمة فاتورة، أو معدل الإرجاع. هذا يعتمد كثيراً على مهارات التجميع والتلخيص (Groupby & Aggregation): إنشاء تقارير إحصائية برمجية وكذلك على دمج الجداول من مصادر متعددة كما في دمج وتوحيد الجداول (Merge, Join, Concat) لبناء قاعدة بيانات تحليلية شاملة.
مثال عملي باستخدام Pandas
في المثال التالي سنحوّل بيانات مبيعات خام إلى مجموعة ميزات أكثر قابلية للاستخدام في التحليل أو النمذجة:
import pandas as pd
import numpy as np
df = pd.read_csv("sales_data.csv")
df["order_date"] = pd.to_datetime(df["order_date"])
df["day_of_week"] = df["order_date"].dt.dayofweek
df["month"] = df["order_date"].dt.month
df["is_weekend"] = df["day_of_week"].isin([5, 6]).astype(int)
df["discount_ratio"] = df["discount_amount"] / df["original_price"].replace(0, np.nan)
df["net_revenue"] = df["quantity"] * df["sale_price"] - df["discount_amount"]
customer_stats = (
df.groupby("customer_id")
.agg(
total_orders=("order_id", "nunique"),
avg_order_value=("net_revenue", "mean"),
total_quantity=("quantity", "sum")
)
.reset_index()
)
df = df.merge(customer_stats, on="customer_id", how="left")
df["revenue_per_item"] = df["net_revenue"] / df["quantity"].replace(0, np.nan)
print(df.head())
هذا المثال يبني ميزات زمنية، مالية، وتجميعية في آن واحد. وإذا كنت تعمل على ملفات أولية، فمن المفيد مراجعة مكتبة Pandas (1): قراءة واستدعاء البيانات من ملفات CSV و Excel برمجياً لفهم أفضل لمصادر الإدخال.
هندسة الميزات على البيانات الضخمة باستخدام PySpark
عندما نتعامل مع عشرات أو مئات الملايين من السجلات، يصبح التنفيذ المحلي محدوداً. هنا يظهر دور Apache Spark في تنفيذ التحويلات بشكل موزع وقابل للتوسع.
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, month, dayofweek, when, sum, avg, countDistinct
spark = SparkSession.builder.appName("feature_engineering").getOrCreate()
df = spark.read.option("header", True).csv("hdfs:///data/sales.csv", inferSchema=True)
df = (
df.withColumn("month", month(col("order_date")))
.withColumn("day_of_week", dayofweek(col("order_date")))
.withColumn("is_weekend", when(col("day_of_week").isin(1, 7), 1).otherwise(0))
.withColumn("net_revenue", col("quantity") * col("sale_price") - col("discount_amount"))
)
customer_features = (
df.groupBy("customer_id")
.agg(
countDistinct("order_id").alias("total_orders"),
avg("net_revenue").alias("avg_order_value"),
sum("quantity").alias("total_quantity")
)
)
final_df = df.join(customer_features, on="customer_id", how="left")
final_df.show(5)
في بيئات
Spark، حاول تقليل عملياتshuffleالمكلفة، واستخدم التقسيم المناسبpartitioning، وخزن الجداول الوسيطة بصيغ عمودية مثلParquetلتحسين الأداء واستهلاك الذاكرة.
استخدام SQL لبناء الميزات داخل مستودع البيانات
في كثير من المؤسسات، تُبنى الميزات مباشرة داخل مستودعات البيانات قبل وصولها إلى طبقة النمذجة. هذا النهج ممتاز لتوحيد المنطق وتحسين الحوكمة وإعادة الاستخدام عبر الفرق.
SELECT
customer_id,
COUNT(DISTINCT order_id) AS total_orders,
AVG(quantity * sale_price - discount_amount) AS avg_order_value,
SUM(quantity) AS total_quantity,
MAX(order_date) AS last_order_date
FROM sales
GROUP BY customer_id;
هذا النمط يتكامل بامتياز مع خطوط ETL وELT، خاصة عندما تكون البيانات موزعة بين قواعد SQL وNoSQL.
أخطاء شائعة يجب تجنبها
- تسريب البيانات
Data Leakageعبر استخدام معلومات مستقبلية أثناء التدريب. - إنشاء عدد هائل من الميزات دون تقييم أثرها الحقيقي على النموذج.
- إهمال التوزيع الإحصائي للميزة بعد التحويل.
- عدم توثيق منطق الاشتقاق داخل
Pipelineواضح وقابل للإعادة.
كيف تقيس نجاح الميزة الجديدة؟
نجاح أي ميزة لا يُقاس بجمال الفكرة، بل بتأثيرها الفعلي. لذلك يجب تقييمها من خلال:
- تحسن دقة النموذج أو انخفاض الخطأ.
- زيادة قابلية التفسير للأعمال.
- استقرار الأداء بين التدريب والإنتاج.
- انخفاض تكلفة الحساب والزمن مقارنة بالعائد التحليلي.
كما يمكن استخدام أدوات التصور لفهم أثر الميزات بصرياً، خصوصاً عبر مكتبة Matplotlib: أساسيات تصوير البيانات ورسم المخططات البيانية أو مكتبة Seaborn: إنشاء رسوم بيانية إحصائية متقدمة ومريحة للعين بسطر كود واحد.
الخلاصة
هندسة الميزات ليست خطوة تجميلية، بل هي قلب التحويل الحقيقي من بيانات خام إلى معرفة قابلة للتنبؤ والقرار. كلما فهمت منطق الأعمال، وبنية الجداول، وسلوك المتغيرات، أصبحت قادراً على توليد ميزات أكثر ذكاءً وأقل ضجيجاً. في المشاريع الحديثة، تتقاطع هذه المهارة مع التحليل، والهندسة، والحوكمة، وتحسين الأداء على حد سواء.
لذلك فإن أفضل نهج عملي هو بناء ميزات قليلة لكن مدروسة، قابلة للتوسع، ومُعرّفة بوضوح داخل مسار معالجة موثوق. عندها فقط تتحول البيانات الحالية إلى أصول جديدة تمنح نماذجك وقراراتك قوة تنافسية حقيقية.