NLP从零开始------12. 关于前十一章补充(英文分词)

news2024/11/16 1:34:37

        相较于基础篇章,这一部分相较于基础篇减少了很多算法推导,多了很多代码实现。

1.英文词规范化

        英文词规范化一般分为标准化缩写,大小写相互转化,动词目态转化等。

1.1 大小写折叠

        大小写折叠( casefolding) 是将所有的英文大写字母转化成小写字母的过程。在搜索场景中, 用户往往喜欢使用小写字母形式,而在计算机中, 大写字母和小写字母并非同一字符,当遇到用户想要搜索一些人名、地名等带有大写字母的专有名词的情况下,若不将小写字母转换成大写, 可能难以匹配正确的搜索结果。示例代码:

# 待处理的句子
sentence = "Let's study Hands-on-NLP"

# 将句子中的所有字符转换为小写
lowercase_sentence = sentence.lower()

# 打印转换后的句子
print(lowercase_sentence)

        结果:

D:\ana\envs\nlp\python.exe D:\pythoncode\nlp\main.py 
let's study hands-on-nlp

进程已结束,退出代码为 0

1.2 词目还原

       在诸如英文这样的语言中,很多单词都会根据不同的主语、语境、时态等情形修改为相应的形态,而这些单词本身表达的含义是接近甚至相同的, 例如英文中的 am、 is、are都可以还原成 be,英文名词 cat根据不同情形有 cat、 cats、 cat's、 cats'等多种形态。这些形态对文本的语义影响相对较小,但是大幅提高了词表的大小, 因而提高了自然语言处理模型的构建成本。因此在有些文本处理问题上,需要将所有的词进行词目还原( lemmatization), 即找出词的原型。人类在学习这些语言的过程中,可以通过词典查找词的原型; 类似地,计算机可以通过构建词典来进行词目还原:

# 构建词典
lemma_dict = {
    'am': 'be',
    'is': 'be',
    'are': 'be',
    'cats': 'cat',
    "cats'": 'cat',
    "cat's": 'cat',
    'dogs': 'dog',
    "dogs'": 'dog',
    "dog's": 'dog',
    'chasing': 'chase'
}

# 待处理的句子
sentence = "Two dogs are chasing three cats"

# 将句子分割成单词列表
words = sentence.split()

# 打印原始单词列表
print(f'词目还原前: {words}')

# 初始化词目还原后的单词列表
lemmatized_words = []

# 遍历单词列表,进行词目还原
for word in words:
    if word in lemma_dict:
        lemmatized_words.append(lemma_dict[word])
    else:
        lemmatized_words.append(word)

# 打印词目还原后的单词列表
print(f'词目还原后: {lemmatized_words}')

        代码结果如下:
 

词目还原前: [' Two', ' dogs', ' are', ' chasing', ' three', ' cats']
词目还原后: [' Two', ' dog', ' be', ' chase', ' three', ' cat']

        另外,也可以利用NLTK 自带的词典来进行词目还原:
 

import nltk
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet

# 下载分词包和wordnet包
nltk.download('punkt', quiet=True)
nltk.download('wordnet', quiet=True)

# 创建词形还原器实例
lemmatizer = WordNetLemmatizer()

# 待处理的句子
sentence = "Two dogs are chasing three cats"

# 使用nltk的分词器对句子进行分词
words = word_tokenize(sentence)

# 打印原始单词列表
print(f'词目还原前: {words}')

# 词形还原后的单词列表
lemmatized_words = []

# 遍历单词列表,进行词形还原
for word in words:
    # 词形还原时需要确定词性,这里暂时使用名词(NOUN)作为示例
    lemmatized_words.append(lemmatizer.lemmatize(word, pos=wordnet.NOUN))

# 打印词形还原后的单词列表
print(f'词目还原后: {lemmatized_words}')

        代码结果如下:
 

