【機械学習】多分類・多ラベル分類アルゴリズム(ソースコード含む)

1. 単一ラベル二項分類問題

1.1 シングルラベルバイナリ分類アルゴリズムの原理

単一ラベルのバイナリ分類の問題は、私たちの最も一般的なアルゴリズムの問​​題です. これは主に、ラベル ラベルの値が 2 つしかなく、アルゴリズムで予測する必要があるラベル ラベルが 1 つしかないことを意味します。率直に言って、各インスタンスの可能なカテゴリは 2 つのタイプ (A または B) のみです; この時点での分類アルゴリズムは、実際にはデータを 2 つのカテゴリに分割する分類線を構築しています。一般的なアルゴリズム: ロジスティック、SVM、KNN、決定木など

ここに画像の説明を挿入
ロジスティック アルゴリズムの原理:

ここに画像の説明を挿入

2. 単一ラベル多分類問題

単一ラベルの複数分類の問題は、実際には、予測されるラベル ラベルが 1 つだけであることを意味しますが、ラベル ラベルの値には多くの状況がある可能性があります。率直に言えば、各インスタンスに対して KK の可能なカテゴリがありますK種 (t 1 t_1t1t 2 t_2t2, ⋯ \cdots ,tk t_ktk,k≥3); 一般的なアルゴリズム: Softmax、KNN、決定木など
ここに画像の説明を挿入
ここに画像の説明を挿入

実際の作業では、それが多分類問題である場合、解決する問題を二分分類アルゴリズムの拡張に変換する、つまり、多分類タスクをいくつかの二分分類タスクに分割して解決することができます。以下のとおりであります:

  • One-Versus-One(ovo): 一対一
  • One-Versus-All / One-Versus-the-Rest (ova/ovr): 一対多
  • エラー訂正出力コード (エラー訂正コード メカニズム): 多対多

ここに画像の説明を挿入

2.1 オボ

原理:

