تطوير مقدرات scikit-learn#
سواء كنت تقترح مقدرًا لإدراجه في scikit-learn، أو تطوير حزمة منفصلة متوافقة مع scikit-learn، أو تنفيذ مكونات مخصصة لمشاريعك الخاصة، يوضح هذا الفصل كيفية تطوير كائنات تتفاعل بشكل آمن مع خطوط أنابيب scikit-learn وأدوات اختيار النموذج.
واجهات برمجة تطبيقات كائنات scikit-learn#
للحصول على واجهة برمجة تطبيقات موحدة، نحاول أن يكون لدينا واجهة برمجة تطبيقات أساسية مشتركة لجميع الكائنات. بالإضافة إلى ذلك، لتجنب انتشار كود الإطار، نحن نحاول اعتماد اتفاقيات بسيطة والحد من عدد الأساليب التي يجب على الكائن تنفيذها إلى الحد الأدنى.
يتم وصف عناصر واجهة برمجة تطبيقات scikit-learn بشكل أكثر تحديدًا في مسرد المصطلحات الشائعة وعناصر واجهة برمجة التطبيقات.
كائنات مختلفة#
الكائنات الرئيسية في 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
على بعض العمليات العشوائية، انظر
random_state. استثناء آخر لهذه القاعدة هو عندما
يتم تعيين المعلمة الفائقة warm_start
إلى True
للمقدرات التي
تدعمها. warm_start=True
تعني أنه تمت إعادة استخدام الحالة السابقة لـ
معلمات المقدر القابلة للتدريب بدلاً من استخدام
استراتيجية التهيئة الافتراضية.
السمات المقدرة#
يجب أن تحتوي السمات التي تم تقديرها من البيانات دائمًا على اسم
ينتهي بشرطة سفلية زائدة، على سبيل المثال، سيتم تخزين معاملات
بعض مقدرات الانحدار في سمة coef_
بعد
استدعاء fit
.
من المتوقع تجاوز السمات المقدرة عند استدعاء fit
للمرة الثانية.
السمات الاختيارية#
في الخوارزميات التكرارية، يجب تحديد عدد التكرارات بواسطة
عدد صحيح يسمى n_iter
.
السمات العامة#
يجب على المقدرات التي تتوقع إدخالًا جدوليًا تعيين سمة n_features_in_
في وقت fit
للإشارة إلى عدد الميزات التي يتوقعها المقدر
للاستدعاءات اللاحقة لـ predict
أو transform
.
انظر
SLEP010
للتفاصيل.
بناء المقدر الخاص بك#
إذا كنت ترغب في تنفيذ مقدر جديد متوافق مع scikit-learn،
سواء كان ذلك لك فقط أو للمساهمة به في scikit-learn، فهناك
العديد من العناصر الداخلية لـ scikit-learn التي يجب أن تكون على دراية بها بالإضافة إلى
واجهة برمجة تطبيقات scikit-learn الموضحة أعلاه. يمكنك التحقق مما إذا كان المقدر الخاص بك
يلتزم بواجهة ومعايير scikit-learn عن طريق تشغيل
check_estimator
على نموذج.
يمكن أيضًا استخدام مُزَيِّن pytest
parametrize_with_checks
(انظر سلسلة الوثائق الخاصة به للحصول على التفاصيل والتفاعلات الممكنة مع pytest
):
>>> from sklearn.utils.estimator_checks import check_estimator
>>> from sklearn.svm import LinearSVC
>>> check_estimator(LinearSVC()) # يمر
الدافع الرئيسي لجعل الفئة متوافقة مع واجهة مقدر scikit-learn
قد يكون أنك تريد استخدامها مع أدوات اختيار النموذج وتقييمه
مثل model_selection.GridSearchCV
و
pipeline.Pipeline
.
قبل تفصيل الواجهة المطلوبة أدناه، نصف طريقتين لتحقيق الواجهة الصحيحة بسهولة أكبر.
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
اسم (مثل الخطوات المسماة في كائن
Pipeline
)، وفي هذه الحالة يجب أن يصبح
المفتاح <name>__C
و <name>__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
ليست ضرورية (انظر الاستنساخ أدناه)،
فإن دالة 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#
بما أن model_selection.GridSearchCV
يستخدم set_params
لتطبيق إعداد المعلمات على المقدرات،
فمن الضروري أن يكون لاستدعاء set_params
نفس التأثير
مثل تعيين المعلمات باستخدام أسلوب __init__
.
أسهل طريقة موصى بها لتحقيق ذلك هي
عدم إجراء أي تحقق من صحة المعلمات في __init__
.
يجب القيام بكل المنطق وراء معلمات المقدر،
مثل ترجمة وسيطات السلسلة إلى دوال، في fit
.
من المتوقع أيضًا عدم تعيين المعلمات ذات الشرطات السفلية الزائدة _
داخل أسلوب __init__
. جميع السمات العامة التي تم تعيينها
بواسطة fit ولديها شرطة سفلية زائدة _
. نتيجة لذلك، يتم استخدام وجود معلمات ذات
شرطة سفلية زائدة _
للتحقق مما إذا كان المقدر قد تم توفيقه.
الاستنساخ#
لاستخدامه مع وحدة model_selection
،
يجب أن يدعم المقدر دالة base.clone
لتكرار مقدر.
يمكن القيام بذلك عن طريق توفير أسلوب get_params
.
إذا كان get_params
موجودًا، فسيكون clone(estimator)
نموذجًا لـ
type(estimator)
الذي تم استدعاء set_params
عليه مع مستنسخات
نتيجة estimator.get_params()
.
سيتم نسخ الكائنات التي لا توفر هذا الأسلوب بعمق
(باستخدام دالة Python القياسية copy.deepcopy
)
إذا تم تمرير safe=False
إلى clone
.
يمكن للمقدرات تخصيص سلوك base.clone
عن طريق تعريف
أسلوب __sklearn_clone__
. يجب أن يُعيد __sklearn_clone__
نموذجًا لـ
المقدر. __sklearn_clone__
مفيد عندما يحتاج المقدر إلى التمسك
ببعض الحالة عند استدعاء 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
اختياريًا.
أنواع المقدرات#
تعتمد بعض الوظائف الشائعة على نوع المقدر الذي تم تمريره.
على سبيل المثال، يكون التحقق المتبادل في model_selection.GridSearchCV
و
model_selection.cross_val_score
افتراضيًا طبقيًا عند استخدامه
على مصنف، ولكن ليس بخلاف ذلك. وبالمثل، تحتاج أدوات التسجيل لمتوسط الدقة
التي تأخذ تنبؤًا مستمرًا إلى استدعاء decision_function
للمصنفات،
ولكن predict
لمقدرات الانحدار. يتم تنفيذ هذا التمييز بين المصنفات ومقدرات
الانحدار باستخدام سمة _estimator_type
، التي تأخذ قيمة سلسلة.
يجب أن تكون "classifier"
للمصنفات و "regressor"
لمقدرات
الانحدار و "clusterer"
لأساليب التجميع، لتعمل كما هو متوقع.
ستعيِّن الوراثة من ClassifierMixin
أو RegressorMixin
أو ClusterMixin
السمة تلقائيًا. عندما يحتاج مقدر التعريف التلوي إلى التمييز
بين أنواع المقدرات، بدلاً من التحقق من _estimator_type
مباشرةً،
يجب استخدام مساعدين مثل 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 التي تنفذ أنماط النموذج الخطي
الشائعة.
تحتوي الوحدة multiclass
على دوال مفيدة
للعمل مع مشكلات متعددة الفئات ومتعددة التسميات.
واجهة برمجة تطبيقات المطور لـ set_output
#
مع
SLEP018،
يُقدِّم scikit-learn واجهة برمجة تطبيقات set_output
لتكوين المحولات
لإخراج إطارات بيانات pandas. يتم تعريف واجهة برمجة تطبيقات set_output
تلقائيًا إذا
عرّف المحول get_feature_names_out وفئات فرعية
base.TransformerMixin
. يُستخدم get_feature_names_out للحصول على
أسماء أعمدة ناتج pandas.
base.OneToOneFeatureMixin
و
base.ClassNamePrefixFeaturesOutMixin
هما mixins مفيدان لتعريف
get_feature_names_out. base.OneToOneFeatureMixin
مفيد عندما
يكون للمحول تطابق واحد لواحد بين ميزات الإدخال وميزات الإخراج،
مثل StandardScaler
.
base.ClassNamePrefixFeaturesOutMixin
مفيد عندما يحتاج المحول
إلى إنشاء أسماء ميزات خاصة به، مثل 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
، سيقوم التفاف السيارات
بالتفاف المصفوفة الأولى فقط ولن يغير المصفوفات الأخرى.
انظر تقديم واجهة برمجة التطبيقات set_output لمثال حول كيفية استخدام واجهة برمجة التطبيقات.
واجهة برمجة تطبيقات المطور لـ check_is_fitted
#
افتراضيًا، يتحقق check_is_fitted
مما إذا كان هناك
أي سمات في النموذج مع شرطة سفلية زائدة، على سبيل المثال coef_
.
يمكن للمقدر تغيير السلوك عن طريق تنفيذ أسلوب __sklearn_is_fitted__
لا يأخذ أي مدخلات ويُعيد قيمة منطقية. إذا كان هذا الأسلوب موجودًا،
فإن check_is_fitted
يُعيد ببساطة ناتجه.
انظر __sklearn_is_fitted__ كـ API للمطورين لمثال حول كيفية استخدام واجهة برمجة التطبيقات.
واجهة برمجة تطبيقات المطور لتمثيل HTML#
تحذير
واجهة برمجة تطبيقات تمثيل HTML تجريبية وتخضع واجهة برمجة التطبيقات للتغيير.
تعرض المقدرات التي ترث من BaseEstimator
تمثيل HTML لأنفسهم في بيئات البرمجة التفاعلية
مثل دفاتر ملاحظات Jupyter. على سبيل المثال، يمكننا عرض مخطط HTML
هذا:
from sklearn.base import BaseEstimator
BaseEstimator()
يتم الحصول على تمثيل HTML الأولي عن طريق استدعاء دالة
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
.
إرشادات الترميز#
فيما يلي بعض الإرشادات حول كيفية كتابة كود جديد لإدراجه في 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 في جميع سلاسل الوثائق الخاصة بك.
يمكن العثور على مثال جيد للتعليمات البرمجية التي نحبها هنا.
التحقق من صحة الإدخال#
تحتوي الوحدة sklearn.utils
على دوال مختلفة للتحقق من صحة الإدخال
وتحويله. في بعض الأحيان، يكفي np.asarray
للتحقق من الصحة؛
لا تستخدم np.asanyarray
أو np.atleast_2d
، حيث إنها تسمح بمرور
np.matrix
الخاص بـ NumPy، والذي يحتوي على واجهة برمجة تطبيقات مختلفة
(على سبيل المثال، *
تعني حاصل الضرب النقطي على np.matrix
،
ولكن حاصل الضرب Hadamard على np.ndarray
).
في حالات أخرى، تأكد من استدعاء check_array
على أي وسيطة تشبه المصفوفة
يتم تمريرها إلى دالة واجهة برمجة تطبيقات scikit-learn. تعتمد المعلمات الدقيقة التي يجب استخدامها
بشكل أساسي على ما إذا كان يجب قبول مصفوفات scipy.sparse
وأيها.
لمزيد من المعلومات، راجع صفحة أدوات مساعدة للمطورين.
الأرقام العشوائية#
إذا كانت التعليمات البرمجية الخاصة بك تعتمد على مُولِّد أرقام عشوائية، فلا تستخدم
numpy.random.random ()
أو إجراءات مماثلة. لضمان
إمكانية التكرار في فحص الأخطاء، يجب أن يقبل الإجراء كلمة رئيسية
random_state
ويستخدم هذا لإنشاء
كائن numpy.random.RandomState
.
انظر sklearn.utils.check_random_state
في أدوات مساعدة للمطورين.
فيما يلي مثال بسيط للتعليمات البرمجية باستخدام بعض الإرشادات المذكورة أعلاه:
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:`المُصطلحات <random_state>`.
المُخرجات
-------
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
.