D:\ana\envs\nlp\python.exe D:\pythoncode\nlp\cihuanyuan2.py 
[nltk_data] Error loading punkt: <urlopen error [Errno 11004]
[nltk_data]     getaddrinfo failed>
[nltk_data] Error loading wordnet: <urlopen error [Errno 11004]
[nltk_data]     getaddrinfo failed>
词目还原前: ['Two', 'dogs', 'are', 'chasing', 'three', 'cats']
词目还原后: ['Two', 'dog', 'are', 'chasing', 'three', 'cat']

进程已结束,退出代码为 0

        更精确的词目还原基于语素分析( morphological parsing)。在语言学中, 语素( morpheme)是语言中最小的有意义或有语法功能的单位。以中文为例,“动”“手”和“学”这3个语素就组合成了“动手学”这个词。在英文中, 情况会有些不一样, 英文中的很多单词是由词干( stem)和词缀( affix) 组成的。词干是表达主要含义的语素, 而词缀一般和词干连接,表达了附加的含义。例如 unbelievable这个词,由“ un”(词缀, 表示否定)、“ believ”(表示 believe,词干,表示相信)和“ able”(词缀, 表示可能的) 组成,三者合起来的意思是“不可置信的”。想要准确地抽取出词的词根和词干,就需要使用语素分析。

1.3 词干还原

        词干还原( stemming)是将词变成词干的过程。词干还原是一种简单快速的词目还原的方式, 通过将所有的词缀直接移除来获取词干。为了保持词干的完整性, 波特词干还原器提出了一套基于改写规则的方法来进行词干还原。例如:
                        · TIONAL -> TION (如(conditional->condition);
                        · IZATION->IZE (如(organization>organize);
                        · SSES ->SS(如(classes→class)。
        读者如果对这部分有兴趣的话,可以查阅NLTK 中对词干还原相关的描述。

2. 聚类模型分享

2.1 无监督的朴素贝叶斯模型

        朴素贝叶斯模型假设一个文档中的所有词都是在给定文档标签的条件下独立同分布地通过一个离散分布生成。朴素贝叶斯模型定义文档x_{i}的概率如下:
                        P(x_{i})= \sum \limits _{k=1}^{K} \pi _{k}P(x_{i}| \psi _{k})= \sum \limits _{k=1}^{K} \pi _{k} \prod \limits _{j=1}^{w_{i}}Multi(x_{i,j}| \psi k)
        其中, πₖ是第k个簇的混合系数, ψₖ是第k个簇的离散分布(记为 Multi)的参数,表示为\pi_{k} \psi_{k} = (p_{k,1}, p_{k,2}, \ldots, p_{k,\nu}),v为词表大小。w_{i}为当前文档x_{i}的长度,x_{i,j}表示文档x_{i}中的第j个词。

    将朴素贝叶斯模型用于文本分类时,文档标签是包含在数据中的, 因此可以进行监督学习。但在聚类任务中, 文档标签(即文档所属的簇)是未知的。因此, 与高斯混合模型的学习类似,我们需要同时学习朴素贝叶斯模型的参数和文档标签。常见的学习目标依然是最大化所有文档的概率,优化方法同样是最大期望值算法, 即随机初始化所有参数, 然后交替运行E步骤和M步骤直到模型收敛。
        1. E步骤
        计算每个文档的标签分布,将文档基于该分布部分地分配给各个标签:
                     P(y_{i}=k|x_{i}, \theta ^{(t)}) \propto \pi _{k}^{(t)} \prod \limits _{j=1}^{w_{i}}Multi(x_{i,j}| \psi _{k}^{(t)})
        其中, 上标(t)用于标示迭代次数, \theta^{t}为第t次迭代中的模型参数。
        2. M步骤
        根据每个标签被分配到的数据点进行加权最大似然估计,更新该标签对应的参数。首先,更新离散分布中每个词l的概率p_{k,l}^{(t+1)}:
                                ​​​​​​​        ​​​​​​​p_{k,l}^{(t+1)}= \frac { \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)}) \sum \limits _{j} \hbar (x_{i,j}=l)}{ \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})w_{i'}}
        其中, 1()在括号内等式成立时为1,否则为0。这个公式的分子计算的是加权分配到第k个标签的所有文档中出现词1的加权总次数,分母计算的是加权分配到第k个标签的所有文档的总词数。其次, 还需要更新每个标签的混合系数\pi _{k}^{(t+1)},更新公式与5.2节基于高斯混合模型的最大期望值算法的M步骤对应公式完全相同:
                ​​        ​​​​​       ​​​​​​​        ​​     ​     ​​​​​​​\pi _{k}^{(t+1)}= \frac { \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})}{m}
        其中, m为文档x的总个数。

        算法代码演示:

