ADASYN(Adaptive Synthetic Sampling)是一种基于 SMOTE 的过采样办法,它经过核算每个少量类样本周围的大都类样本份额,决议需求发生的新样本数量。ADASYN 能够更好地习惯不同的数据集,由于它会为那些与大都类更接近的少量类样本发生更多的新样本,而为那些与大都类更远的少量类样本发生较少的新样本。这种办法能够帮助防止发生噪声样本,并提高分类器的性能。

下面是 ADASYN 办法的详细流程:

  1. 关于每个少量类样本,核算它周围大都类样本的份额 p;
  2. 关于每个少量类样本,核算需求发生的新样本数量 n = p * k,其间 k 是一个可调参数,用于控制新样本的数量;
  3. 关于每个少量类样本,从它的 k 个最近邻的大都类样本中随机挑选 n 个样本,并将它们刺进到少量类样本和其 k 个最近邻之间。

下面是 ADASYN 的 Python 代码完成:

import numpy as np
from sklearn.neighbors import NearestNeighbors
def ADASYN(X, y, k=5, ratio=0.5):
    """
    ADASYN: Adaptive Synthetic Sampling
    """
    # 核算每个少量类样本周围大都类样本的数量
    neigh = NearestNeighbors(n_neighbors=k+1)
    neigh.fit(X[y == 1])
    distances, indices = neigh.kneighbors()
    n_samples, n_features = X.shape
    synthetic_X = []
    synthetic_y = []
    for i in range(len(indices)):
        # 核算需求发生的新样本数量
        n = int(round(ratio * indices[i].shape[0]))
        if n == 0:
            continue
        # 关于每个少量类样本,随机挑选 n 个样本,并刺进到样本之间
        for j in range(n):
            nn = np.random.randint(1, indices[i].shape[0])
            dif = X[indices[i][nn]] - X[indices[i][0]]
            gap = np.random.random()
            synthetic = X[indices[i][0]] + gap * dif
            synthetic_X.append(synthetic)
            synthetic_y.append(1)
    synthetic_X = np.array(synthetic_X)
    synthetic_y = np.array(synthetic_y)
    # 将生成的新样本和原始样本兼并成新的练习集
    X = np.vstack((X, synthetic_X))
    y = np.hstack((y, synthetic_y))
    return X, y

上面的代码中,输入 X 是练习数据的特征矩阵,y 是练习数据的标签,k 是指定的 k 值,ratio 是新样本占比的参数。函数首先核算每个少量类样本周围大都类样本的数量,然后随机从大都类样本中挑选必定数量的样本,刺进到少量类样本和其 k 个最近邻之间,生成新的组成样本。最终,将生成的新样本和原始样本兼并成新的练习集回来。

需求留意的是,ADASYN 办法在生成新样本时可能会发生重叠的样本,因此需求在生成后去除重复的样本。

下面是一个简单的示例:

from collections import Counter
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
# 生成一个二分类样本不平衡的数据集
X, y = make_classification(n_classes=2, class_sep=2,
                           weights=[0.1, 0.9], n_informative=3,
                           n_redundant=1, flip_y=0, n_features=20,
                           n_clusters_per_class=1, n_samples=1000,
                           random_state=10)
# 原始数据会集少量类样本的数量
print('Original dataset shape %s' % Counter(y))
# 划分练习集和测验集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=10)
# 运用 ADASYN 过采样办法平衡练习集
X_resampled, y_resampled = ADASYN(X_train, y_train)
# 平衡后的数据会集少量类样本的数量
print('Resampled dataset shape %s' % Counter(y_resampled))
# 练习模型
clf = LogisticRegression(random_state=10)
clf.fit(X_resampled, y_resampled)
# 在测验集上进行猜测并评价性能
y_pred = clf.predict(X_test)
print(classification_report(y_test, y_pred))

在这个示例中,咱们运用了 make_classification() 函数生成一个二分类样本不平衡的数据集,并划分出练习集和测验集。然后,咱们运用 ADASYN 过采样办法平衡练习集,并练习逻辑回归模型进行分类。最终,咱们在测验集上进行猜测并评价模型性能。

上面的代码中运用的 ADASYN() 函数并不是 sklearn 中供给的函数,这里咱们自己完成一下 ADASYN 过采样算法

import numpy as np
from sklearn.neighbors import NearestNeighbors
def ADASYN(X, y, k=5, ratio=1):
    """
    ADASYN 过采样算法完成
    参数:
    X: 原始特征矩阵
    y: 原始标签向量
    k: 挑选 k 个最近邻样本
    ratio: 生成新样本与原样本份额
    回来值:
    new_X: 组成新的特征矩阵
    new_y: 组成新的标签向量
    """
    # 统计少量类样本的数量和大都类样本的数量
    minority_num = sum(y == 1)
    majority_num = sum(y == 0)
    # 核算需求生成的新样本数量
    new_sample_num = int((minority_num * ratio) - minority_num)
    # 假如新样本数量为 0,则回来原始数据集
    if new_sample_num == 0:
        return X, y
    # 核算每个少量类样本需求生成的新样本数量
    num_neighbors = np.zeros(minority_num)
    for i in range(minority_num):
        # 核算少量类样本 i 的 k 个最近邻样本
        nn = NearestNeighbors(n_neighbors=k+1)
        nn.fit(X[y == 1])
        distances, indices = nn.kneighbors(X[y == 1][i].reshape(1, -1))
        # 核算少量类样本 i 和其 k 个最近邻样本中属于大都类的样本数量
        num_neighbors[i] = sum(y[y == 1][indices[0, 1:]] == 0)
    # 核算少量类样本 i 生成新样本的份额,即生成 num_synthetic 样本
    # 需求从其 k 个最近邻样本中挑选 num_synthetic * (num_neighbors[i] / sum(num_neighbors)) 个样本
    synthetic_ratios = num_neighbors / sum(num_neighbors)
    num_synthetic = np.round(synthetic_ratios * new_sample_num).astype(int)
    # 对每个少量类样本 i,依据其 k 个最近邻样本生成 num_synthetic 个新样本
    new_X = []
    new_y = []
    for i in range(minority_num):
        nn = NearestNeighbors(n_neighbors=k+1)
        nn.fit(X[y == 1])
        distances, indices = nn.kneighbors(X[y == 1][i].reshape(1, -1))
        # 生成 num_synthetic[i] 个新样本
        for j in range(num_synthetic[i]):
            # 随机挑选一个少量类样本的 k 个最近邻样本
            nn_index = np.random.randint(1, k+1)
            # 核算组成样本的特征值
            dif = X[y == 1][indices[0, nn_index]] - X[y == 1][i]
            gap = np.random.rand(1, X.shape[1])
            new_X.append(X[y == 1][i] + gap * dif)
            new_y.append(1)
    # 将新生成的新样本和原始数据集兼并,回来组成的新特征矩阵和新标签向量
    new_X = np.vstack([X, np.array(new_X).reshape(-1, X.shape[1])])
    new_y = np.hstack([y, np.array(new_y)])
    return new_X, new_y

以上是 Python 代码完成 ADASYN 过采样算法的过程。经过统计少量类样本的数量和大都类样本的数量,核算需求生成的新样本数量,并依据每个少量类样本的 k 个最近邻样本生成新样本,最终将新生成的样本和原始数据集兼并,即可得到组成的新特征矩阵和新标签向量。