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

news2024/11/20 7:16:19

文章目录

      • 分类度量
        • 混淆矩阵(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)
    {
        //数据映射到vector
        std::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和FPR
        for (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和FPR
            temp.first = (calculateFPR(FP, TN));//FPR
            temp.second = (calculateTPR(TP, FN));//TPR
            points.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);
            //找出所有FPR
            for (int j = 0; j < binaryROC.size(); ++j)
            {
                allFPR.push_back(binaryROC.at(j).first);
            }

        }

        allFPR = sortAndRemoveDuplicates(allFPR);

        //求宏平均ROC
        std::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 Kappa
    double 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://www.coloradmin.cn/o/1469345.html

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

相关文章

EasyRecovery2024免费不要钱的电脑数据恢复软件下载

EasyRecovery 2024易恢复软件在数据恢复方面的表现评价&#xff0c;EasyRecovery 2024易恢复软件在数据恢复领域享有良好的声誉&#xff0c;它提供了全面的功能&#xff0c;易于使用的界面以及可靠的数据恢复效果。以下是对该软件在数据恢复方面的详细评价&#xff1a; EasyRec…

03|JOIN关联查询优化

1. mysql关联算法 1.1 嵌套循环连接 Nested-Loop Join(NLJ) 算法 先去t2表&#xff08;驱动表&#xff09;拿一行数据,然后去t1表&#xff08;被驱动表&#xff09;做关联, 关联之后把结果集存下来最后返回. 1.2 基于块的嵌套循环连接 Block Nested-Loop Join(BNL)算法 1.把 t…

森歌深化体育营销战略,揭晓2024奥运新代言人,携手共创影响力奇迹

2024年&#xff0c;奥运龙年的春节将将过去&#xff0c;各大高端品牌便纷纷开始激烈博弈。森歌有备而来&#xff01;布局早&#xff0c;积累深&#xff0c;以其深入骨髓的体育情怀和独具匠心的品牌策略&#xff0c;成为厨电行业的佼佼者。2月27日-2月28日&#xff0c;森歌将在杭…

电子器件系列64:稳压二极管ZM4728A

C143062_稳压二极管_ZM4728A-GS08_规格书_WJ481159 稳压管可以用于信号线路的旁路&#xff0c;用于过滤高频信号&#xff1f; 这种电路叫做限幅电路 从集成电路Al的①脚输出信号通过Rl加到集成电路A2的①脚。当集成电路Al的①脚输出信号幅度没有超过VD1稳压值时&#xff0c;这…

HDL FPGA 学习 - Avlon 总线,从端口传输、主端口传输,单周期、可变周期传输

目录 1.1 Avlon 总线 定制 外设 IP 核的框架 从端口传输 从端口信号类型 从端口传输模式列举 基本单周期读写传输 固定等待周期的读写传输 可变等待周期的读写传输&#xff08;推荐&#xff09; 具有建立时间和保持时间读写传输 主端口传输 主端口信号类型 主端口传…

Day04-流程控制语句_循环结构(while,do...while,关键字continue,关键字break,循环嵌套)

文章目录 Day04- 循环结构学习目标1 while循环2 do...while循环4 循环语句的区别5 关键字continue6 关键字break7 循环嵌套案例1&#xff1a;打印5行直角三角形案例2&#xff1a;break结束当层循环 Day04- 循环结构 学习目标 理解for语句的格式和执行流程 随机数公式 理解…

MES管理系统生产过程控制的核心要素

MES&#xff08;制造执行系统&#xff09;是为优化制造业生产过程和管理而设计的软件系统&#xff0c;其核心要素包括&#xff1a; 工单管理&#xff1a;工单管理是MES系统最基本的功能之一&#xff0c;它可以跟踪和管理各种类型的工单&#xff0c;如生产工单、维修工单和质量…

IO进程线程复习:进程线程、通信

1.进程的创建 #include<myhead.h>int main(int argc, const char *argv[]) {printf("hello world\n");//父进程执行的内容int num520;//在父进程中定义的变量pid_t pidfork();//创建子进程if(pid>0){while(1){printf("我是父进程&#xff0c;num%d\n&…