from scipy.special import logsumexp

# 无监督朴素贝叶斯
class UnsupervisedNaiveBayes:
    def __init__(self, K, dim, max_iter=100):
        self.K = K
        self.dim = dim
        self.max_iter = max_iter
        
        # 初始化参数,pi为先验概率分布,P用于保存K个朴素贝叶斯模型的参数
        self.pi = np.ones(K) / K
        self.P = np.random.random((K, dim))
        self.P /= self.P.sum(axis=1, keepdims=True)
        
    # E步骤
    def E_step(self, X):
        # 根据朴素贝叶斯公式,计算每个数据点分配到每个簇的概率分布
        for i, x in enumerate(X):
            # 由于朴素贝叶斯使用了许多概率连乘,容易导致精度溢出,
            # 因此使用对数概率
            self.Y[i, :] = np.log(self.pi) + (np.log(self.P) *\
                x).sum(axis=1)
            # 使用对数概率、logsumexp和exp,等价于直接计算概率,
            # 好处是数值更加稳定
            self.Y[i, :] -= logsumexp(self.Y[i, :])
            self.Y[i, :] = np.exp(self.Y[i, :])
    
    # M步骤
    def M_step(self, X):
        # 根据估计的簇概率分布更新先验概率分布
        self.pi = self.Y.sum(axis=0) / self.N
        self.pi /= self.pi.sum()
        # 更新每个朴素贝叶斯模型的参数
        for i in range(self.K):
            self.P[i] = (self.Y[:, i:i+1] * X).sum(axis=0) / \
                (self.Y[:, i] * X.sum(axis=1)).sum()
        # 防止除0
        self.P += 1e-10
        self.P /= self.P.sum(axis=1, keepdims=True)
    
    # 计算对数似然,用于判断迭代终止
    def log_likelihood(self, X):
        ll = 0
        for x in X:
            # 使用对数概率和logsumexp防止精度溢出
            logp = []
            for i in range(self.K):
                logp.append(np.log(self.pi[i]) + (np.log(self.P[i]) *\
                    x).sum())
            ll += logsumexp(logp)
        return ll / len(X)
    
    # 无监督朴素贝叶斯的迭代循环
    def fit(self, X):
        self.N = len(X)
        self.Y = np.zeros((self.N, self.K))
        ll = self.log_likelihood(X)
        print(f'初始化log-likelihood = {ll:.4f}')
        print('开始迭代')
        for i in range(self.max_iter):
            self.E_step(X)
            self.M_step(X)
            new_ll = self.log_likelihood(X)
            print(f'第{i}步, log-likelihood = {new_ll:.4f}')
            if new_ll - ll < 1e-4:
                print('log-likelihood不再变化,退出程序')
                break
            else:
                ll = new_ll
    
    def transform(self, X):
        assert hasattr(self, 'Y') and len(self.Y) == len(X)
        return np.argmax(self.Y, axis=1)
    
    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

2.2基于高斯混合模型的最大期望值算法

        这里首先介绍高斯混合模型,然后介绍用于无监督学习高斯混合模型的最大期望值算法。

