神经网络系列---分类度量


文章目录

      • 分类度量
        • 混淆矩阵(Confusion Matrix):
          • 二分类问题
          • 二分类代码
          • 多分类问题
            • 多分类宏平均法:
            • 多分类代码
            • 多分类微平均法:
          • 准确率(Accuracy):
          • 精确率(Precision):
          • 召回率(Recall):
          • F1 分数(F1 Score):
          • F-Score
            • F1-Score
            • F2-Score
            • 其他F-Scores
            • 为何使用F-Score?
        • ROC 曲线(Receiver Operating Characteristic curve):
          • 二分类ROC
          • 多分类ROC
            • 宏平均
            • 微平均
        • AUC(Area Under the ROC Curve):
        • Cohen's Kappa:
        • Matthews相关系数(Matthews Correlation Coefficient,MCC):
    • 最优阈值


分类度量

以下是一些常见的分类任务中使用的度量:

混淆矩阵(Confusion Matrix):

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

    // 计算混淆矩阵 -多分类Eigen::MatrixXd calculateConfusionMatrix(const std::vector<Eigen::VectorXd>& predictions, const std::vector<Eigen::VectorXd>& targets){size_t row = predictions.at(0).size()+1;Eigen::MatrixXd confusionMat = Eigen::MatrixXd::Zero(row,row);// 获取最大值所在的索引位置int pIndex,tIndex;for (size_t i = 0; i < predictions.size(); ++i){predictions.at(i).maxCoeff(&pIndex);targets.at(i).maxCoeff(&tIndex);confusionMat(tIndex,pIndex)++;}//统计矩阵中数据放到最后一列和最后一行for (size_t i = 0; i < row-1; ++i){//累加行数据放到最后一列confusionMat(i,row-1) = confusionMat.row(i).sum();//累加列数据放到最后一行confusionMat(row-1,i) = confusionMat.col(i).sum();}//最后一个数据confusionMat(row-1,row-1) = confusionMat.col(row-1).sum();return confusionMat;}

混淆矩阵是用于描述分类模型性能的表格,包括真正例、假正例、真负例和假负例的数量。
混淆矩阵(Confusion Matrix),也称为误差矩阵(Error Matrix),是用于衡量分类模型性能的一种矩阵形式的工具,特别适用于二分类问题。

二分类问题

混淆矩阵是一个2x2矩阵,其中每一行代表了真实的类别,每一列代表了模型的预测类别。它将预测结果与真实标签之间的四种不同情况进行了分类,包括真正类(True Positive,TP)、真负类(True Negative,TN)、假正类(False Positive,FP)和假负类(False Negative,FN)。

混淆矩阵(Confusion Matrix)中的四个元素用符号表示如下:

  • TP(True Positive):正类别样本中,模型预测正确为正类别的样本数。
  • TN(True Negative):负类别样本中,模型预测正确为负类别的样本数。
  • FP(False Positive):负类别样本中,模型错误地预测为正类别的样本数。
  • FN(False Negative):正类别样本中,模型错误地预测为负类别的样本数。

混淆矩阵的一般形式如下:

|             | 预测为正类别 | 预测为负类别 |
|-------------|--------------|--------------|
| 真实为正类别 |     TP       |     FN       |
| 真实为负类别 |     FP       |     TN       |

通过混淆矩阵,我们可以计算出一系列分类模型的性能指标,如下所示:

  • 精确率(Precision):用于衡量在所有被预测为正类别的样本中,有多少是真正的正类别。
    公式: P r e c i s i o n = T P / ( T P + F P ) Precision = TP / (TP + FP) Precision=TP/(TP+FP)

  • 召回率(Recall):用于衡量在所有真实为正类别的样本中,有多少被正确预测为正类别。
    公式: R e c a l l = T P / ( T P + F N ) Recall = TP / (TP + FN) Recall=TP/(TP+FN)

  • F1分数(F1 Score):精确率和召回率的调和平均数,综合了两者的性能。
    公式: F 1 S c o r e = 2 ∗ ( P r e c i s i o n ∗ R e c a l l ) / ( P r e c i s i o n + R e c a l l ) F1 Score = 2 * (Precision * Recall) / (Precision + Recall) F1Score=2(PrecisionRecall)/(Precision+Recall)

  • 准确率(Accuracy):用于衡量模型在所有样本中正确预测的比例。
    公式: A c c u r a c y = ( T P + T N ) / ( T P + T N + F P + F N ) Accuracy = (TP + TN) / (TP + TN + FP + FN) Accuracy=(TP+TN)/(TP+TN+FP+FN)

这些指标可以帮助我们全面评估分类模型的性能,并更好地理解模型在不同类别下的预测表现。

二分类代码

以下是用C++编写的一个简单示例代码,用于计算混淆矩阵的四个元素(TP、TN、FP、FN)和计算精确率(Precision)、召回率(Recall)、F1分数(F1 Score)和准确率(Accuracy):

#include <iostream>
#include <vector>// 计算混淆矩阵的四个元素(TP、TN、FP、FN)
void calculateConfusionMatrix(const std::vector<int>& predictions, const std::vector<int>& targets,int& TP, int& TN, int& FP, int& FN) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return;}TP = TN = FP = FN = 0;for (size_t i = 0; i < predictions.size(); ++i) {if (predictions[i] == 1) {if (targets[i] == 1) {TP++;} else {FP++;}} else {if (targets[i] == 0) {TN++;} else {FN++;}}}
}// 计算精确率(Precision)
double calculatePrecision(int TP, int FP) {if (TP + FP == 0) {return 0.0;}return static_cast<double>(TP) / (TP + FP);
}// 计算召回率(Recall)
double calculateRecall(int TP, int FN) {if (TP + FN == 0) {return 0.0;}return static_cast<double>(TP) / (TP + FN);
}// 计算F1分数(F1 Score)
double calculateF1Score(double precision, double recall) {if (precision == 0.0 || recall == 0.0) {return 0.0;}return 2 * (precision * recall) / (precision + recall);
}// 计算准确率(Accuracy)
double calculateAccuracy(int TP, int TN, int FP, int FN) {int totalSamples = TP + TN + FP + FN;if (totalSamples == 0) {return 0.0;}return static_cast<double>(TP + TN) / totalSamples;
}int main() {// 假设有10个样本的预测值和真实值std::vector<int> predictions = {1, 0, 1, 1, 0, 1, 0, 0, 1, 1};std::vector<int> targets = {1, 0, 0, 1, 0, 1, 1, 0, 1, 1};int TP, TN, FP, FN;// 计算混淆矩阵的四个元素calculateConfusionMatrix(predictions, targets, TP, TN, FP, FN);// 计算精确率(Precision)double precision = calculatePrecision(TP, FP);// 计算召回率(Recall)double recall = calculateRecall(TP, FN);// 计算F1分数(F1 Score)double f1Score = calculateF1Score(precision, recall);// 计算准确率(Accuracy)double accuracy = calculateAccuracy(TP, TN, FP, FN);std::cout << "混淆矩阵:" << std::endl;std::cout << "| " << TP << " | " << FN << " |" << std::endl;std::cout << "| " << FP << " | " << TN << " |" << std::endl;std::cout << "精确率(Precision)为: " << precision << std::endl;std::cout << "召回率(Recall)为: " << recall << std::endl;std::cout << "F1分数(F1 Score)为: " << f1Score << std::endl;std::cout << "准确率(Accuracy)为: " << accuracy << std::endl;return 0;
}
多分类问题
多分类宏平均法:
|             | 预测为正类别 | 预测为负类别 |
|-------------|--------------|--------------|
| 真实为正类别 |     TP       |     FN       |
| 真实为负类别 |     FP       |     TN       |
                | 预测为类别 1 | 预测为类别 2 | 预测为类别 3 | 预测为类别 4 |
