تعد هندسة السمات (feature engineering) أحد أهم أجزاء بناء نموذج جيد للتعلم الآلي. إذا كانت لدينا سمات مفيدة ، فسيعمل النموذج بشكل أفضل. هناك العديد من المواقف التي يمكنك فيها تجنب النماذج الكبيرة والمعقدة واستخدام نماذج بسيطة ذات سمات مهندسه بعناية. يجب أن نضع في اعتبارنا أن هندسة السمات شيء يتم إجراؤه بأفضل طريقة ممكنة فقط عندما يكون لديك بعض المعرفة حول مجال المشكلة وتعتمد كثيرًا على البيانات المعنية.
ومع ذلك ، هناك بعض الأساليب العامة التي يمكنك تجربتها لإنشاء سمات من جميع أنواع المتغيرات العددية والفئوية تقريبًا. لا تتعلق هندسة السمات فقط بإنشاء سمات جديدة من البيانات ولكنها تتضمن أيضًا أنواعًا مختلفة من التسوية والتحويلات.
في المقال السابق ، رأينا طريقة لدمج المتغيرات الفئوية المختلفة ، وكيف يمكننا تحويل المتغيرات الفئوية إلى الأعداد ،و ترميز الهدف ، واستخدام التضمينات. هذه تقريبًا جميعها أنواع مختلفة لهندسة السمات من المتغيرات الفئوية. وبالتالي ، في هذا المقال، سيقتصر تركيزنا على المتغيرات العددية أومجموعة مدمجة من المتغيرات العددية والفئوية
السمات الزمنية
لنبدأ بأساليب هندسة السمات الأكثر بساطة والأكثر استخدامًا. لنفترض أنك تتعامل مع بيانات التاريخ والوقت. لذلك ، لدينا إطار بيانات الباندا مع عمود نوع التاريخ والوقت. باستخدام هذا العمود ، يمكننا إنشاء سمات مثل:
– العام
– أسبوع من السنة
– الشهر
– يوم من الأسبوع
– عطلة نهاية الاسبوع
– ساعة
– و أكثر من ذلك بكثير.
ويمكن القيام بذلك بسهولة باستخدام الباندا.
df.loc[:, 'year'] = df['datetime_column'].dt.year df.loc[:, 'weekofyear'] = df['datetime_column'].dt.weekofyear df.loc[:, 'month'] = df['datetime_column'].dt.month df.loc[:, 'dayofweek'] = df['datetime_column'].dt.dayofweek df.loc[:, 'weekend'] = (df.datetime_column.dt.weekday >=5).astype(int) df.loc[:, 'hour'] = df['datetime_column'].dt.hour
لذلك ، نقوم بإنشاء مجموعة من الأعمدة الجديدة باستخدام عمود التاريخ والوقت. دعونا نرى بعض نماذج السمات التي يمكن إنشاؤها.
import pandas as pd # إنشاء سلسلة من التاريخ والوقت يتكرار من 10 ساعات s = pd.date_range('2020-01-06' , '2020-01-10', freq= '10H').to_series() # إنشاء سمات من إطار البيانات هذا features = { "dayofweek": s.dt.dayofweek.values, "dayofyear": s.dt.dayofyear.values, "hour": s.dt.hour.values, "is_leap_year": s.dt.is_leap_year.values, "quarter": s.dt.quarter.values, "weekofyear": s.dt.weekofyear.values }
سيؤدي هذا إلى إنشاء قاموس سمات من السلسلة المعطاة. يمكنك تطبيق هذا على أي عمود تاريخ / وقت في إطار بيانات الباندا. هذه بعض السمات العديدة للتاريخ والوقت التي تقدمها الباندا. تعد سمات التاريخ والوقت مهمة عندما تتعامل مع بيانات السلاسل الزمنية (time-series data) ، على سبيل المثال ، توقع مبيعات متجر ولكنك ترغب في استخدام نموذج مثل xgboost على سمات مجمعة (aggregated features) .
السمات المجمعة (aggregated features)
لنفترض أن لدينا إطار بيانات يشبه ما يلي:
نرى أن لدينا عمود تاريخ ، ويمكننا بسهولة استخراج سمات مثل السنة والشهر والربع وما إلى ذلك منه. ثم لدينا عمود customer_id الذي يحتوي على إدخالات متعددة ، لذلك يتم رؤية العميل عدة مرات (لا تظهر على الصورة). ولكل تاريخ ومعرّف عميل ثلاث سمات فئوية و واحدة رقمية مرفقة به. هناك مجموعة من السمات التي يمكننا إنشاؤها منها:
– ما هو الشهر الذي يكون فيه العميل أكثر نشاطًا
– ما هو تعداد الفئة 1 ، الفئة 2 ، الفئة 3 للعميل
– ما هو تعداد الفئة 1 ، الفئة 2 ، الفئة 3 لعميل خلال أسبوع معين من العام
– ما هو متوسط عدد 1 لعميل معين
– وهلم جرا.
باستخدام المجاميع في الباندا ، من السهل جدًا إنشاء سمات مثل هذه. دعونا نرى كيف.
def generated_features(df): # إنشاء عدة سمات بإستخدام عامود التاريخ df.loc[:, 'year'] = df['date'].dt.year df.loc[:, 'weekofyear'] = df['date'].dt.weekofyear df.loc[:, 'month'] = df['date'].dt.month df.loc[:, 'dayofweek'] = df['date'].dt.dayofweek df.loc[:, 'weekend'] = (df['date'].dt.weekday >=5).astype(int) # إنشاء قاموس التجميع aggs = {} # للتجميع حسب الشهر ، نحسب # عدد قيم الشهر الفريدة والمتوسط أيضًا aggs['month'] = ['nunique', 'mean'] aggs['weekofyear'] = ['nunique' , 'mean'] # نحن نجمع العدد 1 ونحسب المجموع ، الحد الأقصى ، الحد الأدنى # و متوسط قيم هذا العمود aggs['num1'] = ['sum' , 'max' , 'min', 'mean'] # نحسب العدد الإجمالي customer_id بالنسية إلى aggs['customer_id'] = ['size'] # نحسب القيم الفريد customer_id aggs['customer_id'] = ['nunique'] # ونحسب المجاميع customer_id نقوم بالتجميع حسب agg_df = df.groupby('customer_id').agg(aggs) agg_df = agg_df.reset_index() return agg_df
يرجى ملاحظة أنه في الوظيفة أعلاه ، تخطينا المتغيرات الفئوية ، ولكن يمكنك استخدامها بنفس طريقة استخدام المجاميع الأخرى.
الآن ، يمكننا ضم إطار البيانات هذا في الصورة أعلاه مع إطار البيانات الأصلي مع عمود معرف العميل لبدء تدريب نموذج. هنا لا نحاول التكهن بأي شيء. نحن نقوم فقط بإنشاء سمات عامة. ومع ذلك ، كان من الأسهل إنشاء سمات إذا كنا نحاول التنبؤ بشيء هنا.
في بعض الأحيان ، على سبيل المثال ، عند التعامل مع مشاكل السلاسل الزمنية ، قد يكون لديك سمات ليست قيمًا فردية ولكنها قائمة من القيم. على سبيل المثال ، المعاملات التي أجراها عميل في فترة زمنية معينة. في هذه الحالات ، نقوم بإنشاء أنواع مختلفة من السمات مثل: مع السمات العددية ، عندما تقوم بالتجميع في عمود فئوي ، ستحصل على سمات مثل قائمة القيم الموزعة على الوقت. في هذه الحالات ، يمكنك إنشاء مجموعة من السمات الإحصائية مثل:
– المتوسط
– القيمة القصوى
– القيمة الأدنى
– القيم الفريده
– انحراف
– التفرطح (Kurtosis)
– كستات (Kstat)
– النسبة المئوية
– كمية
– الذروة إلى الذروة
– و أكثر من ذلك بكثير
يمكن إنشاء هذه باستخدام وظائف numpy بسيطة ، كما هو موضح في مقتطف python التالي.
import numpy as np feature_dict = {} #حساب المتوسط feature_dict['mean'] = np.mean(x) #حساب القيمة القصوى feature_dict['max'] = np.max(x) #حساب القيمة الدنيا feature_dict['min'] = np.min(x) # حساب الانحراف المعياري feature_dict['std'] = np.std(x) # حساب التباين feature_dict['var'] = np.var(x) # حساب الذروة إلى الذروة feature_dict['ptp'] = np.ptp(x) # سمات النسبة المئوية feature_dict['percentile_10'] = np.percentile(x, 10) feature_dict['percentile_60'] = np.percentile(x, 60) feature_dict['percentile_90'] = np.percentile(x, 90) # سمات كمية feature_dict['quantile_5'] = np.percentile(x, 5) feature_dict['quantile_95'] = np.percentile(x, 95) feature_dict['quantile_99'] = np.percentile(x, 99)
يمكن تحويل بيانات السلاسل الزمنية (قائمة القيم) إلى الكثير من السمات .
مكتبة بيثون تسمى tsfresh مفيدة في هذه الحالة.
from tsfresh.feature_extraction import feature_calculators as fc # tsfresh سمات مبنية على feature_dict['abs_energy'] = fc.abs_energy(x) feature_dict['count_above_mean'] = fc.count_above_mean(x) feature_dict['count_below_mean'] = fc.count_below_mean(x) feature_dict['mean_abs_change'] = fc.mean_abs_change(x) feature_dict['mean_change'] = fc.mean_change(x)
هذا ليس كل شيء. تقدم tsfresh المئات من السمات وعشرات الأشكال المختلفة من السمات المختلفة التي يمكنك استخدامها للسمات القائمة على السلاسل الزمنية (قائمة القيم). في الأمثلة أعلاه ، x هي قائمة من القيم. لكن هذا ليس كل شيء.
السمات متعددة الحدود
هناك العديد من السمات الأخرى التي يمكنك إنشاؤها للبيانات العددية مع البيانات الفئوية أو بدونها. طريقة بسيطة لإنشاء العديد من السمات هي بإنشاء مجموعة من السمات متعددة الحدود (polynomial features) .
على سبيل المثال ، سمة كثيرة الحدود من الدرجة الثانية من سمتين “أ” و “ب” تشمل: “أ” و “ب” و “أب” و “أ تربيع” و “ب تربيع”.
import numpy as np # إنشاء إطار بيانات عشوائي باستخدام # عامودين و 100 صف df = pd.DataFrame( np.random.rand(100,2), columns=[f"f_{i}" for i in range (1, 3)] ) df
والذي يعطي إطار بيانات هذا .
ويمكننا إنشاء سمات متعددة الحدود من الدرجة الثانية (two-degree polynomial features) باستخدام PolynomialFeatures من scikit-Learn.
from sklearn import preprocessing pf = preprocessing.PolynomialFeatures( degree = 2, interaction_only=False, include_bias=False ) pf.fit(df) # إنشاء سمات متعددة poly_feats = pf.transform(df) # إنشاء إطار بيانات مع كل السمات num_feats = poly_feats.shape[1] df_tranformed = pd.DataFrame( poly_feats, columns=[ f"f{i}" for i in range(1, num_feats +1 )]) df_tranformed
وهذا من شأنه أن يعطي إطار البيانات هذا
لذا ، فقد أنشأنا الآن بعض السمات متعددة الحدود. إذا قمت بإنشاء سمات متعددة الحدود من الدرجة الثالثة ، ستحصل في النهاية على تسع سمات في المجموع. كلما زاد عدد السمات ، زاد عدد السمات متعددة الحدود ويجب أن تتذكر أيضًا أنه إذا كان لديك الكثير من العينات في مجموعة البيانات ، فسيستغرق إنشاء هذه الأنواع من السمات بعض الوقت.
إنشاء الحاويات
سمة أخرى مثيرة للاهتمام تحول الأرقام إلى فئات. تعرف باسم إنشاء الحاويات binning. لنلقِ نظرة على الصورة أدناه، الذي يُظهر عينة مدرج تكراري لسمة غددية عشوائية. نستخدم عشرة حاويات لهذا الشكل ، ونلاحظ أنه يمكننا تقسيم البيانات إلى عشرة أجزاء.
يتم تحقيق ذلك باستخدام cut في الباندا.
# إنشاء حاويات الأعمدة العددية # عشرة حاويات df["f_bin_10"] = pd.cut(df["f_1"], bins= 10, labels=False) #مائة حاوية df["f_bin_100"] = pd.cut(df["f_1"], bins = 100, labels=False) df
والتي تولد سمتين جديدتين في إطار البيانات .
عند إنشاء الحاويات ، يمكنك استخدام كل من الحاوية والسمة الأصلية. يتيح لك Binning أيضًا التعامل مع السمات العددية على أنها فئوية.
تحويل اللوغاريتم
هناك نوع آخر مثير للاهتمام من السمات التي يمكنك إنشاؤها من السمات الرقمية وهو تحويل اللوغاريتم (log transformation.) . ألق نظرة على السمة f_3 في الصورة أدناه.
f_3 هي سمة خاصة ذات تباين كبير جدًا. مقارنة بالسمات الأخرى ذات التباين المنخفض (لنفترض ذلك). وبالتالي ، نود تقليل تباين هذا العمود ، ويمكن القيام بذلك عن طريق إجراء تحويل اللوغارينم . تتراوح القيم في العمود f_3 من 0 إلى 10000 ويظهر الرسم التكراري أدناه .
ويمكننا تطبيق log(1 + x) على هذا العمود لتقليل تباينه موضح أدنا ما يحدث للرسم البياني عند تطبيق تحويل اللوغاريتم.
دعنا نلقي نظرة على التباين بدون تحويل السجل ومعه.
In [X]: df.f_3.var() Out[X]: 8077265.875858586 In [X]: df.f_3.apply(lambda x: np.log(1 + x)).var() Out[X]: 0.6058771732119975
التحويل الأسي
في بعض الأحيان ، بدلاً من اللوغاريتم ، يمكنك أيضًا أن تأخذ الأس (exponential) . هناك حالة مثيرة للاهتمام للغاية عندما تستخدم مقياس تقييم قائم على اللوغاريتم، على سبيل المثال ، RMSLE. في هذه الحالة ، يمكنك التدرب على الأهداف المحولة باللوغاريتم والتحويل مرة أخرى إلى الأصل باستخدام الأسي في التنبؤ. سيساعد ذلك في تحسين النموذج للمقياس.
في معظم الأحيان ، يتم إنشاء هذه الأنواع من السمات العددية بناءً على الحدس. لا توجد صيغة. إذا كنت تعمل في صناعة ما ، فستقوم بإنشاء سمات خاصة بالصناعة.
التعامل مع البيانات المفقودة
عند التعامل مع كل من المتغيرات الفئوية والرقمية ، قد تواجه قيمًا مفقودة. لقد رأينا بعض الطرق للتعامل مع القيم المفقودة في السمات الفئوية في المقال السابق ، ولكن هناك العديد من الطرق للتعامل مع القيم المفقودة / NaN. يعتبر هذا أيضًا هندسة سمات.
بالنسبة إلى السمات الفئوية ، دعنا نجعلها بسيطة للغاية. إذا واجهت قيمًا مفقودة في السمات الفئوية ، فستكون المعاملة فئة جديدة! بهذه البساطة ، فهذا يعمل دائمًا (تقريبًا)
! تتمثل إحدى طرق ملء القيم المفقودة في البيانات العددية في اختيار قيمة لا تظهر في السمة المحددة وتعبئتها باستخدام ذلك. على سبيل المثال ، لنفترض أن 0 لم يظهر في السمة. لذلك ، نملأ جميع القيم المفقودة باستخدام 0. هذه إحدى الطرق ولكنها قد لا تكون الأكثر فاعلية.
إحدى الطرق التي تعمل بشكل أفضل من ملء 0 للبيانات العددية هي الملء بالمتوسط بدلاً من ذلك. يمكنك أيضًا محاولة التعبئة بمتوسط جميع القيم الخاصة بهذه السمة ، أو يمكنك استخدام القيمة الأكثر شيوعًا لملء القيم المفقودة. هناك العديد من الطرق للقيام بذلك.
الجار الأقرب كي (k-nearest neighbor)
تتمثل إحدى الطرق الفاخرة لملء القيم المفقودة في استخدام طريقة الجار الأقرب كي (k-nearest neighbor) الأقرب. يمكنك تحديد عينة بقيم مفقودة والعثور على أقرب الجيران باستخدام نوع من قياس المسافة ، على سبيل المثال ، المسافة الإقليدية. يمكنك بعد ذلك أخذ متوسط أقرب جيران وملء القيمة المفقودة. يمكنك استخدام تطبيق KNN لملء القيم المفقودة مثل هذا.
دعونا نرى كيف يتم التعامل مع مصفوفة ذات قيم مفقودة ، كما هو موضح في الصورة أعلاه بواسطة KNNImputer.
import numpy as np from sklearn import impute # إنشاء مصفوفة عشوائية مكونة من 10 عينات # و 6 سمات وقيم تتراوح من 1 إلى 15 X = np.random.randint(1, 15, (10,6)) # تحويل المصفوفة إلى تعويم X = X.astype(float) # (مفقود) NaN قم بتعيين 10 عناصر بشكل عشوائي لـ X.ravel()[np.random.choice(X.size, 10, replace=False)] = np.nan # NAN استخدم أقرب ثلاث جيران لملء قيم knn_impute = impute.KNNImputer(n_neighbors=2) knn_impute.fit_transform(X)
الذي يملأ المصفوفة أعلاه ، كالأتي
هناك طريقة أخرى لحساب القيم المفقودة في عمود وهي تدريب نموذج انحدار يحاول التنبؤ بالقيم المفقودة في عمود استنادًا إلى أعمدة أخرى. لذلك ، تبدأ بعمود واحد يحتوي على قيمة مفقودة وتعامل هذا العمود على أنه العمود المستهدف لنموذج الانحدار بدون القيم المفقودة. باستخدام جميع الأعمدة الأخرى ، تقوم الآن بتدريب نموذج على عينات لا توجد لها قيمة مفقودة في العمود المعني ثم تحاول التنبؤ بالهدف (نفس العمود) للعينات التي تمت إزالتها سابقًا. بهذه الطريقة ، يكون لديك احتساب أكثر قوة يعتمد على النموذج.
تذكر دائمًا أن احتساب القيم للنماذج القائمة على الأشجار غير ضروري حيث يمكنهم التعامل معها بأنفسهم.
ما أظهرته حتى الآن هو بعض طرق إنشاء السمات بشكل عام. الآن ، لنفترض أنك تعمل على مشكلة توقع مبيعات المتجر لعناصر مختلفة (أسبوعيًا أو شهريًا). لديك عناصر ولديك معرفات متجر. لذلك ، يمكنك إنشاء سمات مثل العناصر لكل متجر.
الآن ، هذه إحدى السمات التي لم تتم مناقشتها أعلاه. لا يمكن تعميم هذه الأنواع من السمات وتأتي فقط من المجال والبيانات والمعرفة التجارية. انظر إلى البيانات وشاهد ما يناسبها وأنشئ السمات وفقًا لذلك. وتذكر دائمًا تكبير أو تسوية سماتك إذا كنت تستخدم نموذجًا خطيًا مثل الانحدار اللوجستي أو نموذج مثل SVM. ستعمل النماذج المستندة إلى الشجرة دائمًا بشكل جيد دون أي تطبيع للسمات.
إضافة تعليق