在许多实际应用中,收集的数据往往是不平衡的,即目标类别的样本数量并不均等。例如,在个人贷款分类问题中,很容易获得“未批准”的数据,而“批准”的数据则相对较少。这种不平衡会导致模型倾向于多数类,从而降低模型的预测能力。此外,不平衡数据还会导致II型错误的增加,在典型的二元分类问题中尤为明显。这种挑战不仅局限于机器学习模型,计算机视觉和自然语言处理领域也同样存在。通过使用不同的技术可以有效处理这些问题。本文将简要介绍各种数据增强方法,而不深入技术细节。
机器学习中的不平衡数据
处理类别不平衡的主要方法是上采样(过采样)和下采样(欠采样)。这些采样过程仅应用于训练集,而不改变验证和测试数据。Python中的imbalanced-learn库可以帮助实现数据重采样。上采样是将少数类的合成数据点注入数据集的过程,使得两个标签的数量几乎相同。这种平衡过程可以防止模型倾向于多数类,同时保持目标类别之间的边界不变。然而,上采样机制会因为额外的信息而引入偏差。
# 导入imbalanced-learn库
from imblearn.over_sampling import SMOTENC
oversample = SMOTENC(categorical_features=[0,1,2,3,4,9,10], random_state = 100)
X, y = oversample.fit_resample(X, y)
数据复制是一种上采样方法,它随机选择对应于少数类的现有数据点并进行复制。
from sklearn.utils import resample
maxcount = 332
train_nonnull_resampled = train_nonnull[0:0]
for grp in train_nonnull['Loan_Status'].unique():
GrpDF = train_nonnull[train_nonnull['Loan_Status'] == grp]
resampled = resample(GrpDF, replace=True, n_samples=int(maxcount), random_state=123)
train_nonnull_resampled = train_nonnull_resampled.append(resampled)
下采样是一种减少多数类训练样本数量的机制。它有助于平衡目标类别的数量。通过移除收集的数据,可能会丢失大量有价值的信息。
from imblearn.under_sampling import TomekLinks
undersample = TomekLinks()
X, y = undersample.fit_resample(X, y)
基于质心的算法试图在多数类中找到同质聚类,并仅保留质心。这将减少多数类的大部分标签。它利用了KMeans聚类中使用的逻辑,但会浪费大量有用信息。
计算机视觉中的不平衡数据
对于图像和文本输入等非结构化数据,上述平衡技术将无效。在计算机视觉中,模型的输入是图像中像素的张量表示。因此,随机更改像素值(以增加更多输入记录)可能会完全改变图片的含义。有一种称为数据增强的概念,即图像经过大量变换,但仍然保持含义不变。
各种图像变换包括缩放、裁剪、翻转、填充、旋转、亮度、对比度和饱和度级别的变化。通过这样做,只需一张图像,就可以创建一个庞大的图像数据集。
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
img = load_img('images/0.jpg')
x = img_to_array(img)
x = x.reshape((1,) + x.shape)
print(x.shape)
i = 0
for batch in datagen.flow(x, batch_size=1, save_to_dir='preview', save_prefix='vehichle', save_format='jpeg'):
i += 1
if i > 19:
break
整个代码以及预训练模型可以在GitHub仓库中找到。
自然语言处理中的不平衡数据
自然语言处理模型处理的是文本等序列数据,当前数据与之前的数据具有时间依赖性。由于文本输入属于非结构化数据,以不同的方式处理这些场景。例如,如果考虑一个工单分类语言模型,其中IT工单需要根据输入文本中出现的单词序列分配给不同的组。
from googletrans import Translator
translator = Translator()
def German_translation(x):
german_translation = translator.translate(x, dest='de')
return german_translation.text
def English_translation(x):
english_translation = translator.translate(x, dest='en')
return english_translation.text
x = German_translation("warning for using windows disk space")
English_translation(x)
import numpy as np
from tensorflow import keras
from sklearn.utils.class_weight import compute_class_weight
y_integers = np.argmax(raw_y_train, axis=1)
class_weights = compute_class_weight('balanced', np.unique(y_integers), y_integers)
d_class_weights = dict(enumerate(class_weights))
history = model.fit(input_final, raw_y_train, batch_size=32, class_weight = d_class_weights, epochs=8,callbacks=[checkpoint,reduceLoss],validation_data =(val_final, raw_y_val), verbose=1)