----------------------------------------------------------------
真实为类别 1   |     TP_1    |     FP_1    |     FP_1'   |     FP_1''  |
真实为类别 2   |     FP_2    |     TP_2    |     FP_2'   |     FP_2''  |
真实为类别 3   |     FP_3    |     FP_3'   |     TP_3    |     FP_3''  |
真实为类别 4   |     FP_4    |     FP_4'   |     FP_4''  |     TP_4    |
  1. 宏平均精确率(Precision):
    宏平均精确率是计算每个类别的精确率,并对它们取算术平均。它衡量了分类器在每个类别上的平均分类精确率。

Macro-Precision = 1 N ∑ i = 1 N TP i TP i + FP i \text{Macro-Precision} = \frac{1}{N} \sum_{i=1}^{N} \frac{\text{TP}_i}{\text{TP}_i + \text{FP}_i} Macro-Precision=N1i=1NTPi+FPiTPi

其中,N是类别的总数, TP i \text{TP}_i TPi是第i个类别的真正例数, FP i \text{FP}_i FPi是第i个类别的假正例数。

  1. 宏平均召回率(Macro-Recall):
    宏平均召回率是计算每个类别的召回率,并对它们取算术平均。它衡量了分类器在每个类别上的平均分类召回率。

Macro-Recall = 1 N ∑ i = 1 N TP i TP i + FN i \text{Macro-Recall} = \frac{1}{N} \sum_{i=1}^{N} \frac{\text{TP}_i}{\text{TP}_i + \text{FN}_i} Macro-Recall=N1i=1NTPi+FNiTPi

其中, FN i \text{FN}_i FNi是第i个类别的假反例数。

  1. 宏平均F1分数(Macro-F1):
    宏平均F1分数是计算每个类别的F1分数,并对它们取算术平均。F1分数是准确率和召回率的调和平均,用于综合衡量分类器在精确性和召回性能之间的平衡。

Macro-F1 = 1 N ∑ i = 1 N 2 × TP i 2 × TP i + FP i + FN i \text{Macro-F1} = \frac{1}{N} \sum_{i=1}^{N} \frac{2 \times \text{TP}_i}{2 \times \text{TP}_i + \text{FP}_i + \text{FN}_i} Macro-F1=N1i=1N2×TPi+FPi+FNi2×TPi

4.准确率(Accuracy):用于衡量模型在所有样本中正确预测的比例。
Accuracy = 正确分类的样本数 总样本数 \text{Accuracy} = \frac{\text{正确分类的样本数}}{\text{总样本数}} Accuracy=总样本数正确分类的样本数


//微平均  按照上述公式,所有结果 = tp  / 总样本  ,也就是准确率// 计算准确率(Accuracy)-多分类double calculateAccuracy(const Eigen::MatrixXd& confusionMat){size_t numClass = confusionMat.rows()-1;size_t totalSamples = (size_t)confusionMat(numClass,numClass);if (confusionMat(numClass,numClass) == 0){return 0.0;}double accuracy = 0;//累加所有正确类别个数for (size_t i = 0; i < numClass; ++i){accuracy += confusionMat(i,i);}return accuracy / totalSamples;}
多分类代码
// 计算混淆矩阵 -多分类Eigen::MatrixXd calculateConfusionMatrix(const std::vector<Eigen::VectorXd>& predictions, const std::vector<Eigen::VectorXd>& targets){size_t row = predictions.at(0).size()+1;Eigen::MatrixXd confusionMat = Eigen::MatrixXd::Zero(row,row);// 获取最大值所在的索引位置int pIndex,tIndex;for (size_t i = 0; i < predictions.size(); ++i){predictions.at(i).maxCoeff(&pIndex);targets.at(i).maxCoeff(&tIndex);confusionMat(tIndex,pIndex)++;}//统计矩阵中数据放到最后一列和最后一行for (size_t i = 0; i < row-1; ++i){//累加行数据放到最后一列confusionMat(i,row-1) = confusionMat.row(i).sum();//累加列数据放到最后一行confusionMat(row-1,i) = confusionMat.col(i).sum();}//最后一个数据confusionMat(row-1,row-1) = confusionMat.col(row-1).sum();return confusionMat;}// 宏平均精确率(Precision)-多分类double calculatePrecision(const Eigen::MatrixXd& confusionMat){size_t numClass = confusionMat.rows()-1;Eigen::VectorXd classV(numClass);for (size_t i = 0; i < numClass; ++i){if(confusionMat(numClass,i) == 0){classV(i) = 0;}else{classV(i) = confusionMat(i,i) / confusionMat(numClass,i);}}//所有类累加后的平均值return classV.sum() / numClass;}// 宏平均召回率(Recall)-多分类double calculateRecall(const Eigen::MatrixXd& confusionMat){size_t numClass = confusionMat.rows()-1;Eigen::VectorXd classV(numClass);for (size_t i = 0; i < numClass; ++i){if(confusionMat(i,numClass) == 0){classV(i) = 0;}else{classV(i) = confusionMat(i,i) / confusionMat(i,numClass);}}//所有类累加后的平均值return classV.sum() / numClass;}// 宏平均F1分数(F1 Score)-多分类double calculateF1Score(const Eigen::MatrixXd& confusionMat){size_t numClass = confusionMat.rows()-1;Eigen::VectorXd classV(numClass);for (size_t i = 0; i < numClass; ++i){if(confusionMat(i,numClass) == 0 || confusionMat(numClass,i) == 0){classV(i) = 0;}else{classV(i) = 2 * confusionMat(i,i) / (confusionMat(numClass,i) + confusionMat(i,numClass));}}//所有类累加后的平均值return classV.sum() / numClass;}// 计算准确率(Accuracy)-多分类double calculateAccuracy(const Eigen::MatrixXd& confusionMat){size_t numClass = confusionMat.rows()-1;size_t totalSamples = (size_t)confusionMat(numClass,numClass);if (confusionMat(numClass,numClass) == 0){return 0.0;}double accuracy = 0;//累加所有正确类别个数for (size_t i = 0; i < numClass; ++i){accuracy += confusionMat(i,i);}return accuracy / totalSamples;}
多分类微平均法:

多分类微平均法是一种用于多类别分类任务性能评估的指标汇总方法,它将所有类别的预测结果汇总成一个二分类问题,并计算总体性能指标。与宏平均法不同,多分类微平均法将每个样本都视为同等重要,不考虑类别本身,因此适用于类别样本数量相对均衡的情况。

在多分类微平均法中,我们通常会关注以下性能指标:

  1. 总体精确率(Micro-Precision):
    Micro-Precision = TP total TP total + FP total \text{Micro-Precision} = \frac{\text{TP}_{\text{total}}}{\text{TP}_{\text{total}} + \text{FP}_{\text{total}}} Micro-Precision=TPtotal+FPtotalTPtotal

  2. 总体召回率(Micro-Recall):
    Micro-Recall = TP total TP total + FN total \text{Micro-Recall} = \frac{\text{TP}_{\text{total}}}{\text{TP}_{\text{total}} + \text{FN}_{\text{total}}} Micro-Recall=TPtotal+FNtotalTPtotal

  3. 总体F1分数(Micro-F1):
    Micro-F1 = 2 × TP total 2 × TP total + FP total + FN total \text{Micro-F1} = \frac{2 \times \text{TP}_{\text{total}}}{2 \times \text{TP}_{\text{total}} + \text{FP}_{\text{total}} + \text{FN}_{\text{total}}} Micro-F1=2×TPtotal+FPtotal+FNtotal2×TPtotal

4.准确率(Accuracy):用于衡量模型在所有样本中正确预测的比例。
Accuracy = 正确分类的样本数 总样本数 \text{Accuracy} = \frac{\text{正确分类的样本数}}{\text{总样本数}} Accuracy=总样本数正确分类的样本数

准确率(Accuracy):

准确率是最常见的分类度量之一,它简单地表示模型预测正确的样本数量与总样本数量之间的比例。
准确率的取值范围在 0 到 1 之间,数值越接近 1 表示模型预测越准确,数值越接近 0 表示模型预测越不准确。

数学上,准确率的计算方法如下:

假设有 n 个样本,模型的预测结果分别为 y ^ 1 , y ^ 2 , . . . , y ^ n ŷ₁, ŷ₂, ..., ŷₙ y^1,y^2,...,y^n,对应的真实标签为 y 1 , y 2 , . . . , y n y₁, y₂, ..., yₙ y1,y2,...,yn

准确率 = ( 正确分类的样本数量 ) / ( 总样本数量 ) = ( 正确分类的样本数量 ) / n = Σ ( y ^ i = = y i ) / n 准确率 = (正确分类的样本数量) / (总样本数量) = (正确分类的样本数量) / n = Σ (ŷᵢ == yᵢ) / n 准确率=(正确分类的样本数量)/(总样本数量)=(正确分类的样本数量)/n=Σ(y^i==yi)/n

其中, ( y ^ i = = y i ) (ŷᵢ == yᵢ) (y^i==yi) 表示第 i 个样本是否被正确分类,如果预测值 ŷᵢ 等于真实标签 yᵢ,则表示第 i 个样本被正确分类。

需要注意的是,准确率可能并不适用于所有情况。在某些不平衡的分类问题中,如果某个类别的样本数量较少,模型可能会倾向于预测样本属于数量较多的类别,从而导致准确率的误导。在这种情况下,可能需要结合其他评估指标来综合评估模型的性能。
下面是用C++编写的一个简单示例代码,用于计算分类模型的准确率(Accuracy):

#include <iostream>
#include <vector>// 计算准确率(Accuracy)
double calculateAccuracy(const std::vector<int>& predictions, const std::vector<int>& targets) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return -1.0;}int correctCount = 0;for (size_t i = 0; i < predictions.size(); ++i) {if (predictions[i] == targets[i]) {correctCount++;}}double accuracy = static_cast<double>(correctCount) / predictions.size();return accuracy;
}
精确率(Precision):

精确率是指在所有被模型预测为正例的样本中,真正例的比例。它用于衡量模型预测为正例的准确性。
精确率的取值范围在 0 到 1 之间,数值越接近 1 表示模型在预测正类别时更准确,数值越接近 0 表示模型在预测正类别时不太准确。

数学上,精确率的计算方法如下:

假设有 n 个样本,模型的预测结果分别为 y ^ 1 , y ^ 2 , . . . , y ^ n ŷ₁, ŷ₂, ..., ŷₙ y^1,y^2,...,y^n,对应的真实标签为 y 1 , y 2 , . . . , y n y₁, y₂, ..., yₙ y1,y2,...,yn

精确率 = ( 真正为正类别的样本数量 ) / ( 所有被预测为正类别的样本数量 ) = ( 真正为正类别的样本数量 ) / Σ ( y ^ i = = 1 ) 精确率 = (真正为正类别的样本数量) / (所有被预测为正类别的样本数量) = (真正为正类别的样本数量) / Σ (ŷᵢ == 1) 精确率=(真正为正类别的样本数量)/(所有被预测为正类别的样本数量)=(真正为正类别的样本数量)(y^i==1)

其中, ( y ^ i = = 1 ) (ŷᵢ == 1) (y^i==1) 表示第 i 个样本被模型预测为正类别。