2.2.1 高斯混合模型

        相比于将每个数据点确定性地分类到一个簇中,给出每个数据点归属于每个簇的概率分布会更好地体现数据点和簇之间的关系。这里使用高斯混合模型来建模这个概率分布。顾名思义,高斯混合是指多个高斯分布(即正态分布) 函数的组合, 它的概率密度函数如下:
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        P(x)= \sum \limits _{k=1}^{K} \pi _{k} \mathcal V(x| \mu _{k}, \sum \limits k)
        其中, πₖ是混合系数, 满足\pi _{k} \ge 0, \sum \limits _{k=1}^{K} \pi _{k}=1。也就是说, πₖ表示一个离散分布。N(x|μₖ,∑ₖ)是第k个高斯函数,其中μₖ为均值,维度与数据点x的维度一样,记作d, ∑为协方差矩阵,维度为d×d。N (x|μₖ,∑k)的具体概率密度函数为
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        \mathcal M(x| \mu k,E_{k})= \frac { \exp (- \frac {1}{2}(x- \mu k)^{ \tau } \sum \limits ^{-1}(x- \mu k))}{ \sqrt {(2 \pi )^{d}| \sum \limits |}}
        其中, |∑|为协方差矩阵∑的行列式。
        高斯混合也可以理解为一个生成式模型, 通过两个步骤生成数据点x。令变量y表示数据点x的标签,即x是从哪一个高斯函数采样得到的。第一步, 根据概率分布πₖ采样,令y=k; 第二步, 根据高斯分布. N(x|μₖ,∑ₖ)生成数据点。不难发现, 通过这个过程生成数据点x的概率密度函数即是前面定义的高斯混合。

        在高斯混合用于聚类时, 每个高斯函数对应一个簇, 而每个数据点的标签则表示该数据点属于哪一个簇。在文本聚类这样的无监 贝叶斯网络督任务中,我们既不知道高斯混合的参数(即混合系数πₖ、均值μₖ和协方差∑ₖ),也不知道每个数据点的标签,因此需要同时学习这两者。常见的学习目标为最大化所有数据点的边际概率:
        ​​​​​​​        ​​​​​​​        \prod \limits _{i=1}^{N}P(x_{i})= \prod \limits _{i=1}^{N} \sum \limits _{k=1}^{K}P(y_{i}=k,x_{i})= \prod \limits _{i=1}^{N} \sum \limits _{k=1}^{K} \pi _{k} \mathcal M(x_{i}| \mu _{k}, \sum \limits _{k})
        其中, N是数据集大小。那么如何优化这个目标函数呢? 最常见的方法是最大期望值算法。

2.2.1 最大期望值算法

        最大期望值算法首先随机初始化高斯混合模型的所有参数,然后交替运行E步骤和M步骤,直到模型收敛(常见判断标准是边际概率不再显著增加)。

        1. E步骤
        E步骤将每个数据点按照一定的权重部分地分配给不同的高斯函数。我们将这些权重定义为该数据点被分配到各个高斯函数的概率, 即该数据点的标签的概率分布:
         ​​​​​​​        ​​​​​​​        P(y_{i}=k|x_{i}, \theta ^{(t)}) \propto \pi _{k}^{(t)} \mathcal N(x_{i}| \mu _{k}^{(t)}, \sum \limits _{k}^{(t)})
        其中, 上标(t)用于标示第t次迭代时模型的参数,θ⁽ᵗ⁾为模型参数(即所有的\pi _{k}^{(t)}、 \mu _{k}^{(t)}\sum \limits _{k}^{(t)})。

        2. M步骤

        M步骤需要为每个高斯函数计算新的参数, 基本思想是根据每个高斯函数被分配到的数据点进行最大似然估计。由于每个数据点都是按一定的权重分配给每个高斯函数, 因此这里的最大似然估计也是加权的。这种加权最大似然估计存在以下闭式解:
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​\mu _{k}^{(t+1)}= \frac { \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})x_{i}}{ \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})}
        上述公式将分配到第k个高斯函数的数据点进行加权平均。
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​\sum \limits _{k}= \frac { \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})(x_{i}- \mu _{i}^{(t+1)})(x_{i}- \mu _{i}^{(t+1)})^{T}}{ \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})}
        上述公式将分配到第k个高斯函数的数据点计算加权的协方差矩阵。
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        \pi _{k}^{(t+1)}= \frac { \sum \limits _{i}P(y_{i}=k|x_{i}, \theta ^{(t)})}{m}
        其中, m是数据点的总个数。上述公式计算分配到第k个高斯函数的数据点个数占所有数据点个数的比例。由于每个数据点是按权重部分地分配给每个高斯函数的,因此数据点个数的计算方式是对权重求和。
        通过E步骤和M步骤,我们就拥有了一个完整的最大期望值算法的过程。最大期望值算法具体细节不再展开,有兴趣的读者可以参考相关的机器学习教材。

