Scikit-learn: المجموعة الطبقية KFold

تم إنشاؤها على ١١ أبريل ٢٠١٩  ·  48تعليقات  ·  مصدر: scikit-learn/scikit-learn

وصف

لا تحتوي sklearn حاليًا على خاصية kfold للمجموعة الطبقية. إما يمكننا استخدام التقسيم الطبقي أو يمكننا استخدام مجموعة kfold. ومع ذلك ، سيكون من الجيد أن يكون لديك كلاهما.

أود تنفيذه ، إذا قررنا القيام به.

التعليق الأكثر فائدة

سيكون من الجيد أن يصف الأشخاص المهتمون حالة الاستخدام الخاصة بهم وما يريدون حقًا من هذا.

حالة استخدام شائعة جدًا في الطب والبيولوجيا عندما يكون لديك تدابير متكررة.
مثال: افترض أنك تريد تصنيف مرض ، مثل مرض الزهايمر (AD) مقابل عناصر تحكم صحية من صور MR. لنفس الموضوع ، قد يكون لديك عدة عمليات مسح (من جلسات المتابعة أو البيانات الطولية). لنفترض أن لديك ما مجموعه 1000 شخص ، تم تشخيص 200 منهم بمرض الزهايمر (فصول غير متوازنة). تحتوي معظم الموضوعات على مسح ضوئي واحد ، ولكن بالنسبة لبعضها ، تتوفر صورتان أو ثلاث صور. عند تدريب / اختبار المصنف ، فأنت تريد التأكد من أن الصور من نفس الموضوع موجودة دائمًا في نفس الطية لتجنب تسرب البيانات.
من الأفضل استخدام StratifiedGroupKFold من أجل هذا: التقسيم الطبقي لمراعاة عدم توازن الفئة ولكن مع قيود المجموعة التي يجب ألا يظهر الموضوع في طيات مختلفة.
ملحوظة: سيكون من الجيد جعلها قابلة للتكرار.

أدناه مثال على التنفيذ ، مستوحى من kaggle-kernel .

import numpy as np
from collections import Counter, defaultdict
from sklearn.utils import check_random_state

class RepeatedStratifiedGroupKFold():

    def __init__(self, n_splits=5, n_repeats=1, random_state=None):
        self.n_splits = n_splits
        self.n_repeats = n_repeats
        self.random_state = random_state

    # Implementation based on this kaggle kernel:
    #    https://www.kaggle.com/jakubwasikowski/stratified-group-k-fold-cross-validation
    def split(self, X, y=None, groups=None):
        k = self.n_splits
        def eval_y_counts_per_fold(y_counts, fold):
            y_counts_per_fold[fold] += y_counts
            std_per_label = []
            for label in range(labels_num):
                label_std = np.std(
                    [y_counts_per_fold[i][label] / y_distr[label] for i in range(k)]
                )
                std_per_label.append(label_std)
            y_counts_per_fold[fold] -= y_counts
            return np.mean(std_per_label)

        rnd = check_random_state(self.random_state)
        for repeat in range(self.n_repeats):
            labels_num = np.max(y) + 1
            y_counts_per_group = defaultdict(lambda: np.zeros(labels_num))
            y_distr = Counter()
            for label, g in zip(y, groups):
                y_counts_per_group[g][label] += 1
                y_distr[label] += 1

            y_counts_per_fold = defaultdict(lambda: np.zeros(labels_num))
            groups_per_fold = defaultdict(set)

            groups_and_y_counts = list(y_counts_per_group.items())
            rnd.shuffle(groups_and_y_counts)

            for g, y_counts in sorted(groups_and_y_counts, key=lambda x: -np.std(x[1])):
                best_fold = None
                min_eval = None
                for i in range(k):
                    fold_eval = eval_y_counts_per_fold(y_counts, i)
                    if min_eval is None or fold_eval < min_eval:
                        min_eval = fold_eval
                        best_fold = i
                y_counts_per_fold[best_fold] += y_counts
                groups_per_fold[best_fold].add(g)

            all_groups = set(groups)
            for i in range(k):
                train_groups = all_groups - groups_per_fold[i]
                test_groups = groups_per_fold[i]

                train_indices = [i for i, g in enumerate(groups) if g in train_groups]
                test_indices = [i for i, g in enumerate(groups) if g in test_groups]

                yield train_indices, test_indices

مقارنة RepeatedStratifiedKFold (قد تظهر عينة من نفس المجموعة في كلا الطيتين) بـ RepeatedStratifiedGroupKFold :

import matplotlib.pyplot as plt
from sklearn import model_selection

def plot_cv_indices(cv, X, y, group, ax, n_splits, lw=10):
    for ii, (tr, tt) in enumerate(cv.split(X=X, y=y, groups=group)):
        indices = np.array([np.nan] * len(X))
        indices[tt] = 1
        indices[tr] = 0

        ax.scatter(range(len(indices)), [ii + .5] * len(indices),
                   c=indices, marker='_', lw=lw, cmap=plt.cm.coolwarm,
                   vmin=-.2, vmax=1.2)

    ax.scatter(range(len(X)), [ii + 1.5] * len(X), c=y, marker='_',
               lw=lw, cmap=plt.cm.Paired)
    ax.scatter(range(len(X)), [ii + 2.5] * len(X), c=group, marker='_',
               lw=lw, cmap=plt.cm.tab20c)

    yticklabels = list(range(n_splits)) + ['class', 'group']
    ax.set(yticks=np.arange(n_splits+2) + .5, yticklabels=yticklabels,
           xlabel='Sample index', ylabel="CV iteration",
           ylim=[n_splits+2.2, -.2], xlim=[0, 100])
    ax.set_title('{}'.format(type(cv).__name__), fontsize=15)


# demonstration
np.random.seed(1338)
n_splits = 4
n_repeats=5


# Generate the class/group data
n_points = 100
X = np.random.randn(100, 10)

percentiles_classes = [.4, .6]
y = np.hstack([[ii] * int(100 * perc) for ii, perc in enumerate(percentiles_classes)])

# Evenly spaced groups
g = np.hstack([[ii] * 5 for ii in range(20)])


fig, ax = plt.subplots(1,2, figsize=(14,4))

cv_nogrp = model_selection.RepeatedStratifiedKFold(n_splits=n_splits,
                                                   n_repeats=n_repeats,
                                                   random_state=1338)
cv_grp = RepeatedStratifiedGroupKFold(n_splits=n_splits,
                                      n_repeats=n_repeats,
                                      random_state=1338)

plot_cv_indices(cv_nogrp, X, y, g, ax[0], n_splits * n_repeats)
plot_cv_indices(cv_grp, X, y, g, ax[1], n_splits * n_repeats)

plt.show()

RepeatedStratifiedGroupKFold_demo

ال 48 كومينتر

تضمين التغريدة

قد تكون مثيرة للاهتمام من الناحية النظرية ، لكنني لست متأكدًا من مدى فائدتها من الناحية العملية. يمكننا بالتأكيد إبقاء المشكلة مفتوحة ومعرفة عدد الأشخاص الذين يطلبون هذه الميزة

هل تفترض أن كل مجموعة في فصل واحد؟