精确率通常与召回率(Recall)一起使用,可以帮助我们全面评估分类模型的性能。高精确率意味着模型预测正类别时较少出现误判,而高召回率意味着模型对正类别的覆盖率较高。在实际应用中,需要根据具体任务和需求来选择精确率和召回率的权衡。

下面是用C++编写的一个简单示例代码,用于计算分类模型的精确率(Precision):

#include <iostream>
#include <vector>// 计算精确率(Precision)
double calculatePrecision(const std::vector<int>& predictions, const std::vector<int>& targets) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return -1.0;}int truePositive = 0; // 真正为正类别的样本数量int predictedPositive = 0; // 所有被预测为正类别的样本数量for (size_t i = 0; i < predictions.size(); ++i) {if (predictions[i] == 1) {predictedPositive++;if (targets[i] == 1) {truePositive++;}}}double precision = static_cast<double>(truePositive) / predictedPositive;return precision;
}
召回率(Recall):

召回率是指在所有真正正例中,模型正确预测为正例的比例。它用于衡量模型对正例的覆盖程度。
召回率的取值范围在 0 到 1 之间,数值越接近 1 表示模型对真实正类别的覆盖率较高,数值越接近 0 表示模型对真实正类别的覆盖率较低。

数学上,召回率的计算方法如下:

假设有 n 个样本,模型的预测结果分别为 y ^ 1 , y ^ 2 , . . . , y ^ n ŷ₁, ŷ₂, ..., ŷₙ y^1,y^2,...,y^n,对应的真实标签为 y 1 , y 2 , . . . , y n y₁, y₂, ..., yₙ y1,y2,...,yn

召回率 = ( 真正为正类别的样本数量 ) / ( 所有真实为正类别的样本数量 ) = ( 真正为正类别的样本数量 ) / Σ ( y i = = 1 ) 召回率 = (真正为正类别的样本数量) / (所有真实为正类别的样本数量) = (真正为正类别的样本数量) / Σ (yᵢ == 1) 召回率=(真正为正类别的样本数量)/(所有真实为正类别的样本数量)=(真正为正类别的样本数量)(yi==1)

其中, ( y i = = 1 ) (yᵢ == 1) (yi==1) 表示第 i 个样本是真实为正类别的。

精确率(Precision)和召回率(Recall)通常一起使用,可以帮助我们全面评估分类模型的性能。高精确率意味着模型预测正类别时较少出现误判,而高召回率意味着模型对正类别的覆盖率较高。在实际应用中,需要根据具体任务和需求来选择精确率和召回率的权衡。

下面是用C++编写的一个简单示例代码,用于计算分类模型的召回率(Recall):

#include <iostream>
#include <vector>// 计算召回率(Recall)
double calculateRecall(const std::vector<int>& predictions, const std::vector<int>& targets) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return -1.0;}int truePositive = 0; // 真正为正类别的样本数量int actualPositive = 0; // 所有真实为正类别的样本数量for (size_t i = 0; i < predictions.size(); ++i) {if (targets[i] == 1) {actualPositive++;if (predictions[i] == 1) {truePositive++;}}}double recall = static_cast<double>(truePositive) / actualPositive;return recall;
}
F1 分数(F1 Score):

F1 分数是精确率和召回率的调和平均值,它综合了两者的性能。F1 分数更加平衡精确率和召回率的影响。
F1分数的取值范围在0到1之间,数值越接近1表示模型在预测时具有较高的准确性和召回率,数值越接近0表示模型的预测准确性和召回率较低。
F1分数的计算方法如下:

假设有 n 个样本,模型的预测结果分别为 y ^ 1 , y ^ 2 , . . . , y ^ n ŷ₁, ŷ₂, ..., ŷₙ y^1,y^2,...,y^n,对应的真实标签为 y 1 , y 2 , . . . , y n y₁, y₂, ..., yₙ y1,y2,...,yn

精确率(Precision)的计算方法为:
P r e c i s i o n = ( 真正为正类别的样本数量 ) / ( 所有被预测为正类别的样本数量 ) = ( 真正为正类别的样本数量 ) / Σ ( y ^ i = = 1 ) Precision = (真正为正类别的样本数量) / (所有被预测为正类别的样本数量) = (真正为正类别的样本数量) / Σ (ŷᵢ == 1) Precision=(真正为正类别的样本数量)/(所有被预测为正类别的样本数量)=(真正为正类别的样本数量)(y^i==1)

召回率(Recall)的计算方法为:
R e c a l l = ( 真正为正类别的样本数量 ) / ( 所有真实为正类别的样本数量 ) = ( 真正为正类别的样本数量 ) / Σ ( y i = = 1 ) Recall = (真正为正类别的样本数量) / (所有真实为正类别的样本数量) = (真正为正类别的样本数量) / Σ (yᵢ == 1) Recall=(真正为正类别的样本数量)/(所有真实为正类别的样本数量)=(真正为正类别的样本数量)(yi==1)

F1分数的计算方法为:
F 1 S c o r e = 2 ∗ ( P r e c i s i o n ∗ R e c a l l ) / ( P r e c i s i o n + R e c a l l ) F1 Score = 2 * (Precision * Recall) / (Precision + Recall) F1Score=2(PrecisionRecall)/(Precision+Recall)

F1分数是综合了精确率和召回率的评估指标,适用于处理类别不平衡的情况,因为它考虑了正类别和负类别的权衡。在某些情况下,我们更关注模型在正类别的预测准确性和召回率,此时F1分数是一个很有用的指标。

下面是用C++编写的一个简单示例代码,用于计算分类模型的F1分数(F1 Score):

#include <iostream>
#include <vector>// 计算精确率(Precision)
double calculatePrecision(const std::vector<int>& predictions, const std::vector<int>& targets) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return -1.0;}int truePositive = 0; // 真正为正类别的样本数量int predictedPositive = 0; // 所有被预测为正类别的样本数量for (size_t i = 0; i < predictions.size(); ++i) {if (predictions[i] == 1) {predictedPositive++;if (targets[i] == 1) {truePositive++;}}}double precision = static_cast<double>(truePositive) / predictedPositive;return precision;
}// 计算召回率(Recall)
double calculateRecall(const std::vector<int>& predictions, const std::vector<int>& targets) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return -1.0;}int truePositive = 0; // 真正为正类别的样本数量int actualPositive = 0; // 所有真实为正类别的样本数量for (size_t i = 0; i < predictions.size(); ++i) {if (targets[i] == 1) {actualPositive++;if (predictions[i] == 1) {truePositive++;}}}double recall = static_cast<double>(truePositive) / actualPositive;return recall;
}// 计算F1分数(F1 Score)
double calculateF1Score(double precision, double recall) {if (precision == 0.0 || recall == 0.0) {return 0.0;}double f1Score = 2 * (precision * recall) / (precision + recall);return f1Score;
}
F-Score

