Scikit-learn是否支持层次分类?多子类分类报错咨询
Scikit-learn层次分类支持及代码问题解决
Scikit-learn没有内置专门的层次分类API,但可以通过自定义编码或多阶段训练实现层次分类逻辑。
你的代码报错原因
你定义的y是3维数组(形状(number, rows, cols)),而Scikit-learn分类器要求目标变量y是1维(单标签分类)或2维(多标签/多任务分类),3维数组不符合输入要求,因此抛出ValueError。
针对你的3主类+6子类场景的解决方案
根据任务需求不同,有三种可行思路:
思路1:扁平标签编码(每个样本属于一个主类的一个子类)
将主类与子类的组合映射为唯一整数标签,把层次结构扁平化,直接用普通分类器训练。
import numpy as np from sklearn.tree import DecisionTreeClassifier X = np.random.randn(5, 1) number, main_class_count, sub_class_count = 5, 3, 6 # 生成扁平标签:主类索引*子类数 + 子类索引 y_flat = [] for _ in range(number): main = np.random.randint(main_class_count) sub = np.random.randint(sub_class_count) y_flat.append(main * sub_class_count + sub) y_flat = np.array(y_flat) # 训练与预测 clf = DecisionTreeClassifier() clf.fit(X, y_flat) # 预测后解码回层次标签 pred = clf.predict(X[0].reshape(1, -1))[0] pred_main = pred // sub_class_count pred_sub = pred % sub_class_count print(f"预测主类:{pred_main},预测子类:{pred_sub}")
思路2:多阶段分类(先分主类,再分子类)
先训练主类分类器,再针对每个主类单独训练子类分类器,实现分层预测。
import numpy as np from sklearn.tree import DecisionTreeClassifier X = np.random.randn(5, 1) number, main_class_count, sub_class_count = 5, 3, 6 # 生成主类和对应子类标签 y_main = np.random.randint(main_class_count, size=number) y_sub = np.random.randint(sub_class_count, size=number) # 第一步:训练主类分类器 main_clf = DecisionTreeClassifier() main_clf.fit(X, y_main) # 第二步:为每个主类训练子类分类器 sub_clfs = {} for main_label in range(main_class_count): # 筛选当前主类的样本 mask = y_main == main_label X_sub = X[mask] y_sub_filtered = y_sub[mask] if len(X_sub) > 0: sub_clfs[main_label] = DecisionTreeClassifier() sub_clfs[main_label].fit(X_sub, y_sub_filtered) # 分层预测函数 def predict_hierarchy(x): main_pred = main_clf.predict(x.reshape(1, -1))[0] sub_pred = sub_clfs[main_label].predict(x.reshape(1, -1))[0] if main_pred in sub_clfs else None return (main_pred, sub_pred) # 测试预测 test_x = np.random.randn(1, 1) print(predict_hierarchy(test_x))
思路3:多任务分类(每个样本需预测所有主类的子类)
如果你的任务是每个样本要同时预测3个主类各自的子类,可使用MultiOutputClassifier包装基础分类器,将3维目标转换为2维多任务标签。
import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.multioutput import MultiOutputClassifier X = np.random.randn(5, 1) number, main_class_count, sub_class_count = 5, 3, 6 # 生成原3维标签 y_3d = np.zeros((number, main_class_count, sub_class_count), dtype=int) for n in range(number): for main in range(main_class_count): sub = np.random.randint(sub_class_count) y_3d[n, main, sub] = 1 # 转换为2维多任务标签:每个主类对应一个子类索引 y_multi = np.argmax(y_3d, axis=2) # 形状(5, 3) # 训练多任务分类器 clf = MultiOutputClassifier(DecisionTreeClassifier()) clf.fit(X, y_multi) # 预测结果:每个样本对应3个主类的子类索引 preds = clf.predict(X) print("各样本的主类子类预测结果:") print(preds)
内容的提问来源于stack exchange,提问作者randomboar
相关产品推荐
相关产品推荐