【ubuntu】永久修改主机名

文章目录 1. 问题描述2. 解决方案 1. 问题描述 主机名过长&#xff08;后面的部分&#xff09; 2. 解决方案 查看主机名详情 hostnamectl修改指定主机名 hostnamectl set-hostname ubuntu2204 --static登出重进即可

【Java程序设计】【C00279】基于Springboot的智慧外贸平台(有论文)

基于Springboot的智慧外贸平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的智慧外贸平台 本系统分为系统功能模块、管理员功能模块、买家功能模块以及商家功能模块。 系统功能模块&#xff1a;在平台首页可以…

五篇保姆级分类诊断教程,数据特征提取+优化算法+机器学习

今天水一期&#xff0c;总结一下以前写过的几篇保姆级故障诊断。学会这几篇&#xff0c;机器学习的故障诊断你就基本合格了&#xff01; 本期内容&#xff1a;基于SABO-VMD-CNN-SVM的分类诊断。 依旧是采用经典的西储大学轴承数据。基本流程如下&#xff1a; 首先是以最小包络熵…

java spring 01 IOC源码

01.spring 中的基础是IOC

动态规划课堂1-----斐波那契数列模型

目录 动态规划的概念&#xff1a; 动态规划的解法流程&#xff1a; 题目: 第 N 个泰波那契数 解法&#xff08;动态规划&#xff09; 代码&#xff1a; 优化&#xff1a; 题目&#xff1a;最小花费爬楼梯 解法&#xff08;动态规划&#xff09; 解法1&#xff1a; 解…

mybatis中foreach批量插入并返回主键

背景 批量插入多条数据,插入成功之后每条数据中需要返回自增主键.处理办法 1.确定项目中mybatis版本,要求3.3.1以上. 查看springboot中项目版本方法: pom.xml中进入依赖(Ctrl点击进入): <dependency><groupId>org.mybatis.spring.boot</groupId><artifac…

【Flink精讲】Flink 内存管理

面临的问题 目前&#xff0c; 大数据计算引擎主要用 Java 或是基于 JVM 的编程语言实现的&#xff0c;例如 Apache Hadoop、 Apache Spark、 Apache Drill、 Apache Flink 等。 Java 语言的好处在于程序员不需要太关注底层内存资源的管理&#xff0c;但同样会面临一个问题&…

【安卓逆向】app防止截屏分析与去除

本次分析的app name为&#xff1a;5paH5qGI54uX 这款应用打开之后里面的内容是不允许截图的&#xff0c;防止截图分析&#xff1a;Android应用防止截屏_landroid/view/window;->setflags 0x2000-CSDN博客 App防止恶意截屏功能的方法&#xff1a;iOS、Android和鸿蒙系统的实…

130.乐理基础-倍增音程、倍减音程

上一个内容&#xff1a;129.乐理基础-曾音程、减音程、等音程-CSDN博客 上一个内容里练习的答案&#xff1a; 倍减音程指的是&#xff1a;比减几度还要小二分之一音数的就叫做倍减几度&#xff0c;如下图 反过来说比增还要打二分之一的是倍增 例子1&#xff1a; 例子2&#xf…

[计网底层小探索]:实现并部署多线程并发Tcp服务器框架(基于生产者消费者模型的线程池结构)

文章目录 一.网络层与传输层协议sockaddr结构体继承体系(Linux体系)贯穿计算机系统的网络通信架构图示: 二.实现并部署多线程并发Tcp服务器框架线程池模块序列化反序列化工具模块通信信道建立模块服务器主体模块任务回调模块(根据具体应用场景可重构)Tips:DebugC代码过程中遇到…

成功解决ModuleNotFoundError: No module named ‘cv2’

&#x1f525; 成功解决ModuleNotFoundError: No module named ‘cv2’ &#x1f525; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 …

如何安装自定义模块?

自定义模块的安装方式如下&#xff1a; 进行了这些操作之后&#xff0c;你就会发现&#xff0c;自己写的代码块&#xff0c;成了可以调用的模块了。