F-Score(也称为F-值)是一种用于评估分类模型准确性的度量。特别地,它是精确度(Precision)和召回率(Recall)的加权平均值。在深度学习和其他分类任务中,F-Score是一种常用的评估指标。

F-Score的一般公式如下:

F β = ( 1 + β 2 ) ⋅ Precision ⋅ Recall β 2 ⋅ Precision + Recall F_{\beta} = \frac{(1 + \beta^2) \cdot \text{Precision} \cdot \text{Recall}}{\beta^2 \cdot \text{Precision} + \text{Recall}} Fβ=β2Precision+Recall(1+β2)PrecisionRecall

其中:

  • Precision(精确度)是模型预测为正的样本中实际为正的样本的比例。
  • Recall(召回率)是实际为正的样本中模型预测为正的样本的比例。
  • β \beta β是一个权重因子,用于在精确度和召回率之间取平衡。特别地, β \beta β的值决定了你是更重视召回率还是精确度。
F1-Score

β = 1 \beta = 1 β=1时,精确度和召回率被赋予相同的权重,这就是F1-Score。F1-Score是最常用的F-Score,计算公式为:

F 1 = 2 ⋅ Precision ⋅ Recall Precision + Recall F1 = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}} F1=Precision+Recall2PrecisionRecall

F2-Score

F2-Score给予召回率更高的权重,是一种特殊情况,其中 β = 2 \beta = 2 β=2。F2-Score适用于召回率比精确度更重要的场景。计算公式为:

F 2 = 5 ⋅ Precision ⋅ Recall 4 ⋅ Precision + Recall F2 = \frac{5 \cdot \text{Precision} \cdot \text{Recall}}{4 \cdot \text{Precision} + \text{Recall}} F2=4Precision+Recall5PrecisionRecall

其他F-Scores

你可以通过调整 β \beta β的值来得到不同的F-Scores。具体来说,增加 β \beta β的值会增加召回率的权重,而减小 β \beta β的值会增加精确度的权重。

为何使用F-Score?

F-Score是一个有用的度量标准,特别是当数据集的类别分布不平衡时。在这些情况下,简单的准确度可能不是一个好的度量标准,因为它可能会被主导类别所掩盖。通过结合精确度和召回率,F-Score提供了一种平衡的方法来评估模型在各个类别上的性能。

ROC 曲线(Receiver Operating Characteristic curve):
二分类ROC

在ROC曲线中,横轴表示FPR,纵轴表示TPR。TPR是召回率(Recall)的另一个名称,它表示在所有真实为正类别的样本中,模型正确预测为正类别的样本所占的比例。FPR表示在所有真实为负类别的样本中,模型错误地预测为正类别的样本所占的比例。

ROC曲线的绘制过程如下:

  1. 首先,根据模型预测的概率值对样本进行排序,从高到低排列。
  2. 选择一个阈值,将概率大于等于该阈值的样本预测为正类别,将概率小于该阈值的样本预测为负类别。
  3. 计算在当前阈值下的TPR和FPR。
  4. 不断地调整阈值,重复步骤3,直到所有样本都被预测为正类别或负类别。
  5. 将所有不同阈值下的TPR和FPR绘制成ROC曲线。

在ROC曲线中,理想的分类器的曲线将沿着左上角到右下角的对角线,这表示在所有阈值下,分类器的TPR和FPR均为1。而对角线以下的曲线则表示分类器的性能较差。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码实现

     // 计算TPR(True Positive Rate,召回率)inline float calculateTPR(const int& TP, const int& FN){float f = (float)TP / (TP + FN);//保留小数点后5位int p = 100000;return static_cast<float>(static_cast<int>(f * p + 0.5) / (float)p);}// 计算FPR(False Positive Rate)inline float calculateFPR(const int& FP, const int& TN){float f = (float)FP / (FP + TN);//保留小数点后5位int p = 100000;return static_cast<float>(static_cast<int>(f * p + 0.5) / (float)p);}//从小到大排序 并去重std::vector<float> sortAndRemoveDuplicates(const std::vector<float>& input){std::vector<float> sortedVector = input;// 先排序std::sort(sortedVector.begin(), sortedVector.end());// 然后使用 std::unique 去重sortedVector.erase(std::unique(sortedVector.begin(), sortedVector.end()), sortedVector.end());return sortedVector;}// 绘制ROC曲线 - 二分类 返回一组坐标virtual std::vector<std::pair<float,float> > calculateBinaryROC(const Eigen::VectorXf& predictions, const Eigen::VectorXf& targets){//数据映射到vectorstd::vector<float> preProb(predictions.data(), predictions.data() + predictions.size());preProb.push_back(0.0);preProb.push_back(1.0);preProb = sortAndRemoveDuplicates(preProb);std::vector<std::pair<float,float> > points;// 遍历样本,计算TPR和FPRfor (int i = 0; i < preProb.size(); ++i){int TP = 0;int FP = 0;int FN = 0;int TN = 0;for (int j = 0; j < predictions.rows(); ++j){//划分概率样本 为正if (predictions(j) - preProb.at(i) >= 0){if ((int)targets(j) == 1){TP++;}else{FP++;}}else //为负{if ((int)targets(j) == 1){FN++;}else{TN++;}}}std::pair<float,float> temp;//TPR和FPRtemp.first = (calculateFPR(FP, TN));//FPRtemp.second = (calculateTPR(TP, FN));//TPRpoints.push_back(temp);}points.push_back({0.0, 0.0});points.push_back({1.0, 1.0});//排序 -- 根据键值std::sort(points.begin(), points.end(), [=](const auto& lhs, const auto& rhs){// 首先比较键,如果键相等则比较值if (lhs.first == rhs.first){return lhs.second - rhs.second < 0.0;}return lhs.first - rhs.first < 0.0;   // 从小到大 排序});// 去除相邻的重复元素points.erase(std::unique(points.begin(), points.end(), [](const auto& a, const auto& b) {return a.first == b.first && a.second == b.second;}), points.end());//        //检测排序 是否 从小到大