أنظر أيضا # 9413

jnothman نعم ، كان لدي شيء مماثل في ذهني. ومع ذلك ، أرى أن طلب السحب لا يزال مفتوحًا. قصدت أن المجموعة لن تتكرر عبر الطيات. إذا كان لدينا معرف كمجموعات ، فلن يحدث نفس المعرف عبر طيات متعددة

أنا أفهم أن هذا وثيق الصلة باستخدام RFECV.
حاليًا هذا الإعداد الافتراضي هو استخدام السيرة الذاتية StratifiedKFold. تناسبها () تأخذ أيضًا مجموعات =
ومع ذلك: يبدو أنه لا يتم احترام المجموعات عند تنفيذ fit (). لا يوجد تحذير (يمكن اعتباره خطأ).

يعتبر التجميع والتقسيم الطبقي مفيدًا لمجموعات البيانات غير المتوازنة تمامًا مع التبعية بين السجلات
(في حالتي ، يمتلك نفس الفرد سجلات متعددة ، ولكن لا يزال هناك عدد كبير من المجموعات = الأشخاص بالنسبة إلى عدد الانقسامات ؛ أتخيل أنه ستكون هناك مشكلات عملية حيث يقترب عدد المجموعات الفريدة في فئة الأقليات عدد الانقسامات).

إذن: +1!

هذا سيكون بالتأكيد مفيد على سبيل المثال ، العمل باستخدام بيانات طبية متسلسلة زمنية غير متوازنة بدرجة كبيرة ، مما يجعل المرضى منفصلين ولكن (تقريبًا) يوازنون الفئة غير المتوازنة في كل جزء.

لقد وجدت أيضًا أن StratifiedKFold تأخذ المجموعات كمعامل ولكن لا يتم تجميعها وفقًا لها ، ربما يجب وضع علامة عليها.

استخدام جيد آخر لهذه الميزة هو البيانات المالية ، والتي عادة ما تكون غير متوازنة للغاية. في حالتي ، لدي مجموعة بيانات غير متوازنة بدرجة كبيرة بها عدة سجلات لنفس الكيان (فقط نقاط زمنية مختلفة). نريد عمل GroupKFold لتجنب التسرب ، ولكن أيضًا التقسيم الطبقي نظرًا لاختلال التوازن الكبير ، يمكن أن ينتهي بنا الأمر مع مجموعات قليلة جدًا أو معدومة.

انظر أيضا # 14524 على ما أعتقد؟

حالة استخدام أخرى لـ Stratified GroupShuffleSplit و GroupKFold هي تصميمات "مقاييس متكررة" بيولوجية ، حيث يكون لديك عينات متعددة لكل موضوع أو وحدة بيولوجية أخرى. يوجد أيضًا في العديد من مجموعات بيانات العالم الحقيقي في علم الأحياء عدم توازن في الفئة. كل مجموعة من العينات لها نفس الفئة. لذلك من المهم التقسيم الطبقي والحفاظ على المجموعات معًا.

وصف

لا تحتوي sklearn حاليًا على خاصية kfold للمجموعة الطبقية. إما يمكننا استخدام التقسيم الطبقي أو يمكننا استخدام مجموعة kfold. ومع ذلك ، سيكون من الجيد أن يكون لديك كلاهما.

أود تنفيذه ، إذا قررنا القيام به.

مرحبًا ، أعتقد أنه سيكون مفيدًا جدًا للطب ML. هل تم تنفيذه بالفعل؟

amueller هل تعتقد أننا يجب أن ننفذ هذا ، بالنظر إلى أن الناس مهتمون بذلك؟

أنا مهتم جدًا أيضًا ... سيكون مفيدًا حقًا في التحليل الطيفي عندما يكون لديك عدة مقاييس مكررة لكل عينة من عينتك ، فعليهم حقًا البقاء في نفس الحظيرة أثناء التحقق من الصحة. وإذا كان لديك العديد من الفئات غير المتوازنة التي تحاول تصنيفها ، فأنت تريد حقًا استخدام ميزة الطبقات أيضًا. لذلك أصوت لها أيضًا! عذرًا ، لست جيدًا بما يكفي للمشاركة في التطوير ولكن بالنسبة لأولئك الذين سيشاركون في ذلك ، يمكنك التأكد من أنه سيتم استخدامه :-)
ممتاز لجميع الفريق. شكرا!

يرجى إلقاء نظرة على القضايا المشار إليها والعلاقات العامة في هذا الموضوع حيث تمت محاولة العمل على الأقل على StratifiedGroupKFold . لقد أنجزت بالفعل 15239 StratifiedGroupShuffleSplit # 15239 والذي يحتاج فقط إلى اختبارات لكنني استخدمته بالفعل في عملي الخاص قليلاً.

أعتقد أننا يجب أن ننفذها ، لكنني أعتقد أنني ما زلت لا أعرف ما نريده بالفعل. hermidalc له قيود على أن أعضاء نفس المجموعة يجب أن يكونوا من نفس الفئة. هذه ليست الحالة العامة ، أليس كذلك؟

سيكون من الجيد أن يصف الأشخاص المهتمون حالة الاستخدام الخاصة بهم وما يريدون حقًا من هذا.

هناك # 15239 # 14524 و # 9413 وأتذكر أن جميعها لها دلالات مختلفة.

