半监督SVM模型运行超时,求实现问题排查与代码修正
关于Elliptic比特币数据集半监督SVM实现的问题与修复
我正在使用Elliptic比特币数据集,测试其在监督式与半监督式模型上的性能。以下是我的监督式SVM模型代码:
classified = class_features_df[class_features_df['class'].isin(['1','2'])] X = classified.drop(columns=['txId', 'class', 'time step']) y = classified[['class']] # 将合法交易(class 2)标记为0,非法交易(class 1)标记为1 y = y['class'].apply(lambda x: 0 if x == '2' else 1 ) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=15, shuffle=False) model_svm = svm.SVC(kernel='linear') # Linear Kernel # 修正:变量名统一,用model_svm而非model,y_train而非Y_train model_svm.fit(X_train, y_train) # 计算准确率 y_pred = model_svm.predict(X_test) acc = accuracy_score(y_test, y_pred)
上述代码运行正常且结果良好,但尝试使用相同逻辑实现半监督式学习时,模型出现警告且已运行超过1小时(而监督式模型运行耗时不到1分钟),半监督代码如下:
unclassified = class_features_df[class_features_df['class'] == 3] X_unclassified = unclassified[local_features_col + agg_features_col] predictions = model_svm.predict(X_unclassified.values) # 这里会触发SettingWithCopyWarning,因为unclassified是原数据集的切片 unclassified['class'] = predictions # 合并标记数据和预测后的未标记数据 classified = classified.append(unclassified) Xtrain = classified.drop(columns=['txId', 'class', 'time step']) ytrain = classified['class'].astype('int') # 转换类型避免错误 X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(Xtrain, ytrain, test_size=0.3, random_state=15, shuffle=False) model_svm.fit(X_train_lab, y_train_lab) # 评估模型 y_pred = model_svm.predict(X_test_unlab) acc = accuracy_score(y_test_unlab, y_pred) print("Accuracy ", acc)
补充信息:类别1和2为已标记交易,类别3为未标记交易。
问题分析与代码修复
1. 核心逻辑问题:SVM不适合大规模自训练场景
你当前的实现属于自训练(Self-Training),但存在两个关键问题:
- Elliptic数据集中未标记数据(class 3)占比约90%,合并后数据集规模是原标记数据的10倍以上。SVM的训练时间复杂度为O(n²),数据量暴增会直接导致训练时间陡增。
- 直接将所有未标记数据的预测结果作为硬标签加入训练,会引入大量噪声,既降低模型精度,又进一步加重训练负担。
2. 代码中的具体错误
- 变量名不一致:监督式代码中定义了
model_svm,但调用model.fit,且Y_train/y_train大小写混乱,会直接触发报错。 - SettingWithCopyWarning:
unclassified是class_features_df的切片,直接修改unclassified['class']会触发警告,甚至导致数据未被正确修改。 - 特征不一致:监督式代码中
X是删除txId/class/time step后的列,而半监督中X_unclassified用local_features_col + agg_features_col,需确保两者特征完全一致,否则预测和训练会出错。 - 过时方法:
DataFrame.append已被弃用,应使用pd.concat。
3. 修复后的代码方案
方案一:优化自训练SVM(仅选取高置信度样本)
import pandas as pd from sklearn.svm import SVC from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 1. 预处理标记数据 classified = class_features_df[class_features_df['class'].isin(['1','2'])].copy() X_labeled = classified.drop(columns=['txId', 'class', 'time step']) y_labeled = classified['class'].apply(lambda x: 0 if x == '2' else 1).astype(int) # 2. 预处理未标记数据 unclassified = class_features_df[class_features_df['class'] == 3].copy() X_unlabeled = unclassified.drop(columns=['txId', 'class', 'time step']) # 3. 初始训练SVM(开启概率计算,用于筛选高置信度样本) model_svm = SVC(kernel='linear', probability=True) model_svm.fit(X_labeled, y_labeled) # 4. 自训练:仅选取置信度>0.9的未标记样本加入训练 probs = model_svm.predict_proba(X_unlabeled) confidence = probs.max(axis=1) high_conf_idx = confidence > 0.9 # 合并高置信度样本到标记数据集 X_combined = pd.concat([X_labeled, X_unlabeled[high_conf_idx]]) y_combined = pd.concat([y_labeled, pd.Series(model_svm.predict(X_unlabeled[high_conf_idx]), index=X_unlabeled[high_conf_idx].index)]) # 5. 划分训练测试集并训练 X_train, X_test, y_train, y_test = train_test_split(X_combined, y_combined, test_size=0.3, random_state=15, shuffle=False) model_svm.fit(X_train, y_train) # 6. 评估 y_pred = model_svm.predict(X_test) acc = accuracy_score(y_test, y_pred) print("Accuracy: ", acc)
方案二:使用sklearn专门的半监督模型(推荐)
SVM并非原生半监督模型,sklearn提供的LabelPropagation/LabelSpreading更适合这类场景:
from sklearn.semi_supervised import LabelPropagation import pandas as pd from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 1. 准备全量数据:将未标记样本的y设为-1(半监督模型要求) full_df = class_features_df.copy() full_df['label'] = full_df['class'].apply(lambda x: 1 if x == '1' else (0 if x == '2' else -1)).astype(int) X = full_df.drop(columns=['txId', 'class', 'time step', 'label']) y = full_df['label'] # 2. 划分训练测试集,过滤测试集中的未标记样本用于评估 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=15, shuffle=True) test_mask = y_test != -1 X_test_labeled = X_test[test_mask] y_test_labeled = y_test[test_mask] # 3. 训练半监督模型 model = LabelPropagation(kernel='rbf', gamma=20) model.fit(X_train, y_train) # 4. 评估 y_pred = model.predict(X_test_labeled) acc = accuracy_score(y_test_labeled, y_pred) print("Accuracy: ", acc)
内容的提问来源于stack exchange,提问作者No_Name
相关产品推荐
相关产品推荐