//        for(int i=1;i<points.size();++i)
//        {
//            CHECK(points.at(i-1).first <= points.at(i).first && points.at(i-1).second <= points.at(i).second);
//        }return points;}
多分类ROC
宏平均多个分类->转多个二分类求平均值(多对多)
微平均多个分类->转一个二分类(多对一)
宏平均

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

代码实现

    // 宏平均绘制ROC曲线 - 多分类 返回一组坐标virtual std::vector<std::pair<float,float> >  calculateMacroROC(const Eigen::MatrixXf& predictions, const Eigen::MatrixXf& targets){std::vector<std::vector<std::pair<float,float>>> MacroROC;std::vector<float> allFPR;//拆分成二分类绘制ROC曲线for (int i = 0; i < predictions.cols(); ++i){std::vector<std::pair<float,float>>  binaryROC = calculateBinaryROC(predictions.col(i), targets.col(i));MacroROC.push_back(binaryROC);//找出所有FPRfor (int j = 0; j < binaryROC.size(); ++j){allFPR.push_back(binaryROC.at(j).first);}}allFPR = sortAndRemoveDuplicates(allFPR);//求宏平均ROCstd::vector<std::pair<float,float>> points;Eigen::VectorXi indexPos = Eigen::VectorXi::Ones(MacroROC.size());for (int i = 0; i < allFPR.size(); ++i){float argY = 0.0;for (int j = 0; j < MacroROC.size(); ++j){std::vector<std::pair<float,float>> binaryROC = MacroROC.at(j);for (int k = indexPos(j); k < binaryROC.size(); ++k){indexPos(j) = k;//求线性插值 (y2-y1) / (x2 - x1) * (x-x1) + y1 = y     x=allFPR.at(i)if (binaryROC.at(k).first > allFPR.at(i)){//找到最后一个的等于值,取x相同的y最大值if(binaryROC.at(k-1).first == allFPR.at(i)){argY += binaryROC.at(k-1).second;}else{argY += (binaryROC.at(k).second - binaryROC.at(k - 1).second) / (binaryROC.at(k).first - binaryROC.at(k - 1).first) *(allFPR.at(i) - binaryROC.at(k - 1).first) + binaryROC.at(k - 1).second;}break;}}}std::pair<float,float> temp;temp.first = (allFPR.at(i));temp.second = (argY / MacroROC.size());points.push_back(temp);}return points;}
微平均

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

代码实现

// 微平均绘制ROC曲线 - 多分类 返回一组坐标std::vector<std::pair<float,float>> calculateMicroROC(const Eigen::MatrixXf& predictions,const Eigen::MatrixXf& targets){//改变维度 - 以行为准则,改变为一维的向量Eigen::VectorXf pred = predictions.reshaped<Eigen::RowMajor>().transpose();Eigen::VectorXf targ = targets.reshaped<Eigen::RowMajor>().transpose();return calculateBinaryROC(pred, targ);}
AUC(Area Under the ROC Curve):

AUC 是 ROC 曲线下的面积,用来衡量模型在不同阈值下分类性能的综合表现。
AUC(Area Under the ROC Curve)是用于衡量分类模型性能的重要指标之一,它表示ROC曲线下的面积,即ROC曲线与坐标轴之间的面积。

在ROC曲线中,横轴表示FPR(False Positive Rate),纵轴表示TPR(True Positive Rate,召回率)。

AUC表示ROC曲线下的面积,其取值范围在0.5到1之间。对于完美的分类器,AUC为1,表示模型在所有阈值下都能完美地将正类别和负类别样本分开。而AUC为0.5表示模型的分类性能等同于随机预测,即ROC曲线为对角线。

AUC值的含义如下:

  • AUC = 1:完美分类器,模型的分类性能非常好。
  • AUC > 0.5:优于随机预测,模型具有良好的分类性能。
  • AUC = 0.5:等于随机预测,模型的分类性能不好,相当于乱猜。
  • AUC < 0.5:差于随机预测,模型的分类性能更差,相当于反向分类。

AUC是一个非常重要的指标,特别适用于处理类别不平衡的情况。它可以帮助我们全面评估分类模型的性能,同时不受分类阈值的影响。在实际应用中,通常更高的AUC值表示模型的分类性能更好。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

 // 根据ROC曲线计算AUC - 返回面积float calculatemAUC(const std::vector<std::pair<float,float>>& points){//梯形面积累加   数据中必须从x=0开始,到1结束,否则缺少面积float auc = 0.0;for (int i = 1; i < points.size(); ++i){float x1 = points[i - 1].first;float x2 = points[i].first;float y1 = points[i - 1].second;float y2 = points[i].second;float value = ((x2 - x1) * (y1 + y2) / 2.0);auc += value;}return auc;}
Cohen’s Kappa:

Cohen’s Kappa 是用于衡量分类器与随机分类器之间一致性的指标。它考虑了分类器的准确率与随机分类之间的差异。
Cohen’s Kappa(科恩的Kappa)是一种用于衡量分类模型在多类别分类问题中的一致性的统计量。它考虑了模型的预测结果与真实标签之间的一致性,同时考虑了由于随机预测导致的准确性。

Cohen’s Kappa的取值范围在-1到1之间,具体解释如下:

  • Kappa = 1:表示模型的预测与真实标签完全一致,没有误差。
  • Kappa > 0:表示模型的预测优于随机预测,具有一定的分类一致性。
  • Kappa = 0:表示模型的预测与随机预测一致性相同,即模型的预测没有优于随机预测。
  • Kappa < 0:表示模型的预测差于随机预测,可能存在较大的误差。

计算Cohen’s Kappa的公式如下:

    Kappa = (Po - Pe) / (1 - Pe)

其中,Po是观测到的分类一致性,Pe是随机分类的预期一致性。

在计算Cohen’s Kappa时,首先需要计算混淆矩阵的四个元素(TP、TN、FP、FN),然后计算分类准确率(Overall Accuracy)和每个类别的预测准确率(Per Class Accuracy),最终计算Cohen’s Kappa。

Cohen’s Kappa是一个重要的评估指标,特别适用于多类别分类问题,它考虑了模型的分类一致性和随机预测之间的差异,使得其评估更加全面。

以下是用C++编写的一个简单示例代码,用于计算Cohen’s Kappa(科恩的Kappa):