ウィルKKKカテゴリの 2 つのカテゴリのデータを結合し、結合したデータを使用してモデルをトレーニングすると、K ( K − 1 ) / 2 K(K-1)/2 が得られます。K ( K/2分類器、これらの分類器の結果が融合され、多数決によって分類器の予測結果が出力され、最終的な予測結果値が出力される。

ここに画像の説明を挿入

2.1.1 手書きコード

def ovo(datas,estimator):
    '''datas[:,-1]为目标属性'''
    import numpy as np
    Y = datas[:,-1]
    X = datas[:,:-1]
    y_value = np.unique(Y)

    #计算类别数目
    k = len(y_value)
    modles = []
    #将K个类别中的两两类别数据进行组合,并对y值进行处理
    for i in range(k-1):
        c_i = y_value[i]
        for j in range(i+1,k):
            c_j = y_value[j]
            new_datas = []
            for x,y in zip(X,Y):
                if y == c_i or y == c_j:
                    new_datas.append(np.hstack((x,np.array([2*float(y==c_i)-1]))))
            new_datas = np.array(new_datas)
            algo = estimator()
            modle = algo.fit(new_datas)
            modles.append([(c_i,c_j),modle])
    return modles
def argmaxcount(seq):
    '''计算序列中出现次数最多元素'''
    '''超极简单的方法'''
    # from collections import Counter
    # return Counter(seq).values[0]

    '''稍微复杂的'''
    # dict_num = {}
    # for item in seq:
    #     if item not in dict_num.keys():
    #         dict_num[item] = seq.count(item)
    # # 排序
    # import operator
    # sorted(dict_num.items(), key=operator.itemgetter(1))

    '''字典推导'''
    dict_num = dict_num = {
    
    i: seq.count(i) for i in set(seq)}

def ovo_predict(X,modles):
    import operator
    result = []
    for x in X:
        pre = []
        for cls,modle in modles:
            pre.append(cls[0] if modle.predict(x) else cls[1])
        d = {
    
    i: pre.count(i) for i in set(pre)} #利用集合的特性去重
        result.append(sorted(d.items(),key=operator.itemgetter(1))[-1][0])
    return result

カプセル化されたコードを直接呼び出すこともできます。

2.1.2 呼び出し API

class sklearn.multiclass.OneVsOneClassifier(estimator, n_jobs=1)

ここに画像の説明を挿入
ここに画像の説明を挿入
コードは以下のように表示されます:

from sklearn import datasets
from sklearn.multiclass import OneVsOneClassifier
from sklearn.svm import LinearSVC
from sklearn.neighbors import KNeighborsClassifier

# 加载数据
iris = datasets.load_iris()

# 获取X和y
X, y = iris.data, iris.target
print("样本数量:%d, 特征数量:%d" % X.shape)
# 设置为3,只是为了增加类别,看一下ovo和ovr的区别
y[-1] = 3

# 模型构建
clf = OneVsOneClassifier(LinearSVC(random_state=0))
# clf = OneVsOneClassifier(KNeighborsClassifier())
# 模型训练
clf.fit(X, y)

# 输出预测结果值
print(clf.predict(X))
print("效果:{}".format(clf.score(X, y)))

# 模型属性输出
k = 1
for item in clf.estimators_:
    print("第%d个模型:" % k, end="")
    print(item)
    k += 1
print(clf.classes_)

2.2 オーバー

原理:

1 対多のモデル トレーニングでは、2 つのカテゴリを組み合わせる代わりに、各カテゴリを正の例として使用し、残りの例を負の例として使用して、それぞれ KK をトレーニングしますKモデル; 次に、このKKの場合、予測する場合K 個のモデルのうち、1 つのモデル出力のみが正の例であり、最終的な予測結果は分類器のこのカテゴリに属します; 複数の正の例が生成された場合、指標として分類器の信頼度に基づいて信頼度を選択できます. 最高次数の分類子が最終結果として使用されます。共通の信頼度: 精度、再現率。

ここに画像の説明を挿入

2.2.1 手書きコード

def ovr(datas,estimator):
    '''datas[:,-1]为目标属性'''
    import numpy as np
    Y = datas[:,-1]
    X = datas[:,:-1]
    y_value = np.unique(Y)

    #计算类别数目
    k = len(y_value)
    modles = []
    #准备K个模型的训练数据,并对y值进行处理
    for i in range(k):
        c_i = y_value[i]
        new_datas = []
        for x,y in zip(X,Y):
            new_datas.append(np.hstack((x,np.array([2*float(y==c_i)-1]))))
        new_datas = np.array(new_datas)
        algo = estimator()
        modle = algo.fit(new_datas)
        confidence = modle.score(new_datas) #计算置信度
        modles.append([(c_i,confidence),modle])
    return modles

def ovr_predict(X,modles):
    import operator
    result = []
    for x in X:
        pre = []
        cls_confi = []
        for cls,modle in modles:
            cls_confi.append(cls)
            pre.append(modle.predict(x))
        pre_res = []
        for c,p in zip(cls_confi,pre):
            if p == 1:
                pre_res.append(c)
        if not pre_res:
            pre_res = cls_confi
        result.append(sorted(pre_res,key=operator.itemgetter(1))[-1][0])
    return result

2.2.2 呼び出し API

sklearn.multiclass.OneVsRestClassifier

ここに画像の説明を挿入
ここに画像の説明を挿入
コードは以下のように表示されます:

from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score

# 数据获取
iris = datasets.load_iris()
X, y = iris.data, iris.target
print("样本数量:%d, 特征数量:%d" % X.shape)
# 设置为3,只是为了增加类别,看一下ovo和ovr的区别
y[-1] = 3

# 模型创建
clf = OneVsRestClassifier(LinearSVC(random_state=0))
# 模型构建
clf.fit(X, y)

# 预测结果输出
print(clf.predict(X))

# 模型属性输出
k = 1
for item in clf.estimators_:
    print("第%d个模型:" % k, end="")
    print(item)
    k += 1
print(clf.classes_)

2.3 OvO と OvR の違い

ここに画像の説明を挿入

2.4 エラー訂正

理論的根拠: モデル構築アプリケーションを 2 つのフェーズ (エンコード フェーズとデコード フェーズ) に分割します。

符号化段階では、K 個のカテゴリ間で M 個の分割が行われます.各分割は、データの一部を肯定的なカテゴリに、データの一部を否定的なカテゴリに分割します.モデルは、分割ごとに構築されます.モデルの結果は各クラスのスペースはそれぞれポイントを定義します。

デコード段階では、トレーニングされたモデルを使用してテスト サンプルを予測し、予測されたサンプルに対応するポイントとカテゴリの間の距離が計算され、距離が最も近いカテゴリが最終的な予測カテゴリとして選択されます。

ここに画像の説明を挿入

sklearn.multiclass.OutputCodeClassifier

コードの構造は次のとおりです。

class sklearn.multiclass.OutputCodeClassifier(estimator, code_size=1.5, random_state=None, n_jobs=1)

ここに画像の説明を挿入
ここに画像の説明を挿入
コードは以下のように表示されます:

from sklearn import datasets
from sklearn.multiclass import OutputCodeClassifier
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score

# 数据获取
iris = datasets.load_iris()
X, y = iris.data, iris.target
print("样本数量:%d, 特征数量:%d" % X.shape)

# 模型对象创建
# code_size: 指定最终使用多少个子模型,实际的子模型的数量=int(code_size*label_number)
# code_size设置为1,等价于ovr子模型个数;
# 设置为0~1, 那相当于使用比较少的数据划分,效果比ovr差; 
# 设置为大于1的值,那么相当于存在部分模型冗余的情况
clf = OutputCodeClassifier(LinearSVC(random_state=0), code_size=30, random_state=0)
# 模型构建
clf.fit(X, y)

# 输出预测结果值
print(clf.predict(X))
print("准确率:%.3f" % accuracy_score(y, clf.predict(X)))

# 模型属性输出
k = 1
for item in clf.estimators_:
    print("第%d个模型:" % k, end="")
    print(item)
    k += 1
print(clf.classes_)

ここに画像の説明を挿入

3. マルチラベル アルゴリズムの問​​題

Multi-Label Machine Learning(MLL アルゴリズム) は、予測モデルに複数の y 値が存在することを指します。これは、次の 2 つの異なる状況に分けることができます。

  • 予測される複数の y 値。
  • 分類モデルでは、サンプルに複数の固定されていないカテゴリが含まれる場合があります。

マルチラベル ビジネスの問題の複雑さに応じて、問題は次の 2 つのカテゴリに分類できます。

  • 予測される値の間には相互依存があります。
  • 予測される値の間に依存関係はありません。

これらの問題の解決策は、次の 2 つのカテゴリに分けることができます。

  • 変換戦略 (問題の変換方法);
  • アルゴリズム適応。

ここに画像の説明を挿入
注: マルチラベルでは、各ラベルには (+1 と -1) という 2 つのカテゴリしかないと一般的に考えられています。ラベルに複数のカテゴリがある場合は、カテゴリを新しい値 +1 に分解する必要があります。または -1. ラベル。

3.1 問題変換方法

戦略変換または問題変換とも呼ばれる問題変換法は、マルチラベル分類問題を単一ラベル モデル構築問題に変換し、モデルをマージする方法です。主に次の方法があります。

  • バイナリ関連性 (一次)
  • 分類子チェーン(高次)
  • 検量ラベルランキング(二次)

3.1.1 バイナリ関連性

Binary Relevance の核となる考え方は、マルチラベル分類問題を分解し、それを q 個のバイナリ分類問題に変換することです。ここで、各バイナリ分類子は予測されるラベルに対応します。

ここに画像の説明を挿入

def Binary_Relevance(X,Y,estimator):
    '''Y是一个只有0和1的数组'''
    import numpy as np

    # 计算标签的个数
    q = Y.shape[1]
    Y_label = [i for i in range(q)]

    modles = []
    #准备K个模型的训练数据,并对y值进行处理
    for j in Y_label:
        D_j = []
        for x,y in zip(X,Y):
            D_j.append(np.hstack((x,np.array([1 if j in Y_label[y==1] else -1]))))
        new_datas = np.array(D_j)
        algo = estimator()
        g_j = algo.fit(new_datas)
        modles.append(g_j)

    # Y = Y.replace(0,-1) #把所有的0替换成-1
    # for j in Y_label:
    #     new_datas = np.hstack((X,Y[:,j].reshape(-1,1)))
    #     new_datas = np.array(new_datas)
    #     algo = estimator()
    #     g_j = algo.fit(new_datas)
    #     modles.append(g_j)

    return modles

def Binary_Relevance_predict(X,modles,label_name):
    import operator
    result = []
    for x in X:
        pre_res = []
        for g_j in modles:
            pre_res.append(g_j.predict(x))
        Y = set(np.array(label_name)[np.array(pre_res)>0]).union(label_name[pre_res.index(max(pre_res))])
        result.append(Y)
    return result

Binary Relevance 方式の利点は次のとおりです。

  • 実装方法はシンプルで理解しやすいです。
  • y 値間に関連する依存関係がない場合、モデルはうまく機能します。

欠点は次のとおりです。

  • y に相互依存関係がある場合、最終モデルの一般化能力は比較的弱いです。
  • q 個のバイナリ分類器を構築する必要があり、q は予測する y 値の数です. q が比較的大きい場合、より多くのモデルを構築する必要があります。

3.1.2 分類子チェーン

分類子チェーンの中心となるアイデアは、マルチラベル分類問題を分解し、それをバイナリ分類子のチェーンに変換することです。チェーンの後のバイナリ分類子の構築は、前の分類子の予測結果に基づいています。モデルを構築するときは、まずタグの順番をシャッフルしてから、各タグに対応するモデルを最初から最後まで構築します。

ここに画像の説明を挿入
Classifier Chains モデルの構築:
ここに画像の説明を挿入
Classifier Chains モデルの予測:
ここに画像の説明を挿入
ここに画像の説明を挿入
Classifier Chains メソッドの利点は次のとおりです。

  • 実装方法は比較的単純で理解しやすいものです。
  • ラベル間の依存関係を考慮すると、最終的なモデルの汎化能力は、Binary Relevance によって構築されたモデルの汎化能力よりも優れています。

短所は次のとおりです。 より適切なラベルの依存関係を見つけるのが難しい。

sklearn.multioutput.ClassifierChain
class sklearn.multioutput.ClassifierChain(base_estimator, order=None, cv=None, random_state=None)

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import make_multilabel_classification
from sklearn.multioutput import MultiOutputClassifier
from sklearn.svm import SVC
from sklearn.preprocessing import LabelBinarizer
from sklearn.decomposition import PCA

def plot_hyperplane(clf, min_x, max_x, linestyle, label):
    # 画图
    w = clf.coef_[0]
    a = -w[0] / w[1]
    xx = np.linspace(min_x - 5, max_x + 5)  
    yy = a * xx - (clf.intercept_[0]) / w[1]
    plt.plot(xx, yy, linestyle, label=label)

def plot_subfigure(X, Y, subplot, title):
    # 将X进行降维操作,变成两维的数据
    X = PCA(n_components=2).fit_transform(X)
    
    min_x = np.min(X[:, 0])
    max_x = np.max(X[:, 0])

    min_y = np.min(X[:, 1])
    max_y = np.max(X[:, 1])

    classif = MultiOutputClassifier(SVC(kernel='linear'))
    classif.fit(X, Y)

    plt.subplot(2, 2, subplot)
    plt.title(title)

    zero_class = np.where(Y[:, 0])
    one_class = np.where(Y[:, 1])
    plt.scatter(X[:, 0], X[:, 1], s=40, c='gray')
    plt.scatter(X[zero_class, 0], X[zero_class, 1], s=160, edgecolors='b',
               facecolors='none', linewidths=2, label='Class 1')
    plt.scatter(X[one_class, 0], X[one_class, 1], s=80, edgecolors='orange',
               facecolors='none', linewidths=2, label='Class 2')

    plot_hyperplane(classif.estimators_[0], min_x, max_x, 'r--',
                    'Boundary\nfor class 1')
    plot_hyperplane(classif.estimators_[1], min_x, max_x, 'k-.',
                    'Boundary\nfor class 2')
    plt.xticks(())
    plt.yticks(())

    plt.xlim(min_x - .5 * max_x, max_x + .5 * max_x)
    plt.ylim(min_y - .5 * max_y, max_y + .5 * max_y)
    if subplot == 1:
        plt.xlabel('First principal component')
        plt.ylabel('Second principal component')
        plt.legend(loc="upper left")

plt.figure(figsize=(8, 6))

X, Y = make_multilabel_classification(n_classes=2,
                                      allow_unlabeled=False, # 该参数控制是否有类别缺省的数据,False表示没有
                                      random_state=1)

plot_subfigure(X, Y, 1, "With unlabeled samples + CCA")


plt.subplots_adjust(.04, .02, .97, .94, .09, .2)
plt.show()
import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import make_multilabel_classification
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.preprocessing import LabelBinarizer
from sklearn.decomposition import PCA

def plot_hyperplane(clf, min_x, max_x, linestyle, label):
    # 画图
    w = clf.coef_[0]
    a = -w[0] / w[1]
    xx = np.linspace(min_x - 5, max_x + 5)  
    yy = a * xx - (clf.intercept_[0]) / w[1]
    plt.plot(xx, yy, linestyle, label=label)

def plot_subfigure(X, Y, subplot, title):
    # 将X进行降维操作,变成两维的数据
    X = PCA(n_components=2).fit_transform(X)
    min_x = np.min(X[:, 0])
    max_x = np.max(X[:, 0])

    min_y = np.min(X[:, 1])
    max_y = np.max(X[:, 1])

    classif = OneVsRestClassifier(SVC(kernel='linear'))
    classif.fit(X, Y)

    plt.subplot(2, 2, subplot)
    plt.title(title)

    zero_class = np.where(Y[:, 0])
    one_class = np.where(Y[:, 1])
    plt.scatter(X[:, 0], X[:, 1], s=40, c='gray')
    plt.scatter(X[zero_class, 0], X[zero_class, 1], s=160, edgecolors='b',
               facecolors='none', linewidths=2, label='Class 1')
    plt.scatter(X[one_class, 0], X[one_class, 1], s=80, edgecolors='orange',
               facecolors='none', linewidths=2, label='Class 2')

    plot_hyperplane(classif.estimators_[0], min_x, max_x, 'r--',
                    'Boundary\nfor class 1')
    plot_hyperplane(classif.estimators_[1], min_x, max_x, 'k-.',
                    'Boundary\nfor class 2')
    plt.xticks(())
    plt.yticks(())

    plt.xlim(min_x - .5 * max_x, max_x + .5 * max_x)
    plt.ylim(min_y - .5 * max_y, max_y + .5 * max_y)
    if subplot == 1:
        plt.xlabel('First principal component')
        plt.ylabel('Second principal component')
        plt.legend(loc="upper left")


plt.figure(figsize=(8, 6))

X, Y = make_multilabel_classification(n_classes=2, n_labels=1,
                                      allow_unlabeled=False, # 该参数控制是否有类别缺省的数据,False表示没有
                                      random_state=1)

plot_subfigure(X, Y, 1, "With unlabeled samples + CCA")


plt.subplots_adjust(.04, .02, .97, .94, .09, .2)
plt.show()

多标签分类问题(OneVsRestClassifier)

3.2 アルゴリズムの適応

Algorithm Adaptation は、アルゴリズム適応戦略とも呼ばれ、既存の単一ラベル アルゴリズムをマルチラベルに直接適用する方法で、主に次の方法があります。

k-nearest neighbor アルゴリズム (k-Nearest Neighbor、KNN) の考え方: サンプルの特徴空間 (つまり、特徴空間で最も近い距離) 内の k 個の最も類似したサンプルのほとんどが特定のカテゴリの場合、サンプルはこのカテゴリに属します。

ML-kNN の考え方: 各インスタンスについて、最初に k 個の最も近いインスタンスを取得し、次にこれらのインスタンスのラベル セットを使用して、最大事後確率 (MAP) を通じてこのインスタンスの予測ラベル セットの値を判断します。

最大事後確率 (MAP): 実際には、推定量の事前確率分布が最尤推定 (MLE) に追加されます。

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ML-DT は決定木を使用してマルチラベル コンテンツを処理します. コアは、この決定木モデルを構築するために、よりきめ細かい情報取得基準を与えることです.
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/wzk4869/article/details/128748406