数据挖掘学习笔记:朴素贝叶斯 | Python复现

news2024/11/23 19:27:51

数据挖掘学习笔记:朴素贝叶斯

机器学习系列(四):朴素贝叶斯(华强买瓜版) - yyxy的文章 - 知乎

十分钟,让你再也忘不掉贝叶斯分类 - VoidHaruhi的文章 - 知乎

《机器学习》(西瓜书)公式详解

【吃瓜教程】《机器学习公式详解》(南瓜书)与西瓜书公式推导

到底要如何理解条件概率? - 石溪的回答 - 知乎

如何在 Python 中从零开始实现朴素贝叶斯

贝叶斯决策论

​  假设当前有一个 N N N分类任务,即 Y = { c 1 , c 2 , ⋯   , c N } \mathcal{Y}=\{c_1,c_2,\cdots,c_N\} Y={c1,c2,,cN},将 λ i j \lambda_{ij} λij定义为将一个真实标记 c j c_j cj的样本误分类为 c i c_i ci所产生的损失。如果其目标为最小化分类错误率,则损失 λ i j \lambda_{ij} λij可写为:
λ i j = { 0 , i = j   ; 1 , otherwise , (1) \lambda_{ij} = \begin{cases} 0, & i=j\ ; \\ 1, & \text{otherwise\ ,} \tag{1} \end{cases} λij={01i=j ;otherwise ,(1)
此时,对于单个样本 x \boldsymbol{x} x而言,定义其期望损失为如下条件风险的形式:
R ( c i ∣ x ) = ∑ j = 1 N λ i j P ( c j ∣ x ) , (2) R(c_i|\boldsymbol{x})=\sum_{j=1}^N{\lambda_{ij}P(c_j|\boldsymbol{x})},\tag{2} R(cix)=j=1NλijP(cjx),(2)
上式中, P ( c j ∣ x ) P(c_j|\boldsymbol{x}) P(cjx)为后验概率。

  那么,贝叶斯决策论的任务就是去寻找一个判定准则 h : X ↦ Y h:\mathcal{X}\mapsto\mathcal{Y} h:XY,以最小化全部样本构成的总体风险:
R ( h ) = E x [ R ( h ( x ) ) ∣ x ] . (3) R(h)=\mathbb{E}_x[R(h(\boldsymbol{x}))|\boldsymbol{x}].\tag{3} R(h)=Ex[R(h(x))x].(3)
  在定义完上述概念之后,我们就可以引入贝叶斯判定准则,即最小化总体风险 R ( h ) R(h) R(h)。因此,只需在每个样本上选择那个能使条件风险 R ( c ∣ x ) R(c|\boldsymbol{x}) R(cx)最小的类别标记:
h ∗ ( x ) = arg ⁡ min ⁡ c ∈ Y   R ( c ∣ x ) , (4) h^*(\boldsymbol{x})=\underset{c\in \mathcal{Y}} {\arg\min}\ R(c|\boldsymbol{x}),\tag{4} h(x)=cYargmin R(cx),(4)
此时, h ∗ h^* h被称为贝叶斯最优分类器。

  对公式(2)展开得:
R ( c i ∣ x ) = 1 ∗ P ( c 1 ∣ x ) + ⋯ + 1 ∗ P ( c i − 1 ∣ x ) + 0 ∗ P ( c i ∣ x ) + 1 ∗ P ( c i + 1 ∣ x ) + ⋯ + 1 ∗ P ( c N ∣ x ) , (5) R(c_i|\boldsymbol{x})=1*P(c_1|\boldsymbol{x})+\cdots+1*P(c_{i-1}|\boldsymbol{x})+0*P(c_i|\boldsymbol{x})+1*P(c_{i+1}|\boldsymbol{x})+\cdots+1*P(c_N|\boldsymbol{x}),\tag{5} R(cix)=1P(c1x)++1P(ci1x)+0P(cix)+1P(ci+1x)++1P(cNx),(5)
对于一个 N N N分类任务而言,所有类别预测的概率总和一定为1,即:
∑ j = 1 N P ( c j ∣ x ) = 1. (6) \sum_{j=1}^N{P(c_j|\boldsymbol{x})}=1.\tag{6} j=1NP(cjx)=1.(6)
  此时,条件风险可化简为:
R ( c i ∣ x ) = 1 − P ( c i ∣ x ) . (7) R(c_i|\boldsymbol{x})=1-P(c_i|\boldsymbol{x}).\tag{7} R(cix)=1P(cix).(7)
  于是,最小化分类错误率的贝叶斯最优分类器可写为:
h ∗ ( x ) = arg ⁡ max ⁡ c ∈ Y   P ( c ∣ x ) . (8) h^*(\boldsymbol{x})=\underset{c\in \mathcal{Y}}{\arg\max}\ P(c|\boldsymbol{x}).\tag{8} h(x)=cYargmax P(cx).(8)
  对每个样本 x \boldsymbol{x} x,选择能使后验概率 P ( c ∣ x ) P(c|\boldsymbol{x}) P(cx)最大的类别标记。

生成式模型与判别式模型

  如SVM这样的机器学习模型,其本质是在特征空间内寻找一个超平面把类别样本划分开,是一个从几何角度思考的模型,并没有涉及概率的计算。所谓判别式模型,就是直接对后验概率进行建模,求出每个类别的概率进行分类。下面要将的朴素贝叶斯则属于生成式模型,其先对联合概率先进行建模,再推导出后验概率,即:
P ( c ∣ x ) = P ( x , c ) P ( x ) . (9) P(c|\boldsymbol{x})=\frac{P(\boldsymbol{x},c)}{P(\boldsymbol{x})}.\tag{9} P(cx)=P(x)P(x,c).(9)
  公式(9)是很简单的条件概率一般定义,可以从古典概型进行推导。

  假定一个试验有 N N N个等可能的结果,事件 A A A B B B分别包含 M 1 M_1 M1个和 M 2 M_2 M2个结果,这其中有 M 12 M_{12} M12个结果是公共的,这就是同时发生事件 A A A 和事件 B B B,即 A ∩ B A\cap B AB事件所包含的试验结果数。

img

图源《到底要如何理解条件概率?石溪的回答》:https://www.zhihu.com/question/322520602/answer/2364488211
  那么已知在事件$B$发生的前提条件下,事件$A$发生的概率为:

P ( A ∣ B ) = M 12 M 2 . (10) P(A|B)=\frac{M_{12}}{M_2}.\tag{10} P(AB)=M2M12.(10)
  对于上式,可以进行展开:
P ( A ∣ B ) = M 12 N M 2 N = P ( A B ) P ( B ) . (11) P(A|B)=\frac{\frac{M_{12}}{N}}{\frac{M_2}{N}}=\frac{P(AB)}{P(B)}.\tag{11} P(AB)=NM2NM12=P(B)P(AB).(11)
  故可以得到条件概率的一般定义:
P ( A ∣ B ) = P ( A B ) P ( B ) . (12) P(A|B)=\frac{P(AB)}{P(B)}.\tag{12} P(AB)=P(B)P(AB).(12)

  回到公式(9),用贝叶斯定理可以恒等变形为:
P ( c ∣ x ) = P ( c ) P ( x ∣ c ) P ( x ) = P ( c ) P ( x 1 , ⋯   , x d ∣ c ) P ( x ) (13) P(c|\boldsymbol{x})=\frac{P(c)P(\boldsymbol{x}|c)}{P(\boldsymbol{x})}=\frac{P(c)P(x_1,\cdots,x_d|c)}{P(\boldsymbol{x})}\tag{13} P(cx)=P(x)P(c)P(xc)=P(x)P(c)P(x1,,xdc)(13)
其中, P ( c ) P(c) P(c)是先验概率, P ( x ∣ c ) P(\boldsymbol{x}|c) P(xc)是样本 x \boldsymbol{x} x相对于类别标记 c c c是类条件概率,也叫似然, P ( x ) P(\boldsymbol{x}) P(x)是归一化用的证据因子。

  在公式(13)中最难建模的是类条件概率,假如样本 x = ( x 1 , x 2 , ⋯   , c d ) \boldsymbol{x}=(x_1,x_2,\cdots,c_d) x=(x1,x2,,cd) d d d个特征,每个特征又有多个取值,那么样本相对于类别 c c c的组合数不胜数,甚至在数据集中都没有这种组合。那如何把这个类条件概率计算出来呢?朴素贝叶斯给了这么一种方法。

朴素贝叶斯

  朴素贝叶斯假设对于已知类别,各个属性相互独立,即满足属性条件独立性假设。那么后验概率可以写成:
P ( c ∣ x ) = P ( c ) P ( x ) ∏ i = 1 d P ( x i ∣ c ) , (14) P(c|\boldsymbol{x})=\frac{P(c)}{P(\boldsymbol{x})}\prod_{i=1}^d{P({x_i}|c)},\tag{14} P(cx)=P(x)P(c)i=1dP(xic),(14)
其中, d d d为属性数目, x i x_i xi表示 x \boldsymbol{x} x在第 i i i个属性上的取值。基于贝叶斯判定准则可得:
h ∗ ( x ) = arg ⁡ max ⁡ c ∈ Y   P ( c ) P ( x ) ∏ i = 1 d P ( x i ∣ c ) . (15) h^*(x)=\underset{c\in \mathcal{Y}}{\arg\max}\ \frac{P(c)}{P(\boldsymbol{x})}\prod_{i=1}^dP(x_i|c).\tag{15} h(x)=cYargmax P(x)P(c)i=1dP(xic).(15)
  综上所述,样本所属的哪个类别的后验概率最大,就选择哪个类别作为模型 h ∗ ( x ) h^*(x) h(x)的预测结果。那么,现在的问题就是,如何计算类条件概率和先验概率,才能使得模型预测得最准,即条件风险最小。

  对于先验概率的计算很简单,利用大数定理,在训练集样本足够多的情况下用频率近似概率:
P ( c ) = ∣ D c ∣ ∣ D ∣ , (16) P(c)=\frac{|D_c|}{|D|},\tag{16} P(c)=DDc,(16)
其中, ∣ D c ∣ |D_c| Dc表示训练集 D D D中类别标记为 c c c的样本集合, ∣ D c ∣ |D_c| Dc表示集合 D c D_c Dc的样本总数。

  对于类条件概率的计算要分成两种情况讨论:离散属性和连续属性。对于离散属性的类条件概率计算思路和公式(10)一样,因此第 i i i个属性为离散属性的类条件概率为:
P ( x i ∣ c ) = ∣ D c , x i ∣ ∣ D c ∣ , (17) P(x_i|c)=\frac{|D_{c,x_i}|}{|D_c|},\tag{17} P(xic)=DcDc,xi,(17)
其中, ∣ D c , x i ∣ |D_{c,x_i}| Dc,xi表示 ∣ D c ∣ |D_c| Dc在第 i i i个属性上取值为 x i x_i xi的样本组成的集合。

  然而,如果某个属性值在训练集中没有与某个类别同时出现过,直接使用公式(17)计算,则会让连乘式子结果为0。为避免出现这种情况,在估计概率值时应该加以平滑,按《西瓜书》的示例,使用拉普拉斯修正:
P ^ ( c ) = ∣ D c ∣ + 1 ∣ D ∣ + N P ^ ( x i ∣ c ) = ∣ D c , x i ∣ + 1 ∣ D c ∣ + N i \begin{align} \hat P(c) &= \frac{|D_c|+1}{|D|+N}\tag{18} \\ \hat P(x_i|c) &= \frac{|D_{c,x_i}|+1}{|D_c|+N_i}\tag{19} \end{align} P^(c)P^(xic)=D+NDc+1=Dc+NiDc,xi+1(18)(19)
其中, N N N表示类别数量, N i N_i Ni表示第 i i i个属性出现的取值数量。

  对于连续属性,假设满足正态分布,那么其概率密度函数为:
p ( x i ∣ c ) = 1 2 π σ c , i exp ⁡ { − ( x i − μ c , i ) 2 2 σ c , i 2 } , (20) p(x_i|c)=\frac{1}{\sqrt{2\pi}\sigma_{c,i}}\exp\{-\frac{(x_i-\mu_{c,i})^2}{2\sigma_{c,i}^2}\},\tag{20} p(xic)=2π σc,i1exp{2σc,i2(xiμc,i)2},(20)
其中, μ c , i \mu_{c,i} μc,i σ c , i 2 \sigma_{c,i}^2 σc,i2分别表示第 c c c类样本在第 i i i个属性上取值的均值和方差。

  接下来,我们使用极大似然估计去估计其均值和方差。公式(20)为一元正态分布的概率密度函数,下面对于多元正态分布的概率密度函数 p ( x ∣ c ) ∼ N ( μ c , σ c 2 ) p(\boldsymbol{x}|c)\sim \mathcal{N}(\boldsymbol{\mu}_c,\boldsymbol{\sigma}_c^2) p(xc)N(μc,σc2)而言,其等价形式为:
p ( x ∣ μ c , σ c 2 ) = 1 ( 2 π ) d ∣ Σ c ∣ exp ⁡ { − 1 2 ( x − μ c ) T Σ c − 1 ( x − μ c ) } , (21) p(\boldsymbol{x}|\boldsymbol{\mu}_c,\boldsymbol{\sigma}_c^2)=\frac{1}{\sqrt{(2\pi)^d|\boldsymbol{\Sigma}_c|}}\exp\{-\frac{1}{2}(\boldsymbol{x}-\boldsymbol{\mu}_c)^T\boldsymbol{\Sigma}_c^{-1}(\boldsymbol{x}-\boldsymbol{\mu}_c)\},\tag{21} p(xμc,σc2)=(2π)dΣc 1exp{21(xμc)TΣc1(xμc)},(21)
其中, d d d表示 x \boldsymbol{x} x的维数, Σ c = σ c 2 \boldsymbol{\Sigma}_c=\boldsymbol{\sigma}_c^2 Σc=σc2为正定协方差矩阵。

  对数极大似然估计的参数求解形式为:
θ c ^ = arg ⁡ max ⁡ θ c   L L ( θ c ) = arg ⁡ min ⁡ θ c   − ∑ x ∈ D c log ⁡ P ( x ∣ θ c ) (22) \begin{align} \hat{\boldsymbol{\theta}_c} &= \underset{\boldsymbol{\theta}_c}{\arg\max}\ LL(\boldsymbol{\theta}_c) \\ &= \underset{\boldsymbol{\theta}_c}{\arg\min}\ -\sum_{\boldsymbol{x}\in D_c}\log P(\boldsymbol{x}|\boldsymbol{\boldsymbol{\theta}_c}) \end{align} \tag{22} θc^=θcargmax LL(θc)=θcargmin xDclogP(xθc)(22)
  通过极大似然估计的均值和方差如下:
μ ^ c = 1 ∣ D c ∣ ∑ x ∈ D c x , (23) \hat {\boldsymbol{\mu}}_c=\frac{1}{|D_c|}\sum_{\boldsymbol{x}\in D_c}\boldsymbol{x},\tag{23} μ^c=Dc1xDcx,(23)

σ ^ c 2 = 1 ∣ D c ∣ ∑ x ∈ D c ( x − μ ^ c ) ( x − μ ^ c ) T . (24) \hat{\boldsymbol{\sigma}}_c^2=\frac{1}{|D_c|}\sum_{\boldsymbol{x}\in D_c}(\boldsymbol{x}-\hat {\boldsymbol{\mu}}_c)(\boldsymbol{x}-\hat {\boldsymbol{\mu}}_c)^T.\tag{24} σ^c2=Dc1xDc(xμ^c)(xμ^c)T.(24)

  详细的推导过程见南瓜书第63~64页。

  假如说,将朴素贝叶斯应用于你的数据集上发现效果并不理想,那么可以考虑更换概率分布,这或许可以看作是贝叶斯分类的超参数。当然,也有可能数据集上的各个属性不独立。

实现代码

  代码中使用的数据集来自和鲸社区:皮马印第安人糖尿病数据库

  复现代码和划分的数据集见Git仓库:朴素贝叶斯

import math
import pandas as pd

# 皮马印第安人糖尿病数据
train_data = pd.read_csv(r'train_data.csv').values
test_data = pd.read_csv(r'test_data.csv').values

# 划分连续和离散型变量
continuous_columns = [1, 2, 3, 4, 5, 6]  # Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction
discrete_columns = [0, 7]  # Pregnancies, Age

# 将数据按类别分离
separated_data = {0: [], 1: []}  # 创建一个空字典用来存储两个类别下的样本
for row in train_data:
    class_label = row[-1]  # 获取类别列
    separated_data[class_label].append(row)  # 把相同类别下的样本放到一起

# 分别计算两个类别下每个连续变量的均值和标准差、和离散变量的频率
class_summaries = {}  # 创建一个空字典用来存储两个类别下连续变量和离散变量的统计信息
for class_label, rows in separated_data.items():
    summaries = {}

    # 连续型变量的均值和标准差
    continuous_summaries = []
    for col_idx in continuous_columns:
        column = [row[col_idx] for row in rows]  # 把连续变量的一整列提取出来
        mean_val = sum(column) / len(column)  # 计算均值 μ_c
        variance = sum([(x - mean_val) ** 2 for x in column]) / len(column)  # 计算方差 σ_c^2
        stdev_val = math.sqrt(variance)  # 计算标准差 σ_c
        continuous_summaries.append((mean_val, stdev_val))

    # 离散型变量的频率计算
    discrete_summaries = []
    for col_idx in discrete_columns:
        column = [row[col_idx] for row in rows]  # 把离散变量的一整列提取出来
        value_counts = {val: column.count(val) for val in set(column)}  # 统计离散变量中每个取值出现的个数,加1是拉普拉斯修正
        total_count = len(rows)
        discrete_summaries.append((value_counts, total_count))

    # 存储两个类别下连续型和离散型的特征统计信息
    summaries['continuous'] = continuous_summaries
    summaries['discrete'] = discrete_summaries
    class_summaries[class_label] = summaries

# 拉普拉斯修正后的先验概率
class_prior = {}
total_samples = len(train_data)  # 样本长度 |D|
num_classes = len(class_summaries)  # 类别数 N

for class_label in separated_data:  # 取出两个类别的样本
    class_count = len(separated_data[class_label])  # 两个类别各自的样本数量 |D_c|
    class_prior[class_label] = (class_count + 1) / (total_samples + num_classes)

# 分类
predictions = []
for row in test_data:  # 对测试集的每一个样本进行分类
    probabilities = {}
    for class_label, summaries in class_summaries.items():  # 两个类别下连续变量和离散变量的统计信息

        # 将第一个类条件概率初始化为先验概率
        probabilities[class_label] = class_prior[class_label]

        # 连续变量的类条件概率
        for i, (mean_val, stdev_val) in enumerate(summaries['continuous']):
            x = row[continuous_columns[i]]  # 测试集每个样本中每个连续变量的取值
            exponent = math.exp(-((x - mean_val) ** 2 / (2 * stdev_val ** 2)))
            continous_probability = (1 / (math.sqrt(2 * math.pi) * stdev_val)) * exponent
            probabilities[class_label] *= continous_probability

        # 离散变量的类条件概率
        for i, (value_counts, total_count) in enumerate(summaries['discrete']):
            x = row[discrete_columns[i]]
            num_values = len(value_counts)  # 变量取值的数量 N_i
            discrete_probability = (value_counts.get(x, 0) + 1) / (total_count + num_values)  # 拉普拉斯修正
            probabilities[class_label] *= discrete_probability

    # 计算归一化因子 P(x)
    total_probability = sum(probabilities.values())
    for class_label in probabilities:
        probabilities[class_label] /= total_probability
    best_class = max(probabilities, key=probabilities.get)  # 看看哪个类别的后验概率大
    predictions.append(best_class)

# 计算准确率
correct_predictions = sum(1 for i in range(len(test_data)) if test_data[i][-1] == predictions[i])
accuracy = (correct_predictions / len(test_data)) * 100.0
print(f'code_accuracy: {accuracy:.4f}%')

半朴素贝叶斯

  朴素贝叶斯是基于各属性都相互独立的假设进行的,但现实生活中并没有如此理想。半朴素贝叶斯则适当考虑一部分属性间的相互依赖信息,从而既不需进行完全联合概率计算,又不至于彻底忽略了比较强的属性依赖关系。

  回顾公式(14),朴素贝叶斯的类条件概率考虑的是只与一个属性 c c c有关,而半朴素贝叶斯不仅考虑属性 c c c,还考虑其他的一个属性,即独依赖估计(ODE):
P ( c ∣ x ) ∝ P ( c ) ∏ i = 1 d P ( x i ∣ c , p a i ) , (25) P(c|\boldsymbol{x})\propto P(c)\prod_{i=1}^d{P({x_i}|c,pa_i)},\tag{25} P(cx)P(c)i=1dP(xic,pai),(25)
其中, p a i pa_i pai表示属性 x i x_i xi所依赖的属性,称为 x i x_i xi的父属性。

  对于如何确定父属性,最直接的做法是假设所有属性都依赖于同一个属性,即超父独依赖估计(SPODE):
P ( c ∣ x ) = P ( x , c ) P ( x ) = P ( c , x i ) P ( x 1 , ⋯   , x i − 1 , x i + 1 , ⋯   , x d ∣ c , x i ) P ( x ) ∝ P ( c , x i ) ∏ j = 1 d P ( x j ∣ c , x i ) , \begin{align} P(c|\boldsymbol{x})=\frac{P(\boldsymbol{x},c)}{P(\boldsymbol{x})}&=\frac{P(c,x_i)P(x_1,\cdots,x_{i-1},x_{i+1},\cdots,x_d|c,x_i)}{P(\boldsymbol{x})}\\ &\propto P(c,x_i)\prod_{j=1}^d{P(x_j|c,x_i)},\tag{26} \end{align} P(cx)=P(x)P(x,c)=P(x)P(c,xi)P(x1,,xi1,xi+1,,xdc,xi)P(c,xi)j=1dP(xjc,xi),(26)
属性都依赖于同一个属性,即超父独依赖估计(SPODE):
P ( c ∣ x ) = P ( x , c ) P ( x ) = P ( c , x i ) P ( x 1 , ⋯   , x i − 1 , x i + 1 , ⋯   , x d ∣ c , x i ) P ( x ) ∝ P ( c , x i ) ∏ j = 1 d P ( x j ∣ c , x i ) , \begin{align} P(c|\boldsymbol{x})=\frac{P(\boldsymbol{x},c)}{P(\boldsymbol{x})}&=\frac{P(c,x_i)P(x_1,\cdots,x_{i-1},x_{i+1},\cdots,x_d|c,x_i)}{P(\boldsymbol{x})}\\ &\propto P(c,x_i)\prod_{j=1}^d{P(x_j|c,x_i)},\tag{26} \end{align} P(cx)=P(x)P(x,c)=P(x)P(c,xi)P(x1,,xi1,xi+1,,xdc,xi)P(c,xi)j=1dP(xjc,xi),(26)
其中, x i x_i xi为超父属性。

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

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

相关文章

快速生成单元测试

1. Squaretest插件 2. 依赖 <dependency><groupId>junit</groupId>

Spring异步线程池的问题

今天看一视频&#xff0c;提到说 Spring默认的异步线程池比较简单&#xff0c;每次执行异步任务&#xff0c;都会新建一个线程进行处理&#xff0c;不会重复利用&#xff0c;所以在用Spring框架开发的时候&#xff0c;需要自定义异步线程池。第一次听到这个说法。遂开始百度。 …

迷你世界表白神器爱心脚本lua

--迷你世界专用爱心表达公式 local a,angle,count,id30,0,0,math.random(668, 681) -- 根据需要调整θ的遍历范围和步长 while true do angle angle0.01 local ra*(math.sin(angle)*(math.sqrt(math.abs(math.cos(angle)))/(math.sin(angle)1.4)-2)2) if r>10…

动手学深度学习59 双向循环神经网络

1. 双向循环神经网络 视频&#xff1a;https://www.bilibili.com/video/BV12X4y1c71W/?p2&spm_id_frompageDriver&vd_sourceeb04c9a33e87ceba9c9a2e5f09752ef8 课件&#xff1a;https://courses.d2l.ai/zh-v2/assets/pdfs/part-3_7.pdf 课本&#xff1a; https://zh-…

机器学习K近邻算法——分类问题K近邻算法示例

针对“数据8.1”&#xff0c;讲解分类问题的K近邻算法&#xff0c;以V1&#xff08;转型情况&#xff09;为响应变量&#xff0c;以V2&#xff08;存款规模&#xff09;、V3&#xff08;EVA&#xff09;、V4&#xff08;中间业务收入&#xff09;、V5&#xff08;员工人数&…

【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则

文章目录 C 继承详解&#xff1a;初阶理解与实战应用前言第一章&#xff1a;继承的基本概念与定义1.1 继承的概念1.2 继承的定义 第二章&#xff1a;继承中的访问权限2.1 基类成员在派生类中的访问权限2.2 基类与派生类对象的赋值转换2.2.1 派生类对象赋值给基类对象2.2.2 基类…

多端同步的收银系统源码

随着经济的不断发展&#xff0c;很多门店越来越趋向连锁品牌化&#xff0c;收银系统自然也成为很多连锁门店必不可少的软件工具。希望通过一套软件可以帮助门店解决门店线下销售、会员管理、连锁多门店管理、线下线上一体化、商品库存管理等难题实现降本增效&#xff0c;为了方…

MySQL连接查询:联合查询

先看我的表结构 emp表 联合查询的关键字&#xff08;union all, union&#xff09; 联合查询 基本语法 select 字段列表 表A union all select 字段列表 表B 例子&#xff1a;将薪资低于5000的员工&#xff0c; 和 年龄大于50 岁的员工全部查询出来 第一种 select * fr…

大模型微调技术之 LoRA:开启高效微调新时代

一、LoRA 简介 LoRA&#xff0c;即低秩适应&#xff08;Low-Rank Adaptation&#xff09;&#xff0c;是一种用于微调大型语言模型的技术&#xff0c;旨在以较小的计算资源和数据量实现模型的快速适应特定任务或领域。 LoRA 方法通过引入低秩近似的思想&#xff0c;对大型预训…

NFS共享文件系统(将文件目录挂载到别的机器上)

我们创建的磁盘是否都必须挂载到本机上&#xff1f;并不是。在 Linux 和其他操作系统中&#xff0c;有一种叫做 NFS&#xff08;网络文件系统&#xff09;的工具&#xff0c;它允许跨网络共享文件系统资源。通过使用 NFS&#xff0c;我们可以将多个客户端服务器的数据目录挂载到…

Java中常见的等待唤醒机制及实践

JDK自带的等待唤醒机制 在Java中&#xff0c;有一个JDK维度的等待唤醒机制。Object类的wait和notify,notifyAll 需要在synchronized同步代码块内并且对象必须获取到锁才能调用。否则会抛IllegalMonitorStateException异常。 当线程在尝试获取锁时失败&#xff0c;会被封装成节…

Mybatis-plus做了什么

Mybatis-plus做了什么 Mybatis回顾以前的方案Mybatis-plus 合集总览&#xff1a;Mybatis框架梳理 聊一下mybatis-plus。你是否有过疑问&#xff0c;Mybatis-plus中BaseMapper方法对应的SQL在哪里&#xff1f;它为啥会被越来越多人接受。在Mybatis已经足够灵活的情况下&…

《强烈推荐一个强大的书签管理工具》

在信息爆炸的时代&#xff0c;我们每天都会浏览大量的网页&#xff0c;收藏各种各样的书签。然而&#xff0c;随着书签数量的增加&#xff0c;管理起来也变得越来越困难。这时&#xff0c;一个强大的书签管理工具就显得尤为重要。今天&#xff0c;我要向大家推荐一款备受好评的…

EtherCAT学习笔记

文章目录 前言一、EtherCAT介绍二、EtherCA系统组成2.1 ESC(EtherCAT从站控制器)2.2 从站控制微处理器2.3 物理层器件2.4 其它应用层器件 三、EtherCAT数据帧结构3.1 寻址方式3.2 时钟3.3 通信模式 四、状态机和通信初始化五、应用层协议六、ESC概述6.1 EtherCAT从站控制芯片6.…

基于SpringBoot+Vue+MySQL的美食信息推荐系统

系统展示 用户前台界面 管理员后台界面 系统背景 在数字化时代&#xff0c;随着人们对美食文化的热爱与追求不断增长&#xff0c;美食信息推荐系统成为了连接食客与美食之间的重要桥梁。面对海量的美食信息&#xff0c;用户往往难以快速找到符合个人口味和需求的美食。因此&…

Java-数据结构-Lambda表达式 (✪ω✪)

文本目录&#xff1a; ❄️一、背景&#xff1a; ➷ 1、Lambda表达式的语法&#xff1a; ➷ 2、函数式接口&#xff1a; ❄️二、Lambda表达式的基本使用&#xff1a; ➷ 1、语法精简&#xff1a; ❄️三、变量捕获&#xff1a; ❄️四、Lambda在集合中的使用&#xff1a; …

Chromium 中js navigator对象c++实现分析

一、Navigator 对象 Navigator 对象包含有关浏览器的信息。 前端测试例子&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>接口测试</title> </head> <body><div id"example&q…

爱心表达公式

脚本公式 local r (math.sin(angle) * math.sqrt(math.abs(math.cos(angle)))) / (math.sin(angle) 1.4) - 2 * math.sin(angle) 2

IOT-Tree连接西门子PLC S7 200 Smart竟然如此简单

最近一个项目需要把用户现场控制柜接入到云端&#xff0c;控制柜使用西门子PLC Smart 200 SR40型号&#xff0c;已经运行多年&#xff0c;PLC通过以太网接口对接一个触摸屏。 按照我以往的经验&#xff0c;觉得触摸屏以太网接口已经被占用&#xff0c;那么只能通过剩余的RS485…

通过一个实际的例子,介绍 Java 的自动装箱与拆箱机制

Java 中 1000 1000 返回 false&#xff0c;但 100 100 返回 true&#xff0c;这一现象背后隐藏了 Java 对于对象和基本类型的内存管理机制。为了理解这个现象&#xff0c;我们需要从 Java 的自动装箱与拆箱机制、对象引用和数值缓存策略等角度深入探讨。让我们一步一步通过 J…