#include <iostream>
#include <vector>// 计算混淆矩阵的四个元素(TP、TN、FP、FN)
void calculateConfusionMatrix(const std::vector<int>& predictions, const std::vector<int>& targets,int& TP, int& TN, int& FP, int& FN) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return;}TP = TN = FP = FN = 0;for (size_t i = 0; i < predictions.size(); ++i) {if (predictions[i] == 1) {if (targets[i] == 1) {TP++;} else {FP++;}} else {if (targets[i] == 0) {TN++;} else {FN++;}}}
}// 计算Cohen's Kappa
double calculateCohensKappa(int TP, int TN, int FP, int FN) {int totalSamples = TP + TN + FP + FN;if (totalSamples == 0) {std::cerr << "样本数量不能为0" << std::endl;return 0.0;}double Po = static_cast<double>(TP + TN) / totalSamples;double Pe = static_cast<double>((TP + FN) * (TP + FP) + (FN + TN) * (FP + TN)) / (totalSamples * totalSamples);if (Pe == 1) {std::cerr << "Pe的值为1,Cohen's Kappa不能计算" << std::endl;return 0.0;}double kappa = (Po - Pe) / (1 - Pe);return kappa;
}int main() {// 假设有10个样本的预测值和真实值std::vector<int> predictions = {1, 0, 1, 1, 0, 1, 0, 0, 1, 1};std::vector<int> targets = {1, 0, 0, 1, 0, 1, 1, 0, 1, 1};int TP, TN, FP, FN;// 计算混淆矩阵的四个元素calculateConfusionMatrix(predictions, targets, TP, TN, FP, FN);// 计算Cohen's Kappadouble kappa = calculateCohensKappa(TP, TN, FP, FN);std::cout << "混淆矩阵:" << std::endl;std::cout << "| " << TP << " | " << FN << " |" << std::endl;std::cout << "| " << FP << " | " << TN << " |" << std::endl;std::cout << "Cohen's Kappa: " << kappa << std::endl;return 0;
}
Matthews相关系数(Matthews Correlation Coefficient,MCC):

MCC 是另一种衡量分类器性能的指标,它综合考虑了真正例、真负例、假正例和假负例的数量。
Matthews相关系数(Matthews Correlation Coefficient,MCC),也称为Matthews相关性指数,是一种用于衡量二分类模型性能的指标。它综合考虑了混淆矩阵的四个元素(TP、TN、FP、FN),并可以评估模型在类别不平衡情况下的性能。

Matthews相关系数的取值范围在-1到1之间,具体解释如下:

  • MCC = 1:完美预测,模型的预测与真实标签完全一致。
  • MCC > 0:优于随机预测,模型的预测优于随机预测。
  • MCC = 0:与随机预测一致,模型的预测没有优于随机预测。
  • MCC < 0:差于随机预测,模型的预测差于随机预测。

Matthews相关系数的计算公式如下:

    MCC = (TP * TN - FP * FN) / sqrt((TP + FP) * (TP + FN) * (TN + FP) * (TN + FN))

其中,TP、TN、FP、FN分别为混淆矩阵的四个元素。

Matthews相关系数是一种对称性的指标,对类别不平衡问题不敏感。它可以帮助我们全面评估二分类模型的性能,并在样本不均衡的情况下提供更稳健的评估。通常来说,MCC值越接近1,表示模型的性能越好。

以下是用C++编写的一个简单示例代码,用于计算Matthews相关系数(MCC):

#include <iostream>
#include <vector>
#include <cmath>// 计算混淆矩阵的四个元素(TP、TN、FP、FN)
void calculateConfusionMatrix(const std::vector<int>& predictions, const std::vector<int>& targets,int& TP, int& TN, int& FP, int& FN) {if (predictions.size() != targets.size() || predictions.empty()) {std::cerr << "预测值和真实值的数量应该相等且不为空" << std::endl;return;}TP = TN = FP = FN = 0;for (size_t i = 0; i < predictions.size(); ++i) {if (predictions[i] == 1) {if (targets[i] == 1) {TP++;} else {FP++;}} else {if (targets[i] == 0) {TN++;} else {FN++;}}}
}// 计算Matthews相关系数(MCC)
double calculateMatthewsCorrelationCoefficient(int TP, int TN, int FP, int FN) {double denominator = sqrt((TP + FP) * (TP + FN) * (TN + FP) * (TN + FN));if (denominator == 0) {std::cerr << "分母不能为0" << std::endl;return 0.0;}double mcc = (TP * TN - FP * FN) / denominator;return mcc;
}int main() {// 假设有10个样本的预测值和真实值std::vector<int> predictions = {1, 0, 1, 1, 0, 1, 0, 0, 1, 1};std::vector<int> targets = {1, 0, 0, 1, 0, 1, 1, 0, 1, 1};int TP, TN, FP, FN;// 计算混淆矩阵的四个元素calculateConfusionMatrix(predictions, targets, TP, TN, FP, FN);// 计算Matthews相关系数(MCC)double mcc = calculateMatthewsCorrelationCoefficient(TP, TN, FP, FN);std::cout << "混淆矩阵:" << std::endl;std::cout << "| " << TP << " | " << FN << " |" << std::endl;std::cout << "| " << FP << " | " << TN << " |" << std::endl;std::cout << "Matthews相关系数(MCC): " << mcc << std::endl;return 0;
}

在此示例中,我们定义了几个函数来计算混淆矩阵的四个元素(TP、TN、FP、FN)和Matthews相关系数(MCC)。首先,我们计算混淆矩阵的四个元素,然后根据这些元素计算Matthews相关系数。最后,输出混淆矩阵和Matthews相关系数的值作为二分类模型性能的评估指标。

最优阈值

  • F1-Score:F1-Score是精确率(Precision)和召回率(Recall)的调和平均值,取得最大值时对应的阈值可以被认为是最优阈值。F1-Score适用于同时考虑准确率和召回率的情况。

  • ROC曲线:在ROC曲线上,最优阈值通常对应于曲线上最靠近左上角(0, 1)的点。这个点同时具有较高的真阳性率和较低的假阳性率。

在这里插入图片描述

约登指数(Youden’s J statistic),所有样本中 T P R − F P R TPR-FPR TPRFPR 的值最大的数叫约登点,当前序号阈值也是最优阈值。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2807821.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

K8s安全一

Kubernetes是一个开源的&#xff0c;用于编排云平台中多个主机上的容器化的应用&#xff0c;目标是让部署容器化的应用能简单并且高效的使用, 提供了应用部署&#xff0c;规划&#xff0c;更新&#xff0c;维护的一种机制。其核心的特点就是能够自主的管理容器来保证云平台中的…

