无法在多标签分类器上使用Stratified-K-Fold

时间:2019-02-26 17:19:11

标签: keras scikit-learn deep-learning cross-validation

以下代码用于进行KFold验证,但是我要训练模型,因为它会引发错误

ValueError: Error when checking target: expected dense_14 to have shape (7,) but got array with shape (1,)

我的目标变量有7个类。我正在使用LabelEncoder将类编码为数字。

看到此错误,如果我将更改为MultiLabelBinarizer以对类进行编码。我收到以下错误

ValueError: Supported target types are: ('binary', 'multiclass'). Got 'multilabel-indicator' instead.

以下是KFold验证的代码

skf = StratifiedKFold(n_splits=10, shuffle=True)
scores = np.zeros(10)
idx = 0
for index, (train_indices, val_indices) in enumerate(skf.split(X, y)):
    print("Training on fold " + str(index+1) + "/10...")
    # Generate batches from indices
    xtrain, xval = X[train_indices], X[val_indices]
    ytrain, yval = y[train_indices], y[val_indices]
    model = None
    model = load_model() //defined above

    scores[idx] = train_model(model, xtrain, ytrain, xval, yval)
    idx+=1
print(scores)
print(scores.mean())

我不知道该怎么办。我想在模型上使用分层K折。请帮助我。

1 个答案:

答案 0 :(得分:3)

MultiLabelBinarizer返回一个向量,该向量的长度等于您的类数。

如果查看数据集如何StratifiedKFold splits,您将看到它仅接受一维目标变量,而您尝试传递的是维度为{{1}的目标变量}

分层拆分基本上可以保留您的类分布。如果您考虑一下,如果您遇到多标签分类问题就没有多大意义了。

如果要根据目标变量中类的不同组合来保留分布,则答案here解释了两种定义策略化拆分函数的方法。

更新:

逻辑是这样的:

假设您有[n_samples, n_classes]个类,并且目标变量是这两个n类的组合。您将拥有n个组合(不包括全0)。现在,您可以将每个组合视为新标签来创建新的目标变量。

例如,如果(2^n) - 1,则将有n=3个唯一的组合:

7

将所有标签映射到该新目标变量。现在,您可以将问题视为简单的 multi-class 分类,而不是 multi-label 分类。

现在,您可以使用 1. [1, 0, 0] 2. [0, 1, 0] 3. [0, 0, 1] 4. [1, 1, 0] 5. [1, 0, 1] 6. [0, 1, 1] 7. [1, 1, 1] 作为目标直接使用StartefiedKFold。拆分完成后,您可以将标签映射回去。

代码示例:

y_new

输出:

import numpy as np

np.random.seed(1)
y = np.random.randint(0, 2, (10, 7))
y = y[np.where(y.sum(axis=1) != 0)[0]]

标签编码您的类向量:

array([[1, 1, 0, 0, 1, 1, 1],
       [1, 1, 0, 0, 1, 0, 1],
       [1, 0, 0, 1, 0, 0, 0],
       [1, 0, 0, 1, 0, 0, 0],
       [1, 0, 0, 0, 1, 1, 1],
       [1, 1, 0, 0, 0, 1, 1],
       [1, 1, 1, 1, 0, 1, 1],
       [0, 0, 1, 0, 0, 1, 1],
       [1, 0, 1, 0, 0, 1, 1],
       [0, 1, 1, 1, 1, 0, 0]])

输出:

from sklearn.preprocessing import LabelEncoder

def get_new_labels(y):
    y_new = LabelEncoder().fit_transform([''.join(str(l)) for l in y])
    return y_new

y_new = get_new_labels(y)