@ amueller أتفق معك تمامًا ، لقد أمضيت بضع ساعات اليوم في البحث عن شيء ما بين الإصدارات المختلفة المتاحة (# 15239 # 14524 و # 9413) ولكن لم أستطع فهم ما إذا كان أي منها يناسب احتياجاتي. إذن هذه هي حالة الاستخدام الخاصة بي إذا كان بإمكانها المساعدة:
لدي 1000 عينة. تم قياس كل عينة 3 مرات باستخدام مطياف NIR ، بحيث تحتوي كل عينة على 3 مكررات أريد أن أبقى معًا طوال الطريق ...
تنتمي هذه العينات البالغ عددها 1000 إلى 6 فئات مختلفة مع عدد مختلف جدًا من العينات في كل منها:
فئة 1: 400 عينة
فئة 2: 300 عينة
فئة 3: 100 عينة
فئة 4: 100 عينة
فئة 5: 70 عينة
فئة 6:30 عينة
أريد بناء مصنف لكل فئة. لذا فإن الفئة 1 مقابل جميع الفصول الأخرى ، ثم الفئة 2 مقابل جميع الفصول الأخرى ، إلخ.
لتحقيق أقصى قدر من الدقة لكل من المصنفات الخاصة بي ، من المهم أن يكون لدي عينات من الفئات الستة الممثلة في كل جزء من الحظيرة ، لأن فصولي ليست مختلفة تمامًا ، وبالتالي فهي تساعد حقًا في إنشاء حد دقيق بحيث يتم تمثيل الفئات الست دائمًا في كل حظيرة.

هذا هو السبب في أنني أعتقد أن المجموعة الطبقية (دائمًا ما تكون فصول الستة ممثلة في كل جزء) (احتفظ دائمًا بالمقاييس الثلاثة المكررة لكل عينة معًا) يبدو أن kfold هو كثيرًا ما أبحث عنه هنا.
اي رأي؟

حالة الاستخدام الخاصة بي ولماذا كتبت StratifiedGroupShuffleSplit هي دعم تصميمات المقاييس المتكررة https://en.wikipedia.org/wiki/Repeated_measures_design. في حالات الاستخدام الخاصة بي ، يجب أن يكون أعضاء نفس المجموعة من نفس الفئة.

fcoppey بالنسبة لك ، دائمًا ما تحتوي العينات داخل المجموعة على نفس الفئة ، أليس كذلك؟

hermidalc أنا لست على دراية بالمصطلحات ، ولكن من ويكيبيديا يبدو أن "تصميم القياس المتكرر" لا يعني أن نفس المجموعة يجب أن تكون ضمن نفس الفئة كما تقول "تجربة التقاطع لها تصميم مقاييس متكررة حيث يتم تخصيص سلسلة من علاجين أو أكثر لكل مريض ، قد يكون أحدهما علاجًا قياسيًا أو علاجًا وهميًا ".
ربط هذا بإعداد ML ، يمكنك إما محاولة التنبؤ من القياسات ما إذا كان الفرد قد تلقى للتو العلاج أو الدواء الوهمي ، أو يمكنك محاولة التنبؤ بنتيجة العلاج.
لأي من هؤلاء يمكن أن تتغير فئة نفس الفرد ، أليس كذلك؟

بغض النظر عن الاسم ، يبدو لي أن كلاكما لهما نفس حالة الاستخدام ، بينما كنت أفكر في حالة مشابهة لما تم وصفه في دراسة التقاطع. أو ربما يكون الأمر أكثر بساطة: قد يصاب المريض بالمرض بمرور الوقت (أو يتحسن) ، وبالتالي يمكن أن تتغير نتيجة المريض.

في الواقع ، تقول مقالة ويكيبيديا التي تربطها بها صراحةً "التحليل الطولي - تسمح تصاميم المقاييس المتكررة للباحثين بمراقبة كيفية تغير المشاركين بمرور الوقت ، سواء في المواقف طويلة أو قصيرة المدى." ، لذلك أعتقد أن هذا يعني تضمين تغيير الفصل.
إذا كانت هناك كلمة أخرى تعني أن القياس يتم في ظل نفس الظروف ، فيمكننا استخدام هذه الكلمة؟

amueller نعم أنت على حق ، لقد أدركت أنني أخطأت في الكتابة أعلاه حيث قصدت أن أقول في حالات الاستخدام الخاصة بي لهذا التصميم وليس في حالة الاستخدام هذه بشكل عام.

يمكن أن يكون هناك العديد من الأنواع المعقدة تمامًا من تصميمات المقاييس المتكررة ، على الرغم من أنني في النوعين الذين أحتاج إلى StratifiedGroupShuffleSplit ، فإن قيود الفئة نفسها داخل المجموعة (أخذ العينات الطولية قبل وبعد العلاج عند توقع استجابة العلاج ، والمعالجة المسبقة المتعددة عينات لكل موضوع في مواقع مختلفة من الجسم عند التنبؤ باستجابة العلاج).

كنت بحاجة إلى شيء يعمل على الفور وأردت وضعه في مكان آخر ليستخدمه الآخرون وبدء شيء ما على sklearn ، بالإضافة إلى أنه إذا لم أكن مخطئًا ، فسيكون تصميم منطق التقسيم الطبقي أكثر تعقيدًا عندما تكون التسميات داخل فئة المجموعة مختلفة.

amueller نعم دائما. إنها نسخ مكررة لنفس المقياس من أجل تضمين قابلية التباين للجهاز في التنبؤ.

hermidalc نعم ، هذه الحالة أسهل بكثير. إذا كانت هناك حاجة مشتركة ، فأنا سعيد لإضافتها. يجب أن نتأكد فقط من أنه من الواضح إلى حد ما ما يفعله من الاسم ، ويجب أن نفكر فيما إذا كان يجب أن يعيش هذان الإصداران في نفس الفصل.

يجب أن يكون من السهل جدًا جعل StratifiedKFold يفعل ذلك. يوجد خياران: تأكد من أن كل طية تحتوي على عدد مماثل من العينات ، أو تأكد من أن كل حظيرة تحتوي على عدد مماثل من المجموعات.
الثاني هو تافه (من خلال التظاهر فقط كل مجموعة هي نقطة واحدة والتمرير إلى StratifiedKFold ). هذا ما تفعله في العلاقات العامة الخاصة بك ، يبدو.

GroupKFold أعتقد أنه يتم استبدال الاثنين من خلال إضافة إلى أصغر أضعاف أولاً. لست متأكدًا من كيفية ترجمة ذلك إلى الحالة الطبقية ، لذلك أنا سعيد باستخدام نهجك.

هل يجب أن نضيف GroupStratifiedKFold أيضًا في نفس العلاقات العامة؟ أو ترك هذا لوقت لاحق؟
لدى العلاقات العامة الأخرى أهداف مختلفة قليلاً. سيكون من الجيد أن يكتب شخص ما ماهية حالات الاستخدام المختلفة (ربما ليس لدي الوقت الآن).

+1 لمعالجة قيد المجموعة بشكل منفصل حيث تحتوي جميع العينات على نفس الفئة.

hermidalc نعم ، هذه الحالة أسهل بكثير. إذا كانت هناك حاجة مشتركة ، فأنا سعيد لإضافتها. يجب أن نتأكد فقط من أنه من الواضح إلى حد ما ما يفعله من الاسم ، ويجب أن نفكر فيما إذا كان يجب أن يعيش هذان الإصداران في نفس الفصل.

لا أفهم هذا تمامًا ، يجب أن يكون لدى StratifiedGroupShuffleSplit و StratifiedGroupKFold حيث يمكن أن يكون لديك أعضاء من كل مجموعة من فئات مختلفة نفس السلوك المقسم تمامًا عندما يحدد المستخدم جميع أعضاء المجموعة ليكونوا من نفس الفئة. متى يمكن تحسين الأجزاء الداخلية لاحقًا وسيكون السلوك الحالي هو نفسه؟

الثاني هو تافه (من خلال التظاهر فقط أن كل مجموعة هي نقطة واحدة والتمرير إلى StratifiedKFold ). هذا ما تفعله في العلاقات العامة الخاصة بك ، يبدو.

GroupKFold أعتقد أنه يتم استبدال الاثنين من خلال إضافة إلى أصغر أضعاف أولاً. لست متأكدًا من كيفية ترجمة ذلك إلى الحالة الطبقية ، لذلك أنا سعيد باستخدام نهجك.

هل يجب أن نضيف GroupStratifiedKFold أيضًا في نفس العلاقات العامة؟ أو ترك هذا لوقت لاحق؟
لدى العلاقات العامة الأخرى أهداف مختلفة قليلاً. سيكون من الجيد أن يكتب شخص ما ماهية حالات الاستخدام المختلفة (ربما ليس لدي الوقت الآن).

سأضيف StatifiedGroupKFold باستخدام نهج "كل مجموعة عينة واحدة" التي استخدمتها.

سيكون من الجيد أن يصف الأشخاص المهتمون حالة الاستخدام الخاصة بهم وما يريدون حقًا من هذا.

حالة استخدام شائعة جدًا في الطب والبيولوجيا عندما يكون لديك تدابير متكررة.
مثال: افترض أنك تريد تصنيف مرض ، مثل مرض الزهايمر (AD) مقابل عناصر تحكم صحية من صور MR. لنفس الموضوع ، قد يكون لديك عدة عمليات مسح (من جلسات المتابعة أو البيانات الطولية). لنفترض أن لديك ما مجموعه 1000 شخص ، تم تشخيص 200 منهم بمرض الزهايمر (فصول غير متوازنة). تحتوي معظم الموضوعات على مسح ضوئي واحد ، ولكن بالنسبة لبعضها ، تتوفر صورتان أو ثلاث صور. عند تدريب / اختبار المصنف ، فأنت تريد التأكد من أن الصور من نفس الموضوع موجودة دائمًا في نفس الطية لتجنب تسرب البيانات.
من الأفضل استخدام StratifiedGroupKFold من أجل هذا: التقسيم الطبقي لمراعاة عدم توازن الفئة ولكن مع قيود المجموعة التي يجب ألا يظهر الموضوع في طيات مختلفة.
ملحوظة: سيكون من الجيد جعلها قابلة للتكرار.

أدناه مثال على التنفيذ ، مستوحى من kaggle-kernel .

import numpy as np
from collections import Counter, defaultdict
from sklearn.utils import check_random_state

class RepeatedStratifiedGroupKFold():

    def __init__(self, n_splits=5, n_repeats=1, random_state=None):
        self.n_splits = n_splits
        self.n_repeats = n_repeats
        self.random_state = random_state

    # Implementation based on this kaggle kernel:
    #    https://www.kaggle.com/jakubwasikowski/stratified-group-k-fold-cross-validation
    def split(self, X, y=None, groups=None):
        k = self.n_splits
        def eval_y_counts_per_fold(y_counts, fold):
            y_counts_per_fold[fold] += y_counts
            std_per_label = []
            for label in range(labels_num):
                label_std = np.std(
                    [y_counts_per_fold[i][label] / y_distr[label] for i in range(k)]
                )
                std_per_label.append(label_std)
            y_counts_per_fold[fold] -= y_counts
            return np.mean(std_per_label)

        rnd = check_random_state(self.random_state)
        for repeat in range(self.n_repeats):
            labels_num = np.max(y) + 1
            y_counts_per_group = defaultdict(lambda: np.zeros(labels_num))
            y_distr = Counter()
            for label, g in zip(y, groups):
                y_counts_per_group[g][label] += 1
                y_distr[label] += 1

            y_counts_per_fold = defaultdict(lambda: np.zeros(labels_num))
            groups_per_fold = defaultdict(set)

            groups_and_y_counts = list(y_counts_per_group.items())
            rnd.shuffle(groups_and_y_counts)

            for g, y_counts in sorted(groups_and_y_counts, key=lambda x: -np.std(x[1])):
                best_fold = None
                min_eval = None
                for i in range(k):
                    fold_eval = eval_y_counts_per_fold(y_counts, i)
                    if min_eval is None or fold_eval < min_eval:
                        min_eval = fold_eval
                        best_fold = i
                y_counts_per_fold[best_fold] += y_counts
                groups_per_fold[best_fold].add(g)

            all_groups = set(groups)
            for i in range(k):
                train_groups = all_groups - groups_per_fold[i]
                test_groups = groups_per_fold[i]

                train_indices = [i for i, g in enumerate(groups) if g in train_groups]
                test_indices = [i for i, g in enumerate(groups) if g in test_groups]

                yield train_indices, test_indices

مقارنة RepeatedStratifiedKFold (قد تظهر عينة من نفس المجموعة في كلا الطيتين) بـ RepeatedStratifiedGroupKFold :

import matplotlib.pyplot as plt
from sklearn import model_selection

def plot_cv_indices(cv, X, y, group, ax, n_splits, lw=10):
    for ii, (tr, tt) in enumerate(cv.split(X=X, y=y, groups=group)):
        indices = np.array([np.nan] * len(X))
        indices[tt] = 1
        indices[tr] = 0

        ax.scatter(range(len(indices)), [ii + .5] * len(indices),
                   c=indices, marker='_', lw=lw, cmap=plt.cm.coolwarm,
                   vmin=-.2, vmax=1.2)

    ax.scatter(range(len(X)), [ii + 1.5] * len(X), c=y, marker='_',
               lw=lw, cmap=plt.cm.Paired)
    ax.scatter(range(len(X)), [ii + 2.5] * len(X), c=group, marker='_',
               lw=lw, cmap=plt.cm.tab20c)

    yticklabels = list(range(n_splits)) + ['class', 'group']
    ax.set(yticks=np.arange(n_splits+2) + .5, yticklabels=yticklabels,
           xlabel='Sample index', ylabel="CV iteration",
           ylim=[n_splits+2.2, -.2], xlim=[0, 100])
    ax.set_title('{}'.format(type(cv).__name__), fontsize=15)


# demonstration
np.random.seed(1338)
n_splits = 4
n_repeats=5


# Generate the class/group data
n_points = 100
X = np.random.randn(100, 10)

percentiles_classes = [.4, .6]
y = np.hstack([[ii] * int(100 * perc) for ii, perc in enumerate(percentiles_classes)])

# Evenly spaced groups
g = np.hstack([[ii] * 5 for ii in range(20)])


fig, ax = plt.subplots(1,2, figsize=(14,4))

cv_nogrp = model_selection.RepeatedStratifiedKFold(n_splits=n_splits,
                                                   n_repeats=n_repeats,
                                                   random_state=1338)
cv_grp = RepeatedStratifiedGroupKFold(n_splits=n_splits,
                                      n_repeats=n_repeats,
                                      random_state=1338)

plot_cv_indices(cv_nogrp, X, y, g, ax[0], n_splits * n_repeats)
plot_cv_indices(cv_grp, X, y, g, ax[1], n_splits * n_repeats)

plt.show()

RepeatedStratifiedGroupKFold_demo

+1 لـ stratifiedGroupKfold. أحاول الكشف عن حالات سقوط كبار السن بأخذ أجهزة استشعار من ساعة سامرت. نظرًا لأنه ليس لدينا الكثير من بيانات السقوط - فنحن نجري عمليات محاكاة باستخدام ساعات مختلفة لها فئات مختلفة. أقوم أيضًا بإجراء عمليات التعزيز على البيانات قبل تدريبها. من كل نقطة بيانات أقوم بإنشاء 9 نقاط - وهذه مجموعة. من المهم ألا تكون المجموعة في نفس الوقت في التدريب والاختبار كما هو موضح

أود أن أتمكن من استخدام StratifiedGroupKFold أيضًا. إنني أبحث في مجموعة بيانات للتنبؤ بالأزمات المالية ، حيث كانت السنوات التي سبقت كل أزمة وبعدها وأثناءها مجموعتها الخاصة. أثناء التدريب والتحقق المتبادل ، يجب ألا يتسرب أعضاء كل مجموعة بين الطيات.

هل هناك أي طريقة لتعميم ذلك بالنسبة للسيناريو متعدد الملصقات (Multilabel_
stratifiedGroupKfold)؟

+1 لهذا. نحن نحلل حسابات المستخدمين بحثًا عن البريد العشوائي ، لذلك نريد التجميع حسب المستخدم ، ولكن أيضًا التقسيم الطبقي لأن البريد العشوائي منخفض الحدوث نسبيًا. بالنسبة لحالة الاستخدام الخاصة بنا ، يتم وضع علامة على أي مستخدم يرسل بريدًا عشوائيًا مرة واحدة على أنه مرسل بريد عشوائي في جميع البيانات ، لذلك سيكون لعضو المجموعة نفس التصنيف دائمًا.

شكرًا لتقديمك حالة استخدام كلاسيكية لتأطير الوثائق ،
@ فيليب الرابع!

أضفت تطبيق StratifiedGroupKFold إلى نفس PR # 15239 مثل StratifiedGroupShuffleSplit .

على الرغم من أنه كما ترى في العلاقات العامة ، فإن منطق كلاهما أبسط بكثير من https://github.com/scikit-learn/scikit-learn/issues/13621#issuecomment -557802602 لأنني أحاول فقط الحفاظ على النسبة المئوية للمجموعات من أجل كل فصل دراسي (وليس النسبة المئوية للعينات) حتى أتمكن من الاستفادة من الكود الحالي StratifiedKFold و StratifiedShuffleSplit بتمرير معلومات المجموعة الفريدة. لكن كلا التطبيقين ينتج طيات حيث تبقى عينات كل مجموعة معًا في نفس الحظيرة.

على الرغم من أنني سأصوت لأساليب أكثر تعقيدًا استنادًا إلى https://github.com/scikit-learn/scikit-learn/issues/13621#issuecomment -557802602

فيما يلي إصدارات كاملة من StratifiedGroupKFold و RepeatedStratifiedGroupKFold باستخدام الرمز mrunibe الذي قدمته والذي قمت بتبسيطه وتغييره. تتبع هذه الفصول أيضًا تصميم كيفية عمل فئات أخرى من نفس النوع من سيرة ذاتية sklearn.

class StratifiedGroupKFold(_BaseKFold):
    """Stratified K-Folds iterator variant with non-overlapping groups.

    This cross-validation object is a variation of StratifiedKFold that returns
    stratified folds with non-overlapping groups. The folds are made by
    preserving the percentage of samples for each class.

    The same group will not appear in two different folds (the number of
    distinct groups has to be at least equal to the number of folds).

    The difference between GroupKFold and StratifiedGroupKFold is that
    the former attempts to create balanced folds such that the number of
    distinct groups is approximately the same in each fold, whereas
    StratifiedGroupKFold attempts to create folds which preserve the
    percentage of samples for each class.

    Read more in the :ref:`User Guide <cross_validation>`.

    Parameters
    ----------
    n_splits : int, default=5
        Number of folds. Must be at least 2.

    shuffle : bool, default=False
        Whether to shuffle each class's samples before splitting into batches.
        Note that the samples within each split will not be shuffled.

    random_state : int or RandomState instance, default=None
        When `shuffle` is True, `random_state` affects the ordering of the
        indices, which controls the randomness of each fold for each class.
        Otherwise, leave `random_state` as `None`.
        Pass an int for reproducible output across multiple function calls.
        See :term:`Glossary <random_state>`.

    Examples
    --------
    >>> import numpy as np
    >>> from sklearn.model_selection import StratifiedGroupKFold
    >>> X = np.ones((17, 2))
    >>> y = np.array([0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    >>> groups = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8])
    >>> cv = StratifiedGroupKFold(n_splits=3)
    >>> for train_idxs, test_idxs in cv.split(X, y, groups):
    ...     print("TRAIN:", groups[train_idxs])
    ...     print("      ", y[train_idxs])
    ...     print(" TEST:", groups[test_idxs])
    ...     print("      ", y[test_idxs])
    TRAIN: [2 2 4 5 5 5 5 6 6 7]
           [1 1 1 0 0 0 0 0 0 0]
     TEST: [1 1 3 3 3 8 8]
           [0 0 1 1 1 0 0]
    TRAIN: [1 1 3 3 3 4 5 5 5 5 8 8]
           [0 0 1 1 1 1 0 0 0 0 0 0]
     TEST: [2 2 6 6 7]
           [1 1 0 0 0]
    TRAIN: [1 1 2 2 3 3 3 6 6 7 8 8]
           [0 0 1 1 1 1 1 0 0 0 0 0]
     TEST: [4 5 5 5 5]
           [1 0 0 0 0]

    See also
    --------
    StratifiedKFold: Takes class information into account to build folds which
        retain class distributions (for binary or multiclass classification
        tasks).

    GroupKFold: K-fold iterator variant with non-overlapping groups.
    """

    def __init__(self, n_splits=5, shuffle=False, random_state=None):
        super().__init__(n_splits=n_splits, shuffle=shuffle,
                         random_state=random_state)

    # Implementation based on this kaggle kernel:
    # https://www.kaggle.com/jakubwasikowski/stratified-group-k-fold-cross-validation
    def _iter_test_indices(self, X, y, groups):
        labels_num = np.max(y) + 1
        y_counts_per_group = defaultdict(lambda: np.zeros(labels_num))
        y_distr = Counter()
        for label, group in zip(y, groups):
            y_counts_per_group[group][label] += 1
            y_distr[label] += 1

        y_counts_per_fold = defaultdict(lambda: np.zeros(labels_num))
        groups_per_fold = defaultdict(set)

        groups_and_y_counts = list(y_counts_per_group.items())
        rng = check_random_state(self.random_state)
        if self.shuffle:
            rng.shuffle(groups_and_y_counts)

        for group, y_counts in sorted(groups_and_y_counts,
                                      key=lambda x: -np.std(x[1])):
            best_fold = None
            min_eval = None
            for i in range(self.n_splits):
                y_counts_per_fold[i] += y_counts
                std_per_label = []
                for label in range(labels_num):
                    std_per_label.append(np.std(
                        [y_counts_per_fold[j][label] / y_distr[label]
                         for j in range(self.n_splits)]))
                y_counts_per_fold[i] -= y_counts
                fold_eval = np.mean(std_per_label)
                if min_eval is None or fold_eval < min_eval:
                    min_eval = fold_eval
                    best_fold = i
            y_counts_per_fold[best_fold] += y_counts
            groups_per_fold[best_fold].add(group)

        for i in range(self.n_splits):
            test_indices = [idx for idx, group in enumerate(groups)
                            if group in groups_per_fold[i]]
            yield test_indices


class RepeatedStratifiedGroupKFold(_RepeatedSplits):
    """Repeated Stratified K-Fold cross validator.

    Repeats Stratified K-Fold with non-overlapping groups n times with
    different randomization in each repetition.

    Read more in the :ref:`User Guide <cross_validation>`.

    Parameters
    ----------
    n_splits : int, default=5
        Number of folds. Must be at least 2.

    n_repeats : int, default=10
        Number of times cross-validator needs to be repeated.

    random_state : int or RandomState instance, default=None
        Controls the generation of the random states for each repetition.
        Pass an int for reproducible output across multiple function calls.
        See :term:`Glossary <random_state>`.

    Examples
    --------
    >>> import numpy as np
    >>> from sklearn.model_selection import RepeatedStratifiedGroupKFold
    >>> X = np.ones((17, 2))
    >>> y = np.array([0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    >>> groups = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8])
    >>> cv = RepeatedStratifiedGroupKFold(n_splits=2, n_repeats=2,
    ...                                   random_state=36851234)
    >>> for train_index, test_index in cv.split(X, y, groups):
    ...     print("TRAIN:", groups[train_idxs])
    ...     print("      ", y[train_idxs])
    ...     print(" TEST:", groups[test_idxs])
    ...     print("      ", y[test_idxs])
    TRAIN: [2 2 4 5 5 5 5 8 8]
           [1 1 1 0 0 0 0 0 0]
     TEST: [1 1 3 3 3 6 6 7]
           [0 0 1 1 1 0 0 0]
    TRAIN: [1 1 3 3 3 6 6 7]
           [0 0 1 1 1 0 0 0]
     TEST: [2 2 4 5 5 5 5 8 8]
           [1 1 1 0 0 0 0 0 0]
    TRAIN: [3 3 3 4 7 8 8]
           [1 1 1 1 0 0 0]
     TEST: [1 1 2 2 5 5 5 5 6 6]
           [0 0 1 1 0 0 0 0 0 0]
    TRAIN: [1 1 2 2 5 5 5 5 6 6]
           [0 0 1 1 0 0 0 0 0 0]
     TEST: [3 3 3 4 7 8 8]
           [1 1 1 1 0 0 0]

    Notes
    -----
    Randomized CV splitters may return different results for each call of
    split. You can make the results identical by setting `random_state`
    to an integer.

    See also
    --------
    RepeatedStratifiedKFold: Repeats Stratified K-Fold n times.
    """

    def __init__(self, n_splits=5, n_repeats=10, random_state=None):
        super().__init__(StratifiedGroupKFold, n_splits=n_splits,
                         n_repeats=n_repeats, random_state=random_state)

hermidalc أنا في حيرة من أمري بشأن ما توصلنا إليه عند النظر إلى هذا الأمر من وقت لآخر. (لسوء الحظ ، لم يعد وقتي كما كان من قبل!) هل يمكن أن تعطيني فكرة عما توصي بتضمينه في scikit-Learn؟

hermidalc أنا في حيرة من أمري بشأن ما توصلنا إليه عند النظر إلى هذا الأمر من وقت لآخر. (لسوء الحظ ، لم يعد وقتي كما كان من قبل!) هل يمكن أن تعطيني فكرة عما توصي بتضمينه في scikit-Learn؟

أردت أن أفعل تنفيذًا أفضل مما فعلته في # 15239. يعمل التنفيذ في ذلك العلاقات العامة ولكنه يتراكم على المجموعات لجعل المنطق مباشرًا ، على الرغم من أن هذا ليس مثاليًا.

إذن ما فعلته أعلاه (بفضل mrunibe و kaggle من jakubwasikowski) هو تطبيق أفضل لـ StratifiedGroupKFold الذي يتراكم على العينات. أريد أن أنقل نفس المنطق لأقوم بعمل أفضل StratifiedGroupShuffleSplit وبعد ذلك سيكون جاهزًا. سأضع الكود الجديد في # 15239 ليحل محل التطبيق الأقدم.

أعتذر عن العلاقات العامة الخاصة بي التي لم تنته بعد ، فأنا أحصل على درجة الدكتوراه ، لذا لم يكن لدي وقت!

شكرًا لك hermidalc و mrunibe على توفير التنفيذ. لقد كنت أبحث أيضًا عن طريقة StratifiedGroupKFold للتعامل مع البيانات الطبية التي تحتوي على عدم توازن قوي في الفئة وعدد متنوع بشكل كبير من العينات لكل موضوع. يقوم GroupKFold بمفرده بإنشاء مجموعات فرعية من بيانات التدريب تحتوي على فئة واحدة فقط.

أريد نقل نفس المنطق لعمل StratifiedGroupShuffleSplit أفضل وبعد ذلك سيكون جاهزًا.

يمكننا بالتأكيد التفكير في دمج StratifiedGroupKFold قبل أن يصبح StratifiedGroupShuffleSplit جاهزًا.

أعتذر عن العلاقات العامة الخاصة بي التي لم تنته بعد ، فأنا أحصل على درجة الدكتوراه ، لذا لم يكن لدي وقت!

أخبرنا إذا كنت تريد دعمًا لإكماله!

ونتمنى لك التوفيق في عملك لدرجة الدكتوراه

فيما يلي إصدارات كاملة من StratifiedGroupKFold و RepeatedStratifiedGroupKFold باستخدام الرمز mrunibe الذي قدمته والذي قمت

هل من الممكن تجربة هذا؟ حاولت القص واللصق ببعض التبعيات المختلفة لكنها لم تنته أبدًا. أود أن أجرب هذا الفصل في مشروعي. مجرد محاولة لمعرفة ما إذا كانت هناك طريقة متاحة الآن للقيام بذلك.

hermidalc أتمنى أن تكون أعمال الدكتوراه الخاصة بك قد نجحت!
إنني أتطلع إلى الأمام لرؤية هذا التطبيق تم تنفيذه أيضًا لأن عملي في الدكتوراه في علوم الأرض يحتاج إلى ميزة التقسيم الطبقي هذه مع التحكم الجماعي. لقد أمضيت بضع ساعات في تنفيذ فكرة التقسيم يدويًا في مشروعي. لكني تخليت عن إنهائه للسبب نفسه ... تقدم الدكتوراه. لذا ، يمكنني أن أفهم تمامًا كيف يمكن لأعمال الدكتوراه أن تعذب وقت الشخص. لول لا ضغط. في الوقت الحالي ، أستخدم GroupShuffleSplit كبديل.

هتافات

bfeenydispink من السهل جدًا استخدام الفئتين اللتين كتبتهما أعلاه. قم بإنشاء ملف على سبيل المثال split.py بالآتي. ثم في رمز المستخدم الخاص بك إذا كان البرنامج النصي في نفس الدليل مثل split.py ، فأنت تقوم ببساطة باستيراد from split import StratifiedGroupKFold, RepeatedStratifiedGroupKFold

from collections import Counter, defaultdict

import numpy as np

from sklearn.model_selection._split import _BaseKFold, _RepeatedSplits
from sklearn.utils.validation import check_random_state


class StratifiedGroupKFold(_BaseKFold):
    """Stratified K-Folds iterator variant with non-overlapping groups.

    This cross-validation object is a variation of StratifiedKFold that returns
    stratified folds with non-overlapping groups. The folds are made by
    preserving the percentage of samples for each class.

    The same group will not appear in two different folds (the number of
    distinct groups has to be at least equal to the number of folds).

    The difference between GroupKFold and StratifiedGroupKFold is that
    the former attempts to create balanced folds such that the number of
    distinct groups is approximately the same in each fold, whereas
    StratifiedGroupKFold attempts to create folds which preserve the
    percentage of samples for each class.

    Read more in the :ref:`User Guide <cross_validation>`.

    Parameters
    ----------
    n_splits : int, default=5
        Number of folds. Must be at least 2.

    shuffle : bool, default=False
        Whether to shuffle each class's samples before splitting into batches.
        Note that the samples within each split will not be shuffled.

    random_state : int or RandomState instance, default=None
        When `shuffle` is True, `random_state` affects the ordering of the
        indices, which controls the randomness of each fold for each class.
        Otherwise, leave `random_state` as `None`.
        Pass an int for reproducible output across multiple function calls.
        See :term:`Glossary <random_state>`.

    Examples
    --------
    >>> import numpy as np
    >>> from sklearn.model_selection import StratifiedGroupKFold
    >>> X = np.ones((17, 2))
    >>> y = np.array([0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    >>> groups = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8])
    >>> cv = StratifiedGroupKFold(n_splits=3)
    >>> for train_idxs, test_idxs in cv.split(X, y, groups):
    ...     print("TRAIN:", groups[train_idxs])
    ...     print("      ", y[train_idxs])
    ...     print(" TEST:", groups[test_idxs])
    ...     print("      ", y[test_idxs])
    TRAIN: [2 2 4 5 5 5 5 6 6 7]
           [1 1 1 0 0 0 0 0 0 0]
     TEST: [1 1 3 3 3 8 8]
           [0 0 1 1 1 0 0]
    TRAIN: [1 1 3 3 3 4 5 5 5 5 8 8]
           [0 0 1 1 1 1 0 0 0 0 0 0]
     TEST: [2 2 6 6 7]
           [1 1 0 0 0]
    TRAIN: [1 1 2 2 3 3 3 6 6 7 8 8]
           [0 0 1 1 1 1 1 0 0 0 0 0]
     TEST: [4 5 5 5 5]
           [1 0 0 0 0]

    See also
    --------
    StratifiedKFold: Takes class information into account to build folds which
        retain class distributions (for binary or multiclass classification
        tasks).

    GroupKFold: K-fold iterator variant with non-overlapping groups.
    """

    def __init__(self, n_splits=5, shuffle=False, random_state=None):
        super().__init__(n_splits=n_splits, shuffle=shuffle,
                         random_state=random_state)

    # Implementation based on this kaggle kernel:
    # https://www.kaggle.com/jakubwasikowski/stratified-group-k-fold-cross-validation
    def _iter_test_indices(self, X, y, groups):
        labels_num = np.max(y) + 1
        y_counts_per_group = defaultdict(lambda: np.zeros(labels_num))
        y_distr = Counter()
        for label, group in zip(y, groups):
            y_counts_per_group[group][label] += 1
            y_distr[label] += 1

        y_counts_per_fold = defaultdict(lambda: np.zeros(labels_num))
        groups_per_fold = defaultdict(set)

        groups_and_y_counts = list(y_counts_per_group.items())
        rng = check_random_state(self.random_state)
        if self.shuffle:
            rng.shuffle(groups_and_y_counts)

        for group, y_counts in sorted(groups_and_y_counts,
                                      key=lambda x: -np.std(x[1])):
            best_fold = None
            min_eval = None
            for i in range(self.n_splits):
                y_counts_per_fold[i] += y_counts
                std_per_label = []
                for label in range(labels_num):
                    std_per_label.append(np.std(
                        [y_counts_per_fold[j][label] / y_distr[label]
                         for j in range(self.n_splits)]))
                y_counts_per_fold[i] -= y_counts
                fold_eval = np.mean(std_per_label)
                if min_eval is None or fold_eval < min_eval:
                    min_eval = fold_eval
                    best_fold = i
            y_counts_per_fold[best_fold] += y_counts
            groups_per_fold[best_fold].add(group)

        for i in range(self.n_splits):
            test_indices = [idx for idx, group in enumerate(groups)
                            if group in groups_per_fold[i]]
            yield test_indices


class RepeatedStratifiedGroupKFold(_RepeatedSplits):
    """Repeated Stratified K-Fold cross validator.

    Repeats Stratified K-Fold with non-overlapping groups n times with
    different randomization in each repetition.

    Read more in the :ref:`User Guide <cross_validation>`.

    Parameters
    ----------
    n_splits : int, default=5
        Number of folds. Must be at least 2.

    n_repeats : int, default=10
        Number of times cross-validator needs to be repeated.

    random_state : int or RandomState instance, default=None
        Controls the generation of the random states for each repetition.
        Pass an int for reproducible output across multiple function calls.
        See :term:`Glossary <random_state>`.

    Examples
    --------
    >>> import numpy as np
    >>> from sklearn.model_selection import RepeatedStratifiedGroupKFold
    >>> X = np.ones((17, 2))
    >>> y = np.array([0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    >>> groups = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8])
    >>> cv = RepeatedStratifiedGroupKFold(n_splits=2, n_repeats=2,
    ...                                   random_state=36851234)
    >>> for train_index, test_index in cv.split(X, y, groups):
    ...     print("TRAIN:", groups[train_idxs])
    ...     print("      ", y[train_idxs])
    ...     print(" TEST:", groups[test_idxs])
    ...     print("      ", y[test_idxs])
    TRAIN: [2 2 4 5 5 5 5 8 8]
           [1 1 1 0 0 0 0 0 0]
     TEST: [1 1 3 3 3 6 6 7]
           [0 0 1 1 1 0 0 0]
    TRAIN: [1 1 3 3 3 6 6 7]
           [0 0 1 1 1 0 0 0]
     TEST: [2 2 4 5 5 5 5 8 8]
           [1 1 1 0 0 0 0 0 0]
    TRAIN: [3 3 3 4 7 8 8]
           [1 1 1 1 0 0 0]
     TEST: [1 1 2 2 5 5 5 5 6 6]
           [0 0 1 1 0 0 0 0 0 0]
    TRAIN: [1 1 2 2 5 5 5 5 6 6]
           [0 0 1 1 0 0 0 0 0 0]
     TEST: [3 3 3 4 7 8 8]
           [1 1 1 1 0 0 0]

    Notes
    -----
    Randomized CV splitters may return different results for each call of
    split. You can make the results identical by setting `random_state`
    to an integer.

    See also
    --------
    RepeatedStratifiedKFold: Repeats Stratified K-Fold n times.
    """

    def __init__(self, n_splits=5, n_repeats=10, random_state=None):
        super().__init__(StratifiedGroupKFold, n_splits=n_splits,
                         n_repeats=n_repeats, random_state=random_state)

hermidalc شكرا لك على الرد الإيجابي!
أنا أتبناه بسرعة كما وصفت. ومع ذلك ، يمكنني فقط الحصول على الانقسامات التي تحتوي على بيانات فقط في مجموعة التدريب أو الاختبار. بقدر ما أفهم وصف الكود ، لا توجد معلمة لتحديد النسبة بين مجموعات التدريب والاختبار ، أليس كذلك؟
أعلم أنه تعارض بين التقسيم الطبقي والتحكم في المجموعة ونسبة مجموعات البيانات ... لهذا السبب تخليت عن الاستمرار ... ولكن ربما لا يزال بإمكاننا إيجاد حل وسط للعمل حوله.
image

بإخلاص

hermidalc شكرا لك على الرد الإيجابي!
أنا أتبناه بسرعة كما وصفت. ومع ذلك ، يمكنني فقط الحصول على الانقسامات التي تحتوي على بيانات فقط في مجموعة التدريب أو الاختبار. بقدر ما أفهم وصف الكود ، لا توجد معلمة لتحديد النسبة بين مجموعات التدريب والاختبار ، أليس كذلك؟
أعلم أنه تعارض بين التقسيم الطبقي والتحكم في المجموعة ونسبة مجموعات البيانات ... لهذا السبب تخليت عن الاستمرار ... ولكن ربما لا يزال بإمكاننا إيجاد حل وسط للعمل حوله.

لاختبار لقد صنعت split.py وقام بتشغيل هذا المثال في ipython وهو يعمل. لقد كنت أستخدم مكررات السيرة الذاتية المخصصة هذه في عملي لفترة طويلة وليس لديهم أي مشاكل من جانبي. راجع للشغل أنا أستخدم scikit- Learn 0.22.2 وليس 0.23.x ، لذلك لست متأكدًا مما إذا كان هذا هو سبب المشكلة. هل يمكنك محاولة تشغيل هذا المثال أدناه ومعرفة ما إذا كان يمكنك إعادة إنتاجه؟ إذا استطعت ، فقد يكون شيئًا ما مع y و groups في عملك.

In [6]: import numpy as np 
   ...: from split import StratifiedGroupKFold 
   ...:  
   ...: X = np.ones((17, 2)) 
   ...: y = np.array([0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 
   ...: groups = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8]) 
   ...: cv = StratifiedGroupKFold(n_splits=3, shuffle=True, random_state=777) 
   ...: for train_idxs, test_idxs in cv.split(X, y, groups): 
   ...:     print("TRAIN:", groups[train_idxs]) 
   ...:     print("      ", y[train_idxs]) 
   ...:     print(" TEST:", groups[test_idxs]) 
   ...:     print("      ", y[test_idxs]) 
   ...:                                                                                                                                                                                                    
TRAIN: [2 2 4 5 5 5 5 6 6 7]
       [1 1 1 0 0 0 0 0 0 0]
 TEST: [1 1 3 3 3 8 8]
       [0 0 1 1 1 0 0]
TRAIN: [1 1 3 3 3 4 5 5 5 5 8 8]
       [0 0 1 1 1 1 0 0 0 0 0 0]
 TEST: [2 2 6 6 7]
       [1 1 0 0 0]
TRAIN: [1 1 2 2 3 3 3 6 6 7 8 8]
       [0 0 1 1 1 1 1 0 0 0 0 0]
 TEST: [4 5 5 5 5]
       [1 0 0 0 0]

يبدو أن هناك اهتمامًا منتظمًا بهذه الميزة ، hermidalc ، ونحن
من المحتمل أن تجد شخصًا ما لإنهائه إذا كنت لا تمانع.

hermidalc "عليك التأكد من أن كل عينة في نفس المجموعة لها نفس تصنيف الفصل." من الواضح أن هذه هي المشكلة. عيناتي في نفس المجموعة لا تشترك في نفس الفصل. ط ط ط ... يبدو أنه فرع آخر من التنمية.
شكرا جزيلا لك على أي حال.

hermidalc "عليك التأكد من أن كل عينة في نفس المجموعة لها نفس تصنيف الفصل." من الواضح أن هذه هي المشكلة. عيناتي في نفس المجموعة لا تشترك في نفس الفصل. ط ط ط ... يبدو أنه فرع آخر من التنمية.
شكرا جزيلا لك على أي حال.

نعم لقد تمت مناقشة هذا في مواضيع مختلفة هنا. إنها حالة استخدام أخرى أكثر تعقيدًا وهي مفيدة ، لكن الكثيرين مثلي لا يحتاجون إلى حالة الاستخدام هذه حاليًا ولكنهم يحتاجون إلى شيء ما يحافظ على المجموعات معًا ولكن يتم تقسيمها إلى طبقات على العينات. متطلبات الكود أعلاه هي أن جميع العينات في كل مجموعة تنتمي إلى نفس الفئة.

في الواقع dispink كنت مخطئًا ، هذه الخوارزمية لا تتطلب أن ينتمي جميع أعضاء المجموعة إلى نفس الفئة. فمثلا:

In [2]: X = np.ones((17, 2)) 
   ...: y =      np.array([0, 2, 1, 1, 2, 0, 0, 1, 2, 1, 1, 1, 0, 2, 0, 1, 0]) 
   ...: groups = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8]) 
   ...: cv = StratifiedGroupKFold(n_splits=3) 
   ...: for train_idxs, test_idxs in cv.split(X, y, groups): 
   ...:     print("TRAIN:", groups[train_idxs]) 
   ...:     print("      ", y[train_idxs]) 
   ...:     print(" TEST:", groups[test_idxs]) 
   ...:     print("      ", y[test_idxs]) 
   ...:                                                                                                                                                                                                    