值得推荐收藏的5款顶级免费数据恢复软件!

今天分享5个超级简单又适合电脑小白的恢复删除的文件的恢复方法&#xff01; 在我们的日常生活中&#xff0c;偶尔会因为误删除或者清空回收站等原因导致数据丢失。对于电脑小白来说&#xff0c;这或许是一个非常棘手的问题。但是&#xff0c;不用太担心&#xff0c;今天我为大…

【C++那些事儿】C++入门 | 命名空间 | 缺省参数 | 引用 | 内联函数 | auto关键字 | 范围for循环 | nullptr

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C那些事儿 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 前言1. C关键字(C98)2. 命名空间2.1 命名空间定义2.2 命名空间使用 3. C输入&输出4. 缺…

模型上下文长度达到10000000,又一批创业者完蛋了?

没有疑问&#xff0c;Gemini 1.5 Pro的隆重推出被Sora抢了风头。 社交平台X上OpenAI介绍Sora的第一条动态&#xff0c;现在已经被浏览了超过9000万次&#xff0c;而关于Gemini 1.5 Pro热度最高的一条&#xff0c;来自谷歌首席科学家Jeff Dean&#xff0c;区区123万人。 或许J…

【设计模式】策略模式及函数式编程的替代

本文介绍策略模式以及使用函数式编程替代简单的策略模式。 策略模式 在策略模式&#xff08;Strategy Pattern&#xff09;中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。 在策略模式定义了一系列算法或策略&#xff0c;并将每个算法封装在独立…

Jenkins解决Host key verification failed (2)

Jenkins解决Host key verification failed 分析原因情况 一、用OpenSSH的人都知ssh会把你每个你访问过计算机的公钥(public key)都记录在~/.ssh/known_hosts。当下次访问相同计算机时&#xff0c;OpenSSH会核对公钥。如果公钥不同&#xff0c;OpenSSH会发出警告&#xff0c;避免…

基于SpringBoot的航班进出港管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

【Java程序设计】【C00319】基于Springboot的志愿服务管理系统(有论文)

基于Springboot的志愿服务管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的志愿服务管理系统设计与实现&#xff0c;本系统有管理员以及用户二种角色权限 管理员&#xff1a;首页、个人中心、管理员管理、…

【MATLAB源码-第146期】基于matlab的信源编码仿真GUI,对比霍夫曼编码,算术编码和LZ编码。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 霍夫曼编码、算术编码和LZ编码是三种广泛应用于数据压缩领域的编码技术。它们各自拥有独特的设计哲学、实现方式和适用场景&#xff0c;因此在压缩效率、编解码速度和内存使用等方面表现出不同的特点。接下来详细描述这三种编…

Base64 编码 lua

Base64 编码 -- Base64 字符表 local base64_chars { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,…

freeswitch 权威指南 --- 高级篇

官网文档&#xff1a;https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/ 关于 freeswitch 的公开教程&#xff1a;https://zhuanlan.zhihu.com/p/451981734 内容来自 《FreeSWITCH 权威指南》&#xff1a;目录&#xff1a;https://juejin.cn/post/702058079…

Vue+SpringBoot打造开放实验室管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

什么是智慧公厕?如何打造智慧公厕?

近年来&#xff0c;随着城市信息化建设的不断推进&#xff0c;智慧公厕的建设成为我国城市发展的重要一环。以智能化管理为核心&#xff0c;将公厕纳入互联互通的“智慧城市”大数据平台&#xff0c;使得公厕管理更加高效便捷&#xff0c;为市民提供更好的公共服务。本文将以智…

零基础C++开发上位机--基于QT5.15的串口助手(一)

嵌入式开发的过程中&#xff0c;大部分我们的代码是无法一次成功的。这时候我们大部分的工程师可能最熟练的调试方法是printf函数&#xff0c;打印随意一个数据&#xff0c;来观察当前运行的函数是否执行正确。我们连接的工具有各个大神做的串口助手。另外&#xff0c;在做一般…

[RCTF2015]EasySQL1 题目分析与详解

一、题目介绍&#xff1a; 1、题目来源&#xff1a; BUUCTF网址 2、题目介绍&#xff1a; 拿到flag。 二、解题思路&#xff1a; 我们发现题目首页有登录和注册账号两个选项&#xff0c;我们首先尝试注册账号&#xff0c;尝试注册username为admin的账号&#xff0c;输入密码…

2024年贵州省事业单位考试下周一开始报名,千万不要错过报名时间

2024年贵州省事业单位考试公告已出&#xff01;快看看你能不能报名&#xff01; 1、报名时间安排 (一)网上报名 2024年2月26日-2024年2月28日 (二)网上资格初审 2024年2月26日-2024年2月29日 (三)网上缴费 2024年2月26日-2024年3月1日 2、笔试安排 2024年3月30日 08:30-10:…

sentinel整合nacos在gateway中实现限流

sentinel整合nacos在gateway中实现限流 一、应用层面完成网关整合nacos和sentinel实现限流 前沿 启动nacos与sentinel的jar的启动&#xff0c;这里不细讲 sentinel官网 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 sentinel 下载地址 https://github.com/…

Google炸场!最强轻量级、开放模型Gemma发布,个人PC就能用,内部员工:强是强,但名字取得让我混乱

想参与根多多学术讨论&#xff0c;请加qq群 链接直达&#xff1a;00后编程交流qq群 如果想要聊天交友&#xff0c;可以加qq群 链接直达&#xff1a;00后聊天交友处cp 欢迎大家加入 不同于OpenAI的闭源大模型&#xff0c;科技巨头如Google和Meta正积极投入开放模型的开发&a…

uni-app 实现拍照后给照片加水印功能

遇到个需求需要实现&#xff0c;研究了一下后写了个demo 本质上就是把拍完照后的照片放到canvas里&#xff0c;然后加上水印样式然后再重新生成一张图片 代码如下&#xff0c;看注释即可~使用的话记得还是得优化下代码 <template><view class"content"&g…

【ArcGIS】利用DEM进行水文分析:流向/流量等

利用DEM进行水文分析 ArcGIS实例参考 水文分析通过建立地表水文模型&#xff0c;研究与地表水流相关的各种自然现象&#xff0c;在城市和区域规划、农业及森林、交通道路等许多领域具有广泛的应用。 ArcGIS实例 某流域30m分辨率DEM如下&#xff1a; &#xff08;1&#xff09…