У меня есть набор данных с одним классом, который очень несбалансирован (190 записей против 14810) на основе столбца «релевантность». Итак, я попытался повысить частоту дискретизации, и это сработало; но проблема в том, что у меня есть другая категория классов в другом столбце (1000 записей на каждый класс), и когда я просто повышаю выборку на основе столбца «релевантность», эти классы становятся несбалансированными. Есть ли способ увеличить «релевантность», сохраняя это соотношение классов в другом столбце?
# Creating a dataset with a class minority
df_minority = df[df['relevance'] == 1]
# Creating a dataset with the other class
df_rest = df[df['relevance'] != 1]
# Upsample the minority class
df_1_upsampled = resample(df_minority,random_state=SEED,n_samples=14810,replace=True)
# Concatenate the upsampled dataframe
df_upsampled = pd.concat([df_1_upsampled,df_rest])
Пример набора данных:
relevance class 2 3 4 5
1 A 40 24 11 50
1 A 60 20 19 60
0 C 15 57 15 60
0 B 12 50 15 43
0 B 90 8 32 80
0 C 74 8 21 34
Таким образом, цель состоит в том, чтобы сделать количество классов «релевантности» равным, сохраняя соотношение 1:1:1 категории «класс».
Да, у всех из них есть несколько строк с «релевантностью 1». Количество этих строк варьируется для каждого из этих классов; но общее количество строк в классе постоянно и одинаково для каждого класса.
Вот способ сделать это для каждого класса. Обратите внимание, что я не уверен, что это не повлияет на какую-либо модель после этого, здесь недостаточно опыта. Сначала давайте создадим фиктивные данные, которые будут ближе к вашим реальным данным.
# dummy data
np.random.seed(0)
df = pd.DataFrame({
'relevance':np.random.choice(a=[0]*14810+[1]*190,size=15000, replace=False),
'class':list('ABCDEFGHIKLMNOP')*1000,
2 : np.random.randint(0,100, 15000), 3 : np.random.randint(0,100, 15000),
4 : np.random.randint(0,100, 15000), 5 : np.random.randint(0,100, 15000),
})
Просто некоторая проверка релевантности класса, вам все равно понадобится эта информация. У вас есть весь класс с 1000 образцов, и каждый класс имеет разное количество relevance=1
ct = pd.crosstab(df['class'], df['relevance'])
print(ct.head())
# relevance 0 1
# class
# A 983 17
# B 982 18
# C 990 10
# D 993 7
# E 993 7
Теперь вы можете рассчитать количество апсэмплов, необходимых для каждого класса. Обратите внимание, что мы можем определить это несколькими способами, и особенно изменить 1000 на любое число.
nb_upsample = (1000*ct[0].mean()/ct[0]).astype(int)
print(nb_upsample.head())
# class
# A 1004
# B 1005
# C 997
# D 994
# E 994
# Name: 0, dtype: int32
Теперь вы можете увеличить частоту дискретизации для каждого класса
df_1_upsampled = (
df_minority.groupby(['class'])
.apply(lambda x: resample(x, random_state=1, replace=True,
n_samples=nb_upsample[x.name]))
.reset_index(drop=True)
)
print(df_1_upsampled['class'].value_counts().head())
# B 1005
# A 1004
# L 1004
# M 1003
# H 1001
# Name: class, dtype: int64
Наконец, concat и проверьте класс отношения и релевантность
df_upsampled = pd.concat([df_1_upsampled,df_rest])
print(df_upsampled['class'].value_counts().head()) #same ratio
# A 1987
# B 1987
# C 1987
# D 1987
# E 1987
# Name: class, dtype: int64
print(df_upsampled['relevance'].value_counts()) # almost same relevance number
# 1 14995 #this number is affected by the 1000 in nb_upsample
# 0 14810
# Name: relevance, dtype: int64
Вы можете видеть, что теперь релевантность = 1 больше. Что вы можете сделать, так это изменить 1000 в строке, определяющей nb_upsample, на любое число, которое вы хотите. Вы также можете использовать nb_upsample = (ct[0].mean()**2/ct[0]).astype(int), чтобы сбалансировать обе категории релевантности.
Вау, так круто! Именно то, что я хотел сделать; большое спасибо :) Почему вы думаете, что это может повлиять на последующее моделирование? Я не понимаю, почему это должно приводить к какой-либо предвзятости.
@mariant, что я могу сказать, так это то, что до повышения частоты дискретизации соотношение relevance=1 между, скажем, классом A и классом D составляет 17 к 7, то есть более чем в два раза для класса A. точка передискретизации). это может повлиять на вашу модель, нет? это выбор между повторной выборкой только с учетом цели (релевантности) и вашим выбором сохранения соотношения между классами. просто открытый вопрос, я никогда не пробовал это раньше
Хорошо, в ваших реальных данных каждый класс имеет несколько строк с relevance = 1? в вашей игрушке сэмпла нет, поэтому будет сложно апсемплировать и сохранять соотношение между классами.