TRAIN: [1 1 2 2 3 3 3 4 8 8]
       [0 2 1 1 2 0 0 1 1 0]
 TEST: [5 5 5 5 6 6 7]
       [2 1 1 1 0 2 0]
TRAIN: [1 1 4 5 5 5 5 6 6 7 8 8]
       [0 2 1 2 1 1 1 0 2 0 1 0]
 TEST: [2 2 3 3 3]
       [1 1 2 0 0]
TRAIN: [2 2 3 3 3 5 5 5 5 6 6 7]
       [1 1 2 0 0 2 1 1 1 0 2 0]
 TEST: [1 1 4 8 8]
       [0 2 1 1 0]

لذلك لست متأكدًا تمامًا مما يحدث مع بياناتك ، لأنه حتى مع لقطات الشاشة الخاصة بك ، لا يمكنك حقًا رؤية تخطيط البيانات وما قد يحدث. أود أن أقترح عليك أولاً إعادة إنتاج الأمثلة التي عرضتها هنا للتأكد من أنها ليست مشكلة في إصدار scikit-Learn (بما أنني أستخدم 0.22.2) وإذا كان بإمكانك إعادة إنتاجها ، فأقترح أن تبدأ من أجزاء صغيرة من البيانات واختبارها. من الصعب استكشاف أخطاء استخدام ~ 104 كيلو عينة.

hermidalc شكرا لك على الرد!
يمكنني بالفعل إعادة إنتاج النتيجة أعلاه ، لذلك أقوم الآن باستكشاف الأخطاء وإصلاحها باستخدام بيانات أصغر.

+1

هل يمانع أي شخص إذا اخترت هذه المشكلة؟
يبدو أن # 15239 مع https://github.com/scikit-learn/scikit-learn/issues/13621#issuecomment -600894432 لديهم تنفيذ بالفعل ولا يتبقى سوى اختبارات الوحدة.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات