本文目录导读:

我来为你详细讲解如何使用Scikit-learn计算F1分数,包括多个实际案例。
F1分数基础
F1分数是精确率(Precision)和召回率(Recall)的调和平均数:
- F1 = 2 × (Precision × Recall) / (Precision + Recall)
基础案例:二分类问题
from sklearn.metrics import f1_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
import numpy as np
# 创建示例数据
X, y = make_classification(n_samples=1000, n_features=20,
n_classes=2, random_state=42)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 训练模型
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test)
# 计算各个指标
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
print(f"精确率 (Precision): {precision:.3f}")
print(f"召回率 (Recall): {recall:.3f}")
print(f"F1分数: {f1:.3f}")
多分类案例:F1的多种计算方式
from sklearn.metrics import classification_report
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
# 加载鸢尾花数据集(3分类)
iris = load_iris()
X, y = iris.data, iris.target
# 划分数据
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
# 训练随机森林
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# 预测
y_pred = rf.predict(X_test)
# 1. 微平均 (Micro) - 计算所有样本的总体F1
f1_micro = f1_score(y_test, y_pred, average='micro')
print(f"微平均F1: {f1_micro:.3f}")
# 2. 宏平均 (Macro) - 计算每个类别的F1然后取平均
f1_macro = f1_score(y_test, y_pred, average='macro')
print(f"宏平均F1: {f1_macro:.3f}")
# 3. 加权平均 (Weighted) - 按样本数量加权
f1_weighted = f1_score(y_test, y_pred, average='weighted')
print(f"加权平均F1: {f1_weighted:.3f}")
# 4. 每个类别的F1分数
f1_per_class = f1_score(y_test, y_pred, average=None)
for i, f1_c in enumerate(f1_per_class):
print(f"类别 {i} 的F1分数: {f1_c:.3f}")
# 5. 完整的分类报告
print("\n完整分类报告:")
print(classification_report(y_test, y_pred, target_names=iris.target_names))
实战案例:不平衡分类问题
from sklearn.metrics import f1_score, make_scorer
from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC
from imblearn.datasets import make_imbalance # 需要安装imbalanced-learn
# 创建不平衡数据集
X, y = make_classification(n_samples=1000, n_classes=2,
weights=[0.9, 0.1], # 90%负类,10%正类
random_state=42)
# 划分数据
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
print(f"训练集正类比例: {y_train.mean():.3f}")
print(f"测试集正类比例: {y_test.mean():.3f}")
# 使用不同模型比较F1分数
models = {
'逻辑回归': LogisticRegression(random_state=42),
'随机森林': RandomForestClassifier(n_estimators=100, random_state=42),
'SVM': SVC(random_state=42)
}
for name, model in models.items():
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
f1 = f1_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
print(f"\n{name}:")
print(f" 精确率: {precision:.3f}")
print(f" 召回率: {recall:.3f}")
print(f" F1分数: {f1:.3f}")
交叉验证中优化F1分数
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 创建pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC(random_state=42))
])
# 参数网格
param_grid = {
'svm__C': [0.1, 1, 10, 100],
'svm__gamma': [0.01, 0.1, 1, 10],
'svm__kernel': ['rbf', 'linear']
}
# 使用F1分数作为评分标准
f1_scorer = make_scorer(f1_score, average='weighted')
# 网格搜索
grid_search = GridSearchCV(
pipeline,
param_grid,
scoring=f1_scorer,
cv=5,
n_jobs=-1,
verbose=1
)
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证F1分数: {grid_search.best_score_:.3f}")
# 测试最佳模型
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
final_f1 = f1_score(y_test, y_pred)
print(f"测试集F1分数: {final_f1:.3f}")
可视化F1分数与阈值的关系
import matplotlib.pyplot as plt
from sklearn.metrics import precision_recall_curve
from sklearn.calibration import CalibratedClassifierCV
# 使用概率预测
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
# 获取预测概率
y_prob = model.predict_proba(X_test)[:, 1]
# 计算不同阈值下的精确率和召回率
precisions, recalls, thresholds = precision_recall_curve(y_test, y_prob)
# 计算不同阈值下的F1分数
f1_scores = 2 * (precisions[:-1] * recalls[:-1]) / (precisions[:-1] + recalls[:-1] + 1e-10)
# 找到最优阈值
best_threshold_idx = np.argmax(f1_scores)
best_threshold = thresholds[best_threshold_idx]
best_f1 = f1_scores[best_threshold_idx]
print(f"最优阈值: {best_threshold:.3f}")
print(f"最优F1分数: {best_f1:.3f}")
# 可视化
plt.figure(figsize=(10, 6))
plt.plot(thresholds, f1_scores, 'b-', label='F1 Score')
plt.axvline(x=best_threshold, color='r', linestyle='--',
label=f'Best Threshold: {best_threshold:.2f}')
plt.xlabel('Threshold')
plt.ylabel('F1 Score')'F1 Score vs Threshold')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
实用技巧总结
def evaluate_model_with_f1(y_true, y_pred, model_name="Model"):
"""
完整的模型评估函数
"""
# 计算各类F1分数
f1_micro = f1_score(y_true, y_pred, average='micro')
f1_macro = f1_score(y_true, y_pred, average='macro')
f1_weighted = f1_score(y_true, y_pred, average='weighted')
# 对于二分类,获取正类的F1
if len(np.unique(y_true)) == 2:
f1_binary = f1_score(y_true, y_pred, average='binary')
print(f"{model_name} - 二分类F1: {f1_binary:.3f}")
print(f"{model_name} - 微平均F1: {f1_micro:.3f}")
print(f"{model_name} - 宏平均F1: {f1_macro:.3f}")
print(f"{model_name} - 加权平均F1: {f1_weighted:.3f}")
return {
'micro': f1_micro,
'macro': f1_macro,
'weighted': f1_weighted
}
# 使用示例
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 1, 1, 0, 2, 2]
evaluate_model_with_f1(y_true, y_pred, "示例模型")
关键要点:
-
选择合适的average参数:
'binary': 二分类默认'micro': 适合不平衡数据'macro': 所有类别同等重要'weighted': 考虑类别分布
-
阈值优化:对于概率预测,可以调整阈值优化F1分数
-
交叉验证:使用F1作为评分标准进行模型选择
-
多分类问题:注意选择合适的average策略
这些案例覆盖了F1分数的常见使用场景,你可以根据具体需求选择合适的方法。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播