.. _develop: =========================== تطوير مقدرات scikit-learn =========================== سواء كنت تقترح مقدرًا لإدراجه في scikit-learn، أو تطوير حزمة منفصلة متوافقة مع scikit-learn، أو تنفيذ مكونات مخصصة لمشاريعك الخاصة، يوضح هذا الفصل كيفية تطوير كائنات تتفاعل بشكل آمن مع خطوط أنابيب scikit-learn وأدوات اختيار النموذج. .. currentmodule:: sklearn .. _api_overview: واجهات برمجة تطبيقات كائنات scikit-learn ============================================ للحصول على واجهة برمجة تطبيقات موحدة، نحاول أن يكون لدينا واجهة برمجة تطبيقات أساسية مشتركة لجميع الكائنات. بالإضافة إلى ذلك، لتجنب انتشار كود الإطار، نحن نحاول اعتماد اتفاقيات بسيطة والحد من عدد الأساليب التي يجب على الكائن تنفيذها إلى الحد الأدنى. يتم وصف عناصر واجهة برمجة تطبيقات scikit-learn بشكل أكثر تحديدًا في :ref:`glossary`. كائنات مختلفة ----------------- الكائنات الرئيسية في scikit-learn هي (يمكن لفئة واحدة تنفيذ واجهات متعددة): :Estimator: الكائن الأساسي، ينفذ أسلوب ``fit`` للتعلم من البيانات، إما:: estimator = estimator.fit(data, targets) أو:: estimator = estimator.fit(data) :Predictor: للتعلم الخاضع للإشراف، أو بعض المشكلات غير الخاضعة للإشراف، ينفذ:: prediction = predictor.predict(data) عادةً ما تقدم خوارزميات التصنيف أيضًا طريقة لتحديد اليقين للتنبؤ، إما باستخدام ``decision_function`` أو ``predict_proba``:: probability = predictor.predict_proba(data) :Transformer: لتعديل البيانات بطريقة خاضعة للإشراف أو غير خاضعة للإشراف (على سبيل المثال عن طريق إضافة أو تغيير أو إزالة أعمدة، ولكن ليس عن طريق إضافة أو إزالة صفوف). ينفذ:: new_data = transformer.transform(data) عندما يمكن إجراء التوفيق والتحويل معًا بكفاءة أكبر من إجراءهما بشكل منفصل، ينفذ:: new_data = transformer.fit_transform(data) :Model: نموذج يمكنه إعطاء مقياس `جودة التوفيق `_ أو احتمالية بيانات غير مرئية، ينفذ (الأعلى أفضل):: score = model.score(data) المقدرات ---------- تحتوي واجهة برمجة التطبيقات على كائن واحد سائد: المقدر. المقدر هو كائن يلائم نموذجًا بناءً على بعض بيانات التدريب وقادر على استنتاج بعض الخصائص على بيانات جديدة. يمكن أن يكون، على سبيل المثال، مصنفًا أو مقدر انحدار. تنفذ جميع المقدرات أسلوب fit:: estimator.fit(X, y) تحتوي جميع المقدرات المضمنة أيضًا على أسلوب ``set_params``، والذي يعيِّن معلمات مستقلة عن البيانات (يتجاوز قيم المعلمات السابقة التي تم تمريرها إلى ``__init__``). يجب أن ترث جميع المقدرات في قاعدة كود scikit-learn الرئيسية من ``sklearn.base.BaseEstimator``. الاعداد ^^^^^^^^^ يتعلق هذا بإنشاء كائن. قد يقبل أسلوب ``__init__`` الخاص بالكائن ثوابت كوسيطات تحدد سلوك المقدر (مثل الثابت C في SVMs). ومع ذلك، لا ينبغي أن يأخذ بيانات التدريب الفعلية كوسيطة، حيث يتم ترك هذا لأسلوب ``fit()``:: clf2 = SVC(C=2.3) clf3 = SVC([[1, 2], [2, 3]], [-1, 1]) # خطأ! يجب أن تكون جميع الوسيطات المقبولة بواسطة ``__init__`` وسيطات ذات كلمات رئيسية بقيمة افتراضية. بمعنى آخر، يجب أن يكون المستخدم قادرًا على تكوين مقدر دون تمرير أي وسيطات إليه. يجب أن تتوافق جميع الوسيطات مع المعلمات الفائقة التي تصف النموذج أو مشكلة التحسين التي يحاول المقدر حلها. يتم دائمًا تذكر هذه الوسيطات الأولية (أو المعلمات) بواسطة المقدر. لاحظ أيضًا أنه لا ينبغي توثيقها ضمن قسم "السمات"، ولكن بدلاً من ذلك ضمن قسم "المعلمات" لهذا المقدر. بالإضافة إلى ذلك، **يجب أن تتوافق كل وسيطة ذات كلمة رئيسية يقبلها** ``__init__`` **مع سمة في النموذج**. يعتمد Scikit-learn على هذا لـ العثور على السمات ذات الصلة لتعيينها على مقدر عند إجراء اختيار النموذج. لتلخيص، يجب أن يبدو ``__init__`` كما يلي:: def __init__(self, param1=1, param2=2): self.param1 = param1 self.param2 = param2 يجب ألا يكون هناك منطق، ولا حتى التحقق من صحة الإدخال، ولا ينبغي تغيير المعلمات. يجب وضع المنطق المقابل حيث يتم استخدام المعلمات، عادةً في ``fit``. ما يلي خطأ:: def __init__(self, param1=1, param2=2, param3=3): # خطأ: لا ينبغي تعديل المعلمات if param1 > 1: param2 += 1 self.param1 = param1 # خطأ: يجب أن تحتوي سمات الكائن على اسم # الوسيطة في المُنشئ تمامًا self.param3 = param2 سبب تأجيل التحقق من الصحة هو أنه يجب إجراء نفس التحقق من الصحة في ``set_params``، والذي يُستخدم في خوارزميات مثل ``GridSearchCV``. الملائمة ^^^^^^^ الشيء التالي الذي قد ترغب في القيام به هو تقدير بعض المعلمات في النموذج. يتم تنفيذ ذلك في أسلوب ``fit()``. يأخذ أسلوب ``fit()`` بيانات التدريب كوسيطات، والتي يمكن أن تكون مصفوفة واحدة في حالة التعلم غير الخاضع للإشراف، أو مصفوفتين في حالة التعلم الخاضع للإشراف. لاحظ أن النموذج ملائم باستخدام ``X`` و ``y``، لكن الكائن لا يحتفظ بأي مرجع إلى ``X`` و ``y``. ومع ذلك، هناك بعض الاستثناءات لهذا، كما هو الحال في حالة النوى المحسوبة مسبقًا حيث يجب تخزين هذه البيانات لاستخدامها بواسطة أسلوب التنبؤ. ============= ====================================================== المعلمات ============= ====================================================== X مصفوفة من الشكل (n_samples, n_features) y مصفوفة من الشكل (n_samples,) kwargs معلمات اختيارية تعتمد على البيانات ============= ====================================================== يجب أن يكون ``X.shape[0]`` هو نفسه ``y.shape[0]``. إذا لم يتم استيفاء هذا الشرط الأساسي، فيجب طرح استثناء من النوع ``ValueError``. قد يتم تجاهل ``y`` في حالة التعلم غير الخاضع للإشراف. ومع ذلك، لـ جعل من الممكن استخدام المقدر كجزء من خط أنابيب يمكنه خلط كل من المحولات الخاضعة للإشراف وغير الخاضعة للإشراف، حتى المقدرات غير الخاضعة للإشراف تحتاج إلى قبول وسيطة ذات كلمة رئيسية ``y=None`` في الموضع الثاني يتم تجاهلها بواسطة المقدر. للسبب نفسه، تحتاج أساليب ``fit_predict`` و ``fit_transform`` و ``score`` و ``partial_fit`` إلى قبول وسيطة ``y`` في المكان الثاني إذا تم تنفيذها. يجب أن يُعيد الأسلوب الكائن (``self``). هذا النمط مفيد لتكون قادرًا على تنفيذ بطانات سريعة في جلسة IPython مثل:: y_predicted = SVC(C=100).fit(X_train, y_train).predict(X_test) اعتمادًا على طبيعة الخوارزمية، يمكن لـ ``fit`` أحيانًا أيضًا قبول وسيطات إضافية ذات كلمات رئيسية. ومع ذلك، فإن أي معلمة يمكن تعيين قيمة لها قبل الوصول إلى البيانات يجب أن تكون وسيطة ذات كلمة رئيسية ``__init__``. **يجب أن تقتصر معلمات fit على المتغيرات المعتمدة على البيانات مباشرةً**. على سبيل المثال، مصفوفة غرام أو مصفوفة تقارب محسوبة مسبقًا من مصفوفة البيانات ``X`` هي معتمدة على البيانات. معيار إيقاف التسامح ``tol`` لا يعتمد على البيانات مباشرةً (على الرغم من أن القيمة المثلى وفقًا لبعض دوال التسجيل ربما تكون كذلك). عندما يتم استدعاء ``fit``، يجب تجاهل أي استدعاء سابق لـ ``fit``. بشكل عام، استدعاء ``estimator.fit(X1)`` ثم ``estimator.fit(X2)`` يجب أن يكون هو نفسه استدعاء ``estimator.fit(X2)`` فقط. ومع ذلك، قد لا يكون هذا صحيحًا من الناحية العملية عندما يعتمد ``fit`` على بعض العمليات العشوائية، انظر :term:`random_state`. استثناء آخر لهذه القاعدة هو عندما يتم تعيين المعلمة الفائقة ``warm_start`` إلى ``True`` للمقدرات التي تدعمها. ``warm_start=True`` تعني أنه تمت إعادة استخدام الحالة السابقة لـ معلمات المقدر القابلة للتدريب بدلاً من استخدام استراتيجية التهيئة الافتراضية. السمات المقدرة ^^^^^^^^^^^^^^^^ يجب أن تحتوي السمات التي تم تقديرها من البيانات دائمًا على اسم ينتهي بشرطة سفلية زائدة، على سبيل المثال، سيتم تخزين معاملات بعض مقدرات الانحدار في سمة ``coef_`` بعد استدعاء ``fit``. من المتوقع تجاوز السمات المقدرة عند استدعاء ``fit`` للمرة الثانية. السمات الاختيارية ^^^^^^^^^^^^^^^^^^^^ في الخوارزميات التكرارية، يجب تحديد عدد التكرارات بواسطة عدد صحيح يسمى ``n_iter``. السمات العامة ^^^^^^^^^^^^^^^ يجب على المقدرات التي تتوقع إدخالًا جدوليًا تعيين سمة `n_features_in_` في وقت `fit` للإشارة إلى عدد الميزات التي يتوقعها المقدر للاستدعاءات اللاحقة لـ `predict` أو `transform`. انظر `SLEP010 `_ للتفاصيل. .. _rolling_your_own_estimator: بناء المقدر الخاص بك ======================= إذا كنت ترغب في تنفيذ مقدر جديد متوافق مع scikit-learn، سواء كان ذلك لك فقط أو للمساهمة به في scikit-learn، فهناك العديد من العناصر الداخلية لـ scikit-learn التي يجب أن تكون على دراية بها بالإضافة إلى واجهة برمجة تطبيقات scikit-learn الموضحة أعلاه. يمكنك التحقق مما إذا كان المقدر الخاص بك يلتزم بواجهة ومعايير scikit-learn عن طريق تشغيل :func:`~sklearn.utils.estimator_checks.check_estimator` على نموذج. يمكن أيضًا استخدام مُزَيِّن pytest :func:`~sklearn.utils.estimator_checks.parametrize_with_checks` (انظر سلسلة الوثائق الخاصة به للحصول على التفاصيل والتفاعلات الممكنة مع `pytest`):: >>> from sklearn.utils.estimator_checks import check_estimator >>> from sklearn.svm import LinearSVC >>> check_estimator(LinearSVC()) # يمر الدافع الرئيسي لجعل الفئة متوافقة مع واجهة مقدر scikit-learn قد يكون أنك تريد استخدامها مع أدوات اختيار النموذج وتقييمه مثل :class:`model_selection.GridSearchCV` و :class:`pipeline.Pipeline`. قبل تفصيل الواجهة المطلوبة أدناه، نصف طريقتين لتحقيق الواجهة الصحيحة بسهولة أكبر. .. topic:: قالب المشروع: نحن نقدم `قالب مشروع `_ يساعد في إنشاء حزم Python التي تحتوي على مقدرات متوافقة مع scikit-learn. يوفر: * مستودع git أولي مع بنية دليل حزمة Python * قالب لمقدر scikit-learn * مجموعة اختبار أولية بما في ذلك استخدام ``check_estimator`` * هياكل دليل وبرامج نصية لتجميع الوثائق ومعارض الأمثلة * برامج نصية لإدارة التكامل المستمر (الاختبار على Linux و Windows) * تعليمات من البدء إلى النشر على `PyPi `_ .. topic:: ``BaseEstimator`` و mixins: نميل إلى استخدام "كتابة البطة"، لذا فإن بناء مقدر يتبع واجهة برمجة التطبيقات يكفي للتوافق، دون الحاجة إلى الوراثة من أو حتى استيراد أي فئات scikit-learn. ومع ذلك، إذا كان الاعتماد على scikit-learn مقبولًا في التعليمات البرمجية الخاصة بك، فيمكنك منع الكثير من كود boilerplate عن طريق اشتقاق فئة من ``BaseEstimator`` وفئات mixin اختياريًا في ``sklearn.base``. على سبيل المثال، يوجد أدناه مصنف مخصص، مع المزيد من الأمثلة المضمنة في قالب مشروع `scikit-learn-contrib `__. من المهم بشكل خاص ملاحظة أنه يجب أن تكون mixins "على اليسار" بينما يجب أن يكون ``BaseEstimator`` "على اليمين" في قائمة الوراثة لـ MRO المناسب. >>> import numpy as np >>> from sklearn.base import BaseEstimator, ClassifierMixin >>> from sklearn.utils.validation import check_X_y, check_array, check_is_fitted >>> from sklearn.utils.multiclass import unique_labels >>> from sklearn.metrics import euclidean_distances >>> class TemplateClassifier(ClassifierMixin, BaseEstimator): ... ... def __init__(self, demo_param='demo'): ... self.demo_param = demo_param ... ... def fit(self, X, y): ... ... # تحقق من أن X و y لهما الشكل الصحيح ... X, y = check_X_y(X, y) ... # تخزين الفئات التي تمت رؤيتها أثناء التوفيق ... self.classes_ = unique_labels(y) ... ... self.X_ = X ... self.y_ = y ... # إرجاع المصنف ... return self ... ... def predict(self, X): ... ... # تحقق مما إذا كان قد تم استدعاء fit ... check_is_fitted(self) ... ... # التحقق من صحة الإدخال ... X = check_array(X) ... ... closest = np.argmin(euclidean_distances(X, self.X_), axis=1) ... return self.y_[closest] get_params و set_params ------------------------- تحتوي جميع مقدرات scikit-learn على دوال ``get_params`` و ``set_params``. لا تأخذ دالة ``get_params`` أي وسيطات وتُعيد قاموسًا لـ معلمات ``__init__`` للمقدر، جنبًا إلى جنب مع قيمها. يجب أن تأخذ وسيطة واحدة ذات كلمة رئيسية، ``deep``، والتي تتلقى قيمة منطقية تحدد ما إذا كان يجب على الأسلوب إرجاع معلمات المقدرات الفرعية (بالنسبة لمعظم المقدرات، يمكن تجاهل ذلك). القيمة الافتراضية لـ ``deep`` يجب أن تكون `True`. على سبيل المثال، بالنظر إلى المقدر التالي:: >>> from sklearn.base import BaseEstimator >>> from sklearn.linear_model import LogisticRegression >>> class MyEstimator(BaseEstimator): ... def __init__(self, subestimator=None, my_extra_param="random"): ... self.subestimator = subestimator ... self.my_extra_param = my_extra_param ستتحكم المعلمة `deep` فيما إذا كان ينبغي الإبلاغ عن معلمات `subestimator` أم لا. وبالتالي، عندما `deep=True`، سيكون الناتج:: >>> my_estimator = MyEstimator(subestimator=LogisticRegression()) >>> for param, value in my_estimator.get_params(deep=True).items(): ... print(f"{param} -> {value}") my_extra_param -> random subestimator__C -> 1.0 subestimator__class_weight -> None subestimator__dual -> False subestimator__fit_intercept -> True subestimator__intercept_scaling -> 1 subestimator__l1_ratio -> None subestimator__max_iter -> 100 subestimator__multi_class -> deprecated subestimator__n_jobs -> None subestimator__penalty -> l2 subestimator__random_state -> None subestimator__solver -> lbfgs subestimator__tol -> 0.0001 subestimator__verbose -> 0 subestimator__warm_start -> False subestimator -> LogisticRegression() غالبًا ما يكون لـ `subestimator` اسم (مثل الخطوات المسماة في كائن :class:`~sklearn.pipeline.Pipeline`)، وفي هذه الحالة يجب أن يصبح المفتاح `__C` و `__class_weight` وما إلى ذلك. بينما عندما `deep=False`، سيكون الناتج:: >>> for param, value in my_estimator.get_params(deep=False).items(): ... print(f"{param} -> {value}") my_extra_param -> random subestimator -> LogisticRegression() من ناحية أخرى، يأخذ ``set_params`` معلمات ``__init__`` كوسيطات ذات كلمات رئيسية، ويفك حزمها في قاموس بالشكل ``'parameter': value`` ويعيِّن معلمات المقدر باستخدام هذا القاموس. يجب أن تكون القيمة المعادة هي المقدر نفسه. على الرغم من أن آلية ``get_params`` ليست ضرورية (انظر :ref:`cloning` أدناه)، فإن دالة ``set_params`` ضرورية لأنها تُستخدم لتعيين المعلمات أثناء عمليات البحث الشبكية. أسهل طريقة لتنفيذ هذه الدوال، والحصول على أسلوب ``__repr__`` معقول، هي الوراثة من ``sklearn.base.BaseEstimator``. إذا كنت لا ترغب في جعل التعليمات البرمجية الخاصة بك تعتمد على scikit-learn، فإن أسهل طريقة لـ تنفيذ الواجهة هي:: def get_params(self, deep=True): # لنفترض أن هذا المقدر يحتوي على المعلمتين "alpha" و "recursive" return {"alpha": self.alpha, "recursive": self.recursive} def set_params(self, **parameters): for parameter, value in parameters.items(): setattr(self, parameter, value) return self المعلمات و init ------------------- بما أن :class:`model_selection.GridSearchCV` يستخدم ``set_params`` لتطبيق إعداد المعلمات على المقدرات، فمن الضروري أن يكون لاستدعاء ``set_params`` نفس التأثير مثل تعيين المعلمات باستخدام أسلوب ``__init__``. أسهل طريقة موصى بها لتحقيق ذلك هي **عدم إجراء أي تحقق من صحة المعلمات في** ``__init__``. يجب القيام بكل المنطق وراء معلمات المقدر، مثل ترجمة وسيطات السلسلة إلى دوال، في ``fit``. من المتوقع أيضًا **عدم تعيين** المعلمات ذات الشرطات السفلية الزائدة ``_`` **داخل** أسلوب ``__init__``. جميع السمات العامة التي تم تعيينها بواسطة fit ولديها شرطة سفلية زائدة ``_``. نتيجة لذلك، يتم استخدام وجود معلمات ذات شرطة سفلية زائدة ``_`` للتحقق مما إذا كان المقدر قد تم توفيقه. .. _cloning: الاستنساخ ---------- لاستخدامه مع وحدة :mod:`~sklearn.model_selection`، يجب أن يدعم المقدر دالة ``base.clone`` لتكرار مقدر. يمكن القيام بذلك عن طريق توفير أسلوب ``get_params``. إذا كان ``get_params`` موجودًا، فسيكون ``clone(estimator)`` نموذجًا لـ ``type(estimator)`` الذي تم استدعاء ``set_params`` عليه مع مستنسخات نتيجة ``estimator.get_params()``. سيتم نسخ الكائنات التي لا توفر هذا الأسلوب بعمق (باستخدام دالة Python القياسية ``copy.deepcopy``) إذا تم تمرير ``safe=False`` إلى ``clone``. يمكن للمقدرات تخصيص سلوك :func:`base.clone` عن طريق تعريف أسلوب `__sklearn_clone__`. يجب أن يُعيد `__sklearn_clone__` نموذجًا لـ المقدر. `__sklearn_clone__` مفيد عندما يحتاج المقدر إلى التمسك ببعض الحالة عند استدعاء :func:`base.clone` على المقدر. على سبيل المثال، يمكن تعريف مقدر تعريف ثابت للمحولات على النحو التالي:: class FrozenTransformer(BaseEstimator): def __init__(self, fitted_transformer): self.fitted_transformer = fitted_transformer def __getattr__(self, name): # سمات `fitted_transformer` الآن قابلة للوصول return getattr(self.fitted_transformer, name) def __sklearn_clone__(self): return self def fit(self, X, y): # لا يغير التوفيق حالة المقدر return self def fit_transform(self, X, y=None): # fit_transform يحول البيانات فقط return self.fitted_transformer.transform(X, y) توافق خط الأنابيب ---------------------- لكي يكون المقدر قابلاً للاستخدام مع ``pipeline.Pipeline`` في أي خطوة باستثناء الخطوة الأخيرة، فإنه يحتاج إلى توفير دالة ``fit`` أو ``fit_transform``. لكي تتمكن من تقييم خط الأنابيب على أي بيانات باستثناء مجموعة التدريب، فإنه يحتاج أيضًا إلى توفير دالة ``transform``. لا توجد متطلبات خاصة للخطوة الأخيرة في خط الأنابيب، باستثناء أن لديها دالة ``fit``. يجب أن تأخذ جميع دوال ``fit`` و ``fit_transform`` الوسيطات ``X, y``، حتى لو لم يتم استخدام y. وبالمثل، لكي يكون ``score`` قابلًا للاستخدام، تحتاج الخطوة الأخيرة من خط الأنابيب إلى دالة ``score`` تقبل ``y`` اختياريًا. أنواع المقدرات --------------- تعتمد بعض الوظائف الشائعة على نوع المقدر الذي تم تمريره. على سبيل المثال، يكون التحقق المتبادل في :class:`model_selection.GridSearchCV` و :func:`model_selection.cross_val_score` افتراضيًا طبقيًا عند استخدامه على مصنف، ولكن ليس بخلاف ذلك. وبالمثل، تحتاج أدوات التسجيل لمتوسط ​​الدقة التي تأخذ تنبؤًا مستمرًا إلى استدعاء ``decision_function`` للمصنفات، ولكن ``predict`` لمقدرات الانحدار. يتم تنفيذ هذا التمييز بين المصنفات ومقدرات الانحدار باستخدام سمة ``_estimator_type``، التي تأخذ قيمة سلسلة. يجب أن تكون ``"classifier"`` للمصنفات و ``"regressor"`` لمقدرات الانحدار و ``"clusterer"`` لأساليب التجميع، لتعمل كما هو متوقع. ستعيِّن الوراثة من ``ClassifierMixin`` أو ``RegressorMixin`` أو ``ClusterMixin`` السمة تلقائيًا. عندما يحتاج مقدر التعريف التلوي إلى التمييز بين أنواع المقدرات، بدلاً من التحقق من ``_estimator_type`` مباشرةً، يجب استخدام مساعدين مثل :func:`base.is_classifier`. نماذج محددة ------------- يجب أن تقبل المصنفات وسيطات ``y`` (الهدف) إلى ``fit`` وهي متواليات (قوائم، مصفوفات) من السلاسل أو الأعداد الصحيحة. لا ينبغي لهم افتراض أن تسميات الفئات هي نطاق متجاور من الأعداد الصحيحة؛ بدلاً من ذلك، يجب عليهم تخزين قائمة بالفئات في سمة أو خاصية ``classes_``. يجب أن يتطابق ترتيب تسميات الفئات في هذه السمة مع الترتيب الذي تُعيد به ``predict_proba`` و ``predict_log_proba`` و ``decision_function`` قيمها. أسهل طريقة لتحقيق ذلك هي وضع:: self.classes_, y = np.unique(y, return_inverse=True) في ``fit``. يُعيد هذا ``y`` جديدًا يحتوي على فهارس الفئات، بدلاً من التسميات، في النطاق [0، ``n_classes``). يجب أن يُعيد أسلوب ``predict`` الخاص بالمصنف مصفوفات تحتوي على تسميات فئات من ``classes_``. في مصنف ينفذ ``decision_function``، يمكن تحقيق ذلك باستخدام:: def predict(self, X): D = self.decision_function(X) return self.classes_[np.argmax(D, axis=1)] في النماذج الخطية، يتم تخزين المعاملات في مصفوفة تسمى ``coef_``، و يتم تخزين المصطلح المستقل في ``intercept_``. يحتوي ``sklearn.linear_model._base`` على عدد قليل من الفئات الأساسية و mixins التي تنفذ أنماط النموذج الخطي الشائعة. تحتوي الوحدة :mod:`~sklearn.utils.multiclass` على دوال مفيدة للعمل مع مشكلات متعددة الفئات ومتعددة التسميات. .. _estimator_tags: علامات المقدر -------------- .. warning:: علامات المقدر تجريبية وتخضع واجهة برمجة التطبيقات للتغيير. قدّم Scikit-learn علامات المقدر في الإصدار 0.21. هذه تعليقات توضيحية للمقدرات تسمح بفحص إمكانياتها برمجيًا، مثل دعم المصفوفة المتفرقة وأنواع المخرجات المدعومة والأساليب المدعومة. علامات المقدر هي قاموس يُعيده أسلوب ``_get_tags()``. يتم استخدام هذه العلامات في الفحوصات الشائعة التي تُجريها دالة :func:`~sklearn.utils.estimator_checks.check_estimator` ومُزَيِّن :func:`~sklearn.utils.estimator_checks.parametrize_with_checks`. تحدد العلامات الفحوصات التي يجب تشغيلها وبيانات الإدخال المناسبة. يمكن أن تعتمد العلامات على معلمات المقدر أو حتى بنية النظام ويمكن بشكل عام تحديدها فقط في وقت التشغيل. مجموعة علامات المقدر الحالية هي: allow_nan (افتراضيًا = خطأ) ما إذا كان المقدر يدعم البيانات ذات القيم المفقودة المشفرة على أنها np.nan array_api_support (افتراضيًا = خطأ) ما إذا كان المقدر يدعم المدخلات المتوافقة مع واجهة برمجة تطبيقات Array. binary_only (افتراضيًا = خطأ) ما إذا كان المقدر يدعم التصنيف الثنائي ولكنه يفتقر إلى دعم التصنيف متعدد الفئات. multilabel (افتراضيًا = خطأ) ما إذا كان المقدر يدعم المخرجات متعددة التسميات multioutput (افتراضيًا = خطأ) ما إذا كان مقدر الانحدار يدعم مخرجات متعددة الأهداف أو يدعم المصنف مخرجات متعددة الفئات ومتعددة المخرجات. multioutput_only (افتراضيًا = خطأ) ما إذا كان المقدر يدعم فقط التصنيف أو الانحدار متعدد المخرجات. no_validation (افتراضيًا = خطأ) ما إذا كان المقدر يتخطى التحقق من صحة الإدخال. هذا مخصص فقط لـ المحولات عديمة الحالة والوهمية! non_deterministic (افتراضيًا = خطأ) ما إذا كان المقدر غير حتمي نظرًا لـ ``random_state`` ثابت pairwise (افتراضيًا = خطأ) تشير سمة منطقية هذه إلى ما إذا كانت البيانات (`X`) :term:`fit` وأمثالها من الأساليب تتكون من مقاييس زوجية للعينات بدلاً من تمثيل ميزة لكل عينة. عادةً ما تكون `True` حيث يحتوي المقدر على معلمة `metric` أو `affinity` أو `kernel` بقيمة "precomputed". الغرض الأساسي منها هو دعم :term:`meta_estimator` أو إجراء التحقق المتبادل الذي يستخرج عينة فرعية من البيانات المخصصة لمقدر زوجي، حيث يجب فهرسة البيانات على كلا المحورين. على وجه التحديد، يتم استخدام هذه العلامة بواسطة `sklearn.utils.metaestimators._safe_split` لتقطيع الصفوف و الأعمدة. preserves_dtype (افتراضيًا = ``[np.float64]``) ينطبق فقط على المحولات. يتوافق مع أنواع البيانات التي سيتم الحفاظ عليها بحيث يكون `X_trans.dtype` هو نفسه `X.dtype` بعد استدعاء `transformer.transform(X)`. إذا كانت هذه القائمة فارغة، فلا يتوقع أن يحافظ المحول على نوع البيانات. تعتبر القيمة الأولى في القائمة نوع البيانات الافتراضي، المطابق لـ نوع بيانات الإخراج عندما لا يتم الحفاظ على نوع بيانات الإدخال. poor_score (افتراضيًا = خطأ) ما إذا كان المقدر يفشل في توفير درجة "معقولة" لمجموعة الاختبار، والتي هي حاليًا للانحدار R2 من 0.5 على ``make_regression(n_samples=200, n_features=10, n_informative=1, bias=5.0, noise=20, random_state=42)``، و للتصنيف دقة 0.83 على ``make_blobs(n_samples=300, random_state=0)``. تستند مجموعات البيانات والقيم هذه إلى المقدرات الحالية في sklearn وقد يتم استبدالها بشيء أكثر منهجية. requires_fit (افتراضيًا = صحيح) ما إذا كان المقدر يتطلب التوفيق قبل استدعاء أحد `transform` أو `predict` أو `predict_proba` أو `decision_function`. requires_positive_X (افتراضيًا = خطأ) ما إذا كان المقدر يتطلب X موجبًا. requires_y (افتراضيًا = خطأ) ما إذا كان المقدر يتطلب تمرير y إلى أساليب `fit` أو `fit_predict` أو `fit_transform`. تكون العلامة صحيحة للمقدرات التي ترث من `~sklearn.base.RegressorMixin` و `~sklearn.base.ClassifierMixin`. requires_positive_y (افتراضيًا = خطأ) ما إذا كان المقدر يتطلب y موجبًا (ينطبق فقط على الانحدار). _skip_test (افتراضيًا = خطأ) ما إذا كان سيتم تخطي الاختبارات الشائعة تمامًا. لا تستخدم هذا إلا إذا كان لديك سبب *وجيه جدًا*. _xfail_checks (افتراضيًا = خطأ) قاموس ``{check_name: reason}`` من الفحوصات الشائعة التي سيتم تمييزها على أنها `XFAIL` لـ pytest، عند استخدام :func:`~sklearn.utils.estimator_checks.parametrize_with_checks`. سيتم ببساطة تجاهل هذه الفحوصات ولن يتم تشغيلها بواسطة :func:`~sklearn.utils.estimator_checks.check_estimator`، ولكن سيتم طرح `SkipTestWarning`. لا تستخدم هذا إلا إذا كان هناك سبب *وجيه جدًا* لعدم اجتياز المقدر الخاص بك للفحص. لاحظ أيضًا أن استخدام هذه العلامة يخضع للتغيير بدرجة كبيرة لأننا نحاول جعلها أكثر مرونة: كن مستعدًا للتغييرات الجذرية في المستقبل. stateless (افتراضيًا = خطأ) ما إذا كان المقدر يحتاج إلى الوصول إلى البيانات من أجل التوفيق. على الرغم من أن المقدر عديم الحالة، فقد لا يزال بحاجة إلى استدعاء ``fit`` من أجل التهيئة. X_types (افتراضيًا = ["2darray"]) أنواع الإدخال المدعومة لـ X كقائمة من السلاسل. يتم تشغيل الاختبارات حاليًا فقط إذا كانت "2darray" موجودة في القائمة، مما يدل على أن المقدر يأخذ مصفوفات numpy ثنائية الأبعاد مستمرة كمدخلات. القيمة الافتراضية هي ["2darray"]. الأنواع الأخرى المحتملة هي ``'string'`` و ``'sparse'`` و ``'categorical'`` و ``dict`` و ``'1dlabels'`` و ``'2dlabels'``. الهدف هو أنه في المستقبل سيحدد نوع الإدخال المدعوم البيانات المستخدمة أثناء الاختبار، خاصةً للبيانات ``'string'`` و ``'sparse'`` و ``'categorical'``. في الوقت الحالي، لا تستخدم الاختبارات الخاصة بالبيانات المتفرقة علامة ``'sparse'``. من غير المحتمل أن تناسب القيم الافتراضية لكل علامة احتياجات المقدر الخاص بك المحدد. يمكن إنشاء علامات إضافية أو يمكن تجاوز علامات افتراضية عن طريق تعريف أسلوب `_more_tags ()` الذي يُعيد قاموسًا بالعلامات المُلغاة المطلوبة أو العلامات الجديدة. فمثلا:: class MyMultiOutputEstimator(BaseEstimator): def _more_tags(self): return {'multioutput_only': True, 'non_deterministic': True} أي علامة ليست في `_more_tags ()` ستعود إلى القيم الافتراضية الموثقة أعلاه. حتى لو لم يكن ذلك مُوصىً به، فمن الممكن تجاوز أسلوب `_get_tags ()`. لاحظ مع ذلك **أنه يجب أن تكون جميع العلامات موجودة في القاموس**. إذا لم تكن أي من المفاتيح الموثقة أعلاه موجودة في ناتج `_get_tags ()`، فسيحدث خطأ. بالإضافة إلى العلامات، تحتاج المقدرات أيضًا إلى الإعلان عن أي معلمات غير اختيارية إلى ``__init__`` في سمة الفئة ``_required_parameters``، وهي قائمة أو tuple. إذا كانت ``_required_parameters`` هي ``["estimator"]`` أو ``["base_estimator"]`` فقط، فسيتم تهيئة المقدر باستخدام نموذج من ``LogisticRegression`` (أو ``RidgeRegression`` إذا كان المقدر مقدر انحدار) في الاختبارات. اختيار هذين النموذجين غريب نوعًا ما، لكن كلاهما يجب أن يوفر حلولًا قوية مغلقة الشكل. .. _developer_api_set_output: واجهة برمجة تطبيقات المطور لـ `set_output` ============================================= مع `SLEP018 `__، يُقدِّم scikit-learn واجهة برمجة تطبيقات `set_output` لتكوين المحولات لإخراج إطارات بيانات pandas. يتم تعريف واجهة برمجة تطبيقات `set_output` تلقائيًا إذا عرّف المحول :term:`get_feature_names_out` وفئات فرعية :class:`base.TransformerMixin`. يُستخدم :term:`get_feature_names_out` للحصول على أسماء أعمدة ناتج pandas. :class:`base.OneToOneFeatureMixin` و :class:`base.ClassNamePrefixFeaturesOutMixin` هما mixins مفيدان لتعريف :term:`get_feature_names_out`. :class:`base.OneToOneFeatureMixin` مفيد عندما يكون للمحول تطابق واحد لواحد بين ميزات الإدخال وميزات الإخراج، مثل :class:`~preprocessing.StandardScaler`. :class:`base.ClassNamePrefixFeaturesOutMixin` مفيد عندما يحتاج المحول إلى إنشاء أسماء ميزات خاصة به، مثل :class:`~decomposition.PCA`. يمكنك إلغاء الاشتراك في واجهة برمجة تطبيقات `set_output` عن طريق تعيين `auto_wrap_output_keys = None` عند تعريف فئة فرعية مخصصة:: class MyTransformer(TransformerMixin, BaseEstimator, auto_wrap_output_keys=None): def fit(self, X, y=None): return self def transform(self, X, y=None): return X def get_feature_names_out(self, input_features=None): ... القيمة الافتراضية لـ `auto_wrap_output_keys` هي `("transform",)`، والتي تقوم تلقائيًا بالتفاف `fit_transform` و `transform`. يستخدم `TransformerMixin` آلية `__init_subclass__` لاستهلاك `auto_wrap_output_keys` وتمرير جميع وسيطات الكلمات الرئيسية الأخرى إلى فئة super الخاصة به. **لا ينبغي** أن تعتمد `__init_subclass__` لفئات Super على `auto_wrap_output_keys`. بالنسبة للمحولات التي تُعيد مصفوفات متعددة في `transform`، سيقوم التفاف السيارات بالتفاف المصفوفة الأولى فقط ولن يغير المصفوفات الأخرى. انظر :ref:`sphx_glr_auto_examples_miscellaneous_plot_set_output.py` لمثال حول كيفية استخدام واجهة برمجة التطبيقات. .. _developer_api_check_is_fitted: واجهة برمجة تطبيقات المطور لـ `check_is_fitted` ================================================== افتراضيًا، يتحقق :func:`~sklearn.utils.validation.check_is_fitted` مما إذا كان هناك أي سمات في النموذج مع شرطة سفلية زائدة، على سبيل المثال `coef_`. يمكن للمقدر تغيير السلوك عن طريق تنفيذ أسلوب `__sklearn_is_fitted__` لا يأخذ أي مدخلات ويُعيد قيمة منطقية. إذا كان هذا الأسلوب موجودًا، فإن :func:`~sklearn.utils.validation.check_is_fitted` يُعيد ببساطة ناتجه. انظر :ref:`sphx_glr_auto_examples_developing_estimators_sklearn_is_fitted.py` لمثال حول كيفية استخدام واجهة برمجة التطبيقات. واجهة برمجة تطبيقات المطور لتمثيل HTML ========================================== .. warning:: واجهة برمجة تطبيقات تمثيل HTML تجريبية وتخضع واجهة برمجة التطبيقات للتغيير. تعرض المقدرات التي ترث من :class:`~sklearn.base.BaseEstimator` تمثيل HTML لأنفسهم في بيئات البرمجة التفاعلية مثل دفاتر ملاحظات Jupyter. على سبيل المثال، يمكننا عرض مخطط HTML هذا:: from sklearn.base import BaseEstimator BaseEstimator() يتم الحصول على تمثيل HTML الأولي عن طريق استدعاء دالة :func:`~sklearn.utils.estimator_html_repr` على نموذج مقدر. لتخصيص عنوان URL المرتبط بوثائق المقدر (أي عند النقر فوق رمز "?" )، قم بتجاوز سمات `_doc_link_module` و `_doc_link_template`. بالإضافة إلى ذلك، يمكنك توفير أسلوب `_doc_link_url_param_generator`. عيِّن `_doc_link_module` إلى اسم الوحدة (المستوى الأعلى) التي تحتوي على المقدر الخاص بك. إذا لم تتطابق القيمة مع اسم وحدة المستوى الأعلى، فلن يحتوي تمثيل HTML على رابط إلى الوثائق. بالنسبة لمقدرات scikit-learn، يتم تعيين هذا إلى `"sklearn"`. يُستخدم `_doc_link_template` لإنشاء عنوان URL النهائي. افتراضيًا، يمكن أن يحتوي على متغيرين: `estimator_module` (الاسم الكامل للوحدة التي تحتوي على المقدر) و `estimator_name` (اسم فئة المقدر). إذا كنت بحاجة إلى المزيد من المتغيرات، فيجب عليك تنفيذ أسلوب `_doc_link_url_param_generator` الذي يجب أن يُعيد قاموسًا بالمتغيرات وقيمها. سيتم استخدام هذا القاموس لعرض `_doc_link_template`. .. _coding-guidelines: إرشادات الترميز ================= فيما يلي بعض الإرشادات حول كيفية كتابة كود جديد لإدراجه في scikit-learn، والتي قد يكون من المناسب اعتمادها في المشاريع الخارجية. بالطبع، هناك حالات خاصة وستكون هناك استثناءات لهذه القواعد. ومع ذلك، فإن اتباع هذه القواعد عند إرسال كود جديد يجعل المراجعة أسهل حتى يمكن دمج الكود الجديد في وقت أقل. تسهّل التعليمات البرمجية المنسقة بشكل موحد مشاركة ملكية التعليمات البرمجية. يحاول مشروع scikit-learn اتباع إرشادات Python الرسمية المفصّلة في `PEP8 `_ التي توضح كيفية تنسيق التعليمات البرمجية ومسافة بادئة لها. يرجى قراءتها و اتباعها. بالإضافة إلى ذلك، نضيف الإرشادات التالية: * استخدم الشرطات السفلية لفصل الكلمات في الأسماء غير الفئوية: ``n_samples`` بدلاً من ``nsamples``. * تجنب استخدام عبارات متعددة في سطر واحد. فضّل سطر إرجاع بعد عبارة تدفق التحكم (``if``/``for``). * استخدم عمليات الاستيراد النسبية للمراجع داخل scikit-learn. * اختبارات الوحدة هي استثناء للقاعدة السابقة؛ يجب أن تستخدم عمليات الاستيراد المطلقة، تمامًا كما تفعل تعليمات العميل البرمجية. والنتيجة الطبيعية هي أنه إذا صدّرت ``sklearn.foo`` فئة أو دالة تم تنفيذها في ``sklearn.foo.bar.baz``، فيجب على الاختبار استيرادها من ``sklearn.foo``. * **يرجى عدم استخدام** ``import *`` **في أي حالة**. يُعتبر ضارًا من قِبَل `توصيات Python الرسمية `_. يجعل الشفرة أكثر صعوبة في القراءة لأن أصل الرموز لم يعد مرجعًا إليه صراحةً، ولكن الأهم من ذلك، أنه يمنع استخدام أداة تحليل ثابتة مثل `pyflakes `_ للعثور تلقائيًا على الأخطاء في scikit-learn. * استخدم `معيار سلسلة وثائق numpy `_ في جميع سلاسل الوثائق الخاصة بك. يمكن العثور على مثال جيد للتعليمات البرمجية التي نحبها `هنا `_. التحقق من صحة الإدخال ---------------------- .. currentmodule:: sklearn.utils تحتوي الوحدة :mod:`sklearn.utils` على دوال مختلفة للتحقق من صحة الإدخال وتحويله. في بعض الأحيان، يكفي ``np.asarray`` للتحقق من الصحة؛ لا *تستخدم* ``np.asanyarray`` أو ``np.atleast_2d``، حيث إنها تسمح بمرور ``np.matrix`` الخاص بـ NumPy، والذي يحتوي على واجهة برمجة تطبيقات مختلفة (على سبيل المثال، ``*`` تعني حاصل الضرب النقطي على ``np.matrix``، ولكن حاصل الضرب Hadamard على ``np.ndarray``). في حالات أخرى، تأكد من استدعاء :func:`check_array` على أي وسيطة تشبه المصفوفة يتم تمريرها إلى دالة واجهة برمجة تطبيقات scikit-learn. تعتمد المعلمات الدقيقة التي يجب استخدامها بشكل أساسي على ما إذا كان يجب قبول مصفوفات ``scipy.sparse`` وأيها. لمزيد من المعلومات، راجع صفحة :ref:`developers-utils`. الأرقام العشوائية ------------------ إذا كانت التعليمات البرمجية الخاصة بك تعتمد على مُولِّد أرقام عشوائية، فلا تستخدم ``numpy.random.random ()`` أو إجراءات مماثلة. لضمان إمكانية التكرار في فحص الأخطاء، يجب أن يقبل الإجراء كلمة رئيسية ``random_state`` ويستخدم هذا لإنشاء كائن ``numpy.random.RandomState``. انظر :func:`sklearn.utils.check_random_state` في :ref:`developers-utils`. فيما يلي مثال بسيط للتعليمات البرمجية باستخدام بعض الإرشادات المذكورة أعلاه:: from sklearn.utils import check_array, check_random_state def choose_random_sample(X, random_state=0): """اختر نقطة عشوائية من X. المعلمات ---------- X : مصفوفة من الشكل (n_samples, n_features) مصفوفة تمثل البيانات. random_state : int أو نموذج RandomState، افتراضيًا = 0 بذرة مُولِّد الأرقام العشوائية الزائفة الذي يختار عينة عشوائية. مرّر int للحصول على ناتج قابل للتكرار عبر استدعاءات دوال متعددة. انظر :term:`المُصطلحات `. المُخرجات ------- x : ndarray من الشكل (n_features,) نقطة عشوائية محددة من X. """ X = check_array(X) random_state = check_random_state(random_state) i = random_state.randint(X.shape[0]) return X[i] إذا كنت تستخدم العشوائية في مقدر بدلاً من دالة قائمة بذاتها، فتنطبق بعض الإرشادات الإضافية. أولاً، يجب أن يأخذ المقدر وسيطة ``random_state`` إلى ``__init__`` الخاص به بقيمة افتراضية ``None``. يجب أن يخزن قيمة هذه الوسيطة، **دون تعديل**، في سمة ``random_state``. يمكن لـ ``fit`` استدعاء ``check_random_state`` على تلك السمة للحصول على مُولِّد أرقام عشوائية فعلي. إذا كانت هناك حاجة للعشوائية لسبب ما بعد ``fit``، فيجب تخزين RNG في سمة ``random_state_``. يجب أن يوضح المثال التالي هذا:: class GaussianNoise(BaseEstimator, TransformerMixin): """يتجاهل هذا المقدر مدخلاته ويُعيد ضوضاء غاوسية عشوائية. كما أنه لا يلتزم بجميع اتفاقيات scikit-learn، ولكنه يعرض كيفية التعامل مع العشوائية. """ def __init__(self, n_components=100, random_state=None): self.random_state = random_state self.n_components = n_components # يتم تجاهل الوسيطات على أي حال، لذلك نجعلها اختيارية def fit(self, X=None, y=None): self.random_state_ = check_random_state(self.random_state) def transform(self, X): n_samples = X.shape[0] return self.random_state_.randn(n_samples, self.n_components) سبب هذا الإعداد هو إمكانية التكرار: عندما يكون المقدر ``fit`` مرتين لنفس البيانات، يجب أن ينتج نموذجًا متطابقًا في كلتا المرتين، ومن ثم التحقق من الصحة في ``fit``، وليس ``__init__``. التأكيدات العددية في الاختبارات --------------------------------- عند التأكيد على شبه مساواة مصفوفات القيم المستمرة، استخدم `sklearn.utils._testing.assert_allclose`. يتم استنتاج التسامح النسبي تلقائيًا من dtypes المصفوفات المقدمة (لأنواع بيانات float32 و float64 على وجه الخصوص) ولكن يمكنك التجاوز عبر ``rtol``. عند مقارنة مصفوفات العناصر الصفرية، يرجى تقديم قيمة غير صفرية لـ التسامح المطلق عبر ``atol``. لمزيد من المعلومات، يرجى الرجوع إلى سلسلة الوثائق الخاصة بـ `sklearn.utils._testing.assert_allclose`.