2.2.3 最大期望值算法与k均值聚类算法的关联

        如果为最大期望值算法假设两个限定条件:
        (1)所有高斯模型都为球状(即协方差矩阵等比于单位矩阵),且权重和协方差均相同,只有均值是可变化的参数;
        (2)E步骤中计算的标签概率分布均为点估计,也就是说强制将每个数据点分配给单个高斯模型, 这等价于假设所有的方差均无限接近于0。
        我们就会发现, 最大期望值算法等价于k均值聚类算法。
        接下来演示如何使用高斯混合模型来进行聚类。注意,高斯混合模型会计算每个数据点归属于各个族的概率分布,这里将概率最大的族作为聚类输出。

        

from scipy.stats import multivariate_normal as gaussian
from tqdm import tqdm

# 高斯混合模型
class GMM:
    def __init__(self, K, dim, max_iter=100):
        # K为聚类数目,dim为向量维度,max_iter为最大迭代次数
        self.K = K
        self.dim = dim
        self.max_iter = max_iter
        
        # 初始化,pi = 1/K为先验概率,miu ~[-1,1]为高斯分布的均值,
        # sigma = eye为高斯分布的协方差矩阵
        self.pi = np.ones(K) / K
        self.miu = np.random.rand(K, dim) * 2 - 1
        self.sigma = np.zeros((K, dim, dim))
        for i in range(K):
            self.sigma[i] = np.eye(dim)
        
    # GMM的E步骤
    def E_step(self, X):
        # 计算每个数据点被分到不同簇的密度
        for i in range(self.K):
            self.Y[:, i] = self.pi[i] * gaussian.pdf(X, \
                mean=self.miu[i], cov=self.sigma[i])
        # 对密度进行归一化,得到概率分布
        self.Y /= self.Y.sum(axis=1, keepdims=True)
    
    # GMM的M步骤
    def M_step(self, X):
        # 更新先验概率分布
        Y_sum = self.Y.sum(axis=0)
        self.pi = Y_sum / self.N
        # 更新每个簇的均值
        self.miu = np.matmul(self.Y.T, X) / Y_sum[:, None]
        # 更新每个簇的协方差矩阵
        for i in range(self.K):
            # N * 1 * D
            delta = np.expand_dims(X, axis=1) - self.miu[i]
            # N * D * D
            sigma = np.matmul(delta.transpose(0, 2, 1), delta)
            # D * D
            self.sigma[i] = np.matmul(sigma.transpose(1, 2, 0),\
                self.Y[:, i]) / Y_sum[i]
    
    # 计算对数似然,用于判断迭代终止
    def log_likelihood(self, X):
        ll = 0
        for x in X:
            p = 0
            for i in range(self.K):
                p += self.pi[i] * gaussian.pdf(x, mean=self.miu[i],\
                    cov=self.sigma[i])
            ll += np.log(p)
        return ll / self.N
    
    # 运行GMM算法的E步骤、M步骤迭代循环
    def fit(self, X):
        self.N = len(X)
        self.Y = np.zeros((self.N, self.K))
        ll = self.log_likelihood(X)
        print('开始迭代')
        for i in range(self.max_iter):
            self.E_step(X)
            self.M_step(X)
            new_ll = self.log_likelihood(X)
            print(f'第{i}步, log-likelihood = {new_ll:.4f}')
            if new_ll - ll < 1e-4:
                print('log-likelihood不再变化,退出程序')
                break
            else:
                ll = new_ll
    
    # 根据学习到的参数将一个数据点分配到概率最大的簇
    def transform(self, X):
        assert hasattr(self, 'Y') and len(self.Y) == len(X)
        return np.argmax(self.Y, axis=1)
    
    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

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

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

相关文章

开发高质量PDF应用的不二选择:PdfiumViewer库详细解析

1. PdfiumViewer库简介 PdfiumViewer是一款基于谷歌开源PDF渲染引擎PDFium的.NET库&#xff0c;主要用于在Windows应用程序中显示和处理PDF文档。PdfiumViewer提供了多种API和控件&#xff0c;使得开发者可以轻松地将PDF文档嵌入到其应用程序中。同时&#xff0c;PdfiumViewer…

利用 OCR 和强大的 GPT-4o 迷你模型对收据进行信息提取

在本文中&#xff0c;我将向您展示如何从收据中提取信息&#xff0c;并提供收据的简单图像。首先&#xff0c;我们将利用 OCR 从收据中提取信息。然后&#xff0c;此信息将发送到 GPT-4o 迷你模型进行信息提取。我在这个项目中的目标是开发一个应用程序&#xff0c;只需拍摄收据…

【排序算法】八大排序(下)(c语言实现)(附源码)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;算法 目录 前言 测试数据和交换函数 五、堆排序 六、快速排序 1.hoare版本 2.挖坑法 3.lomoto版本 4.快速排序的非递归实现 5.快速排序性能总结 七、归…

手机mkv转换mp4:轻松实现视频格式兼容

如今手机已成为我们日常生活中不可或缺的伴侣&#xff0c;而视频文件则是我们享受娱乐、获取信息的重要来源。然而&#xff0c;由于不同设备和平台对视频格式的支持各有不同&#xff0c;我们有时会遇到无法在手机上播放某些视频文件的问题。 mkv是一种常见的视频格式&#xff…

android使用YOLOV8数据返回到JAVA方法(JAVA)

一、下载扩展文件(最耗时,所以放第一步) 1.opencv下载 1)官网:Releases - OpenCV 2)下载最新版本的android包 2.NCNN下载 1)NCNN下载地址(20220420版本):https://github.com/Tencent/ncnn/releases/download/20220420/ncnn-20220420-android-vulkan.zip 3.在你的…

倍内菲新品发布揭示宠物营养新纪元,引领行业保驾护航

2024年8月21日&#xff0c;伴随着第26届亚洲宠物展览会的揭幕&#xff0c;宠物主粮领军品牌倍内菲在展会首日举行了一场意义深远的新品发布会&#xff0c;重磅推出两款革命性新品——鲜肉烘焙系列与至护烘焙系列&#xff0c;不仅是对宠物进阶营养需求的深刻洞察&#xff0c;更是…

【信创】统信UOS打包工具介绍与使用教程

原文链接&#xff1a;【信创】统信UOS打包工具介绍与使用教程 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于统信UOS桌面操作系统上的UOS打包工具介绍与使用的文章。UOS打包工具是一款专为统信UOS系统开发的应用程序打包工具&#xff0c;旨在帮助开发者轻松创建…

Vue.js:解锁前端开发的快速入门之旅

标题&#xff1a;《Vue.js&#xff1a;解锁前端开发的快速入门之旅》 在日新月异的Web开发领域中&#xff0c;Vue.js以其简洁、灵活和高效的特点&#xff0c;迅速成为前端开发者们的宠儿。对于初学者而言&#xff0c;Vue.js不仅是一个易于上手的框架&#xff0c;更是开启现代前…

python动画:颜色(color)能接受的[manim_colors]

Manim_colors指的是Manim动画引擎中全局命名空间中包含的一组颜色。这些颜色构成了Manim默认的颜色空间。通过使用manim_colors&#xff0c;动画师和创作者可以轻松地访问和应用各种颜色到他们的动画中&#xff0c;而无需单独定义它们。这个特性简化了动画制作的过程&#xff0…

张宇线代9讲啃不动,换李永乐来得及吗?

快9月了&#xff0c;很多同学在后台留言说&#xff0c;跟宇哥的线代&#xff0c;但是啃不动&#xff0c;接下来该怎么办&#xff0c;换李永乐来的急吗&#xff1f; 让我来认真分析一下&#xff01; 张宇线代9讲为什么这么难啃&#xff1f; 25版张宇线代改版&#xff0c;线代的…

二叉树【2.5】代码专项

目录 醍醐灌顶——node* root 和node* &root作为参数的区别 return value&#xff1a; 写一个前序遍历的&#xff08;使用指针&#xff09; 中序遍历&#xff0c;只改动了preorder&#xff0c;只调换了一行 后序 层序&#xff08;使用bfs&#xff09;&#xff0c;新建队…

如何保证支付服务和交易服务订单状态一致?

消息传给消费者&#xff0c;消费者自己弄丢 业务幂等 所有的业务都应该保证幂等性&#xff0c; 如何保障业务幂等性 非幂等业务表单重复提交&#xff0c;在进入表单之前生成唯一标识&#xff0c;未token&#xff0c;携带token进行请求&#xff0c;执行表单提交&#xff0c;把…

unoredered_mapunordered_set封装

各层封装关系 封装时细节/tips Rfr Ptr用来constiterator //HTIterator 模板 template<class K, class T, class Ptr, class Rfr, class KeyOfT, class Hash> class HTIterator//普通Iterator类 & const_iterator类 typedef HTIterator<K, T, T*, T&, KeyOfT…

芯片中的电源VDD和地VSS

一、原理图中的电源和地符号 在绘制原理图的时候您应该会发现某个芯片上有VBAT VDD VSS VDDA VSSA那么他们都是什么意思呢&#xff0c;分别代表什么&#xff1f; 二、与常说的VCC的区别 可以看到VSS是表示GND 数字和模拟是分开的默认是数字&#xff0c;VDD表示电源&#xff0c;…

DC-DC开关电源稳压电路设计——7- 40V转换5V和3.3V

本篇文章记录分享DC-DC开关电源稳压&#xff08;7-40V转换5V和3.3V&#xff09;电路设计的思路及原理图。 目录 一、电路稳压原理图 二、开关稳压芯片 1、BUCK降压电路 2.LM2596 &#xff08;1&#xff09;、LM2596简介 &#xff08;2&#xff09;、LM2596原理 1. 基…

Python计算机视觉 第3章-图像到图像的映射

Python计算机视觉 第3章-图像到图像的映射 3.1 单应性变换 单应性变换&#xff08;Homography&#xff09;是计算机视觉中非常重要的一种几何变换&#xff0c;它用于将一个平面内的点映射到另一个平面内。具体来说&#xff0c;单应性变换可以描述一个图像在摄像机视角变化、…

音视频封装格式之FLV

FLV&#xff08;Flash Video&#xff09;是一种常见的视频文件格式&#xff0c;FLV 格式最初是由 Adobe 公司开发的&#xff0c;旨在为网络视频提供一种高效、可扩展且易于流式传输的解决方案。随着在线视频的迅速发展&#xff0c;FLV 因其良好的兼容性和流式传输性能&#xff…

4.2较难的栈和队列OJ

本篇博客来手撕三道稍有难度的栈和队列相关OJ&#xff0c;题目均已插入超链接&#xff0c;点击即可跳转~ 一、设计循环队列 1、题目描述 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff0c;即first in fir…

day39.动态规划+MySQL数据库复习

一.动态规划: 198.打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定…

深入浅出消息队列----【Broker 集群】

深入浅出消息队列----【Broker 集群】 单 master多 master多 master 多 slave 异步复制多 master 多 slave 同步复制Dledger 本文仅是文章笔记&#xff0c;整理了原文章中重要的知识点、记录了个人的看法 文章来源&#xff1a;编程导航-鱼皮【yes哥深入浅出消息队列专栏】 Brok…