[监督学习] 朴素贝叶斯法

朴素贝叶斯(naive Bayes)法是基于贝叶斯定理与特征条件独立假设的分类法。

方法适用问题模型特点模型类型学习策略学习的损失函数学习算法
朴素贝叶斯法多类分类特征与类别的联合概率分布,条件独立假设生成模型极大似然估计,极大后验概率估计对数似然损失概率计算公式,EM算法

1 前言

说到朴素贝叶斯算法,首先牵扯到的两个概念是判别式生成式
  (1) 判别式:就是直接学习出特征输出Y和特征X之间的关系,如决策函数 Y = f ( X ) Y=f(X) Y=f(X),或者从概率论的角度,求出条件分布 P ( Y ∣ X ) P(Y|X) P(YX)。代表算法有决策树K近邻算法逻辑斯谛回归支持向量机随机条件场CRF等。
  (2) 生成式:就是直接找出特征输出Y和特征X的联合分布 P ( Y ∣ X ) P(Y|X) P(YX),然后用 P ( Y ∣ X ) = P ( X , Y ) P ( X ) P\left( {Y|X} \right) = \frac{{P\left( {X,Y} \right)}}{{P\left( X \right)}} P(YX)=P(X)P(X,Y)得出。代表算法有朴素贝叶斯隐式马尔可夫链等。

2 朴素贝叶斯原理

由于朴素贝叶斯原理式基于贝叶斯定理特征条件独立假设,下面引入这两种定理的概念。

2.1 贝叶斯定理

贝叶斯公式:
                        P ( B ∣ A ) = P ( A ∣ B ) ∗ P ( B ) P ( A ) P\left( {B|A} \right) = \frac{{P\left( {A|B} \right)*P\left( B \right)}}{{P\left( A \right)}} P(BA)=P(A)P(AB)P(B)
按照乘法法则,贝叶斯公式可以这样推导出:
                  P ( A ∩ B ) = P ( A ) ∗ P ( B ∣ A ) = P ( B ) ∗ P ( A ∣ B ) P\left( {A \cap B} \right) = P\left( A \right)*P\left( {B|A} \right) = P\left( B \right)*P\left( {A|B} \right) P(AB)=P(A)P(BA)=P(B)P(AB)

按这些术语,贝叶斯法则可文字表述为:
后验概率 = (似然度 ∗ * 先验概率) / / /标准化常量, 也就是说,后验概率与先验概率和似然度的乘积成正比。
通常,后验概率 = 标准似然度 * 先验概率。
  标准似然度(standardised likelihood) P ( A ∣ B ) / P ( A ) P(A|B)/P(A) P(AB)/P(A)
  先验概率 P ( B ) P(B) P(B)

在贝叶斯法则中,其他约定俗成的名称有:
    P ( B ) P(B) P(B)是B的先验概率或边缘概率。之所以称为"先验"是因为它不考虑任何A方面的因素。
    P ( A ∣ B ) P(A|B) P(AB)是已知B发生后A的条件概率,也由于得自B的取值而被称作A的后验概率。
    P ( B ∣ A ) P(B|A) P(BA)是已知A发生后B的条件概率,也由于得自A的取值而被称作B的后验概率。
可以这么说:
  条件概率又称为后验概率
  边缘概率又称为先验概率

2.2 特征条件独立假设

特征条件独立假设X的n个特征在类确定的条件下都是条件独立的,特征之间发生的概率相互独立。这样可以大大简化了计算过程,但是因为这个假设太过严格,所以会相应牺牲一定的准确率。这也是为什么称呼为朴素的原因。

3 朴素贝叶斯算法

输入:训练集为m个样本n个维度 T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) T = \left( {{x_1},{y_1}} \right),\left( {{x_2},{y_2}} \right),...,\left( {{x_m},{y_m}} \right) T=(x1,y1),(x2,y2),...,(xm,ym),共有K个特征输出类别,分别为 y ∈ { c 1 , c 2 , . . . , c K } y \in \left\{ {{c_1},{c_2},...,{c_K}} \right\} y{c1,c2,...,cK}
输出:为实例 x ( t e s t ) x(test) x(test)的分类。

算法流程如下
   1 首先计算Y的K个先验概率
                     P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) N P\left( {Y = {c_k}} \right) = \frac{{\sum\limits_{i = 1}^N {I\left( {{y_i} = {c_k}} \right)} }}{N} P(Y=ck)=Ni=1NI(yi=ck)
   2 然后计算条件概率分布:
              P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , X ( 2 ) = x ( 2 ) , . . . , X ( n ) = x ( n ) ∣ Y = c k ) P\left( {X = x|Y = {c_k}} \right) = P\left( {{X^{\left( 1 \right)}} = {x^{\left( 1 \right)}},{X^{\left( 2 \right)}} = {x^{\left( 2 \right)}},...,{X^{\left( n \right)}} = {x^{\left( n \right)}}|Y = {c_k}} \right) P(X=xY=ck)=P(X(1)=x(1),X(2)=x(2),...,X(n)=x(n)Y=ck)
如果没有特征条件独立假设的条件,需要求出特征一 X ( 1 ) = x ( 1 ) {X^{(1)}=x^{(1)}} X(1)=x(1)下的特征二 X ( 2 ) = x ( 2 ) {X^{(2)}=x^{(2)}} X(2)=x(2),一直到最后一个特征 X ( n ) = x ( n ) {X^{(n)}=x^{(n)}} X(n)=x(n)的概率分布,加上独立假设的条件后,只需要求 Y = c k Y = {c_k} Y=ck条件发生的情况下,各个特征发生的概率最后的乘积。可以化简为:
                P ( X = x ∣ Y = c k ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P\left( {X = x|Y = {c_k}} \right) = \prod\limits_{j = 1}^n {P\left( {{X^{\left( j \right)}} = {x^{\left( j \right)}}|Y = {c_k}} \right)} P(X=xY=ck)=j=1nP(X(j)=x(j)Y=ck)
  3 根据贝叶斯原理,计算后验概率:
                P ( Y = c k ∣ X = x ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) ∑ k P ( X = x ∣ Y = c k ) P ( Y = c k ) P\left( {Y = {c_k}|X = x} \right) = \frac{{P\left( {X = x|Y = {c_k}} \right)P\left( {Y = {c_k}} \right)}}{{\sum\nolimits_k {P\left( {X = x|Y = {c_k}} \right)P\left( {Y = {c_k}} \right)} }} P(Y=ckX=x)=kP(X=xY=ck)P(Y=ck)P(X=xY=ck)P(Y=ck)
带入 P ( X = x ∣ Y = c k ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P\left( {X = x|Y = {c_k}} \right) = \prod\limits_{j = 1}^n {P\left( {{X^{\left( j \right)}} = {x^{\left( j \right)}}|Y = {c_k}} \right)} P(X=xY=ck)=j=1nP(X(j)=x(j)Y=ck)
得到:
                P ( Y = c k ∣ X = x ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P ( Y = c k ) ∑ k P ( X = x ∣ Y = c k ) P ( Y = c k ) P\left( {Y = {c_k}|X = x} \right) = \frac{{\prod\limits_{j = 1}^n {P\left( {{X^{\left( j \right)}} = {x^{\left( j \right)}}|Y = {c_k}} \right)} P\left( {Y = {c_k}} \right)}}{{\sum\nolimits_k {P\left( {X = x|Y = {c_k}} \right)P\left( {Y = {c_k}} \right)} }} P(Y=ckX=x)=kP(X=xY=ck)P(Y=ck)j=1nP(X(j)=x(j)Y=ck)P(Y=ck) 
由于每类判断的分母相同,上式再变为如下:
               P ( X = x ∣ Y = c k ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P ( Y = c k ) P\left( {X = x|Y = {c_k}} \right) = \prod\limits_{j = 1}^n {P\left( {{X^{\left( j \right)}} = {x^{\left( j \right)}}|Y = {c_k}} \right)} P\left( {Y = {c_k}} \right) P(X=xY=ck)=j=1nP(X(j)=x(j)Y=ck)P(Y=ck) 
  4 计算 x ( t e s t ) x(test) x(test)的类别
               y ( t e s t ) = arg ⁡ max ⁡ c k ∏ j = 1 n P ( X ( j ) = x ( t e s t ) j ∣ Y = c k ) P ( Y = c k ) y\left( {test} \right) = \arg {\max _{{c_k}}}\prod\limits_{j = 1}^n {P\left( {{X^{\left( j \right)}} = x_{\left( {test} \right)}^j|Y = {c_k}} \right)} P\left( {Y = {c_k}} \right) y(test)=argmaxckj=1nP(X(j)=x(test)jY=ck)P(Y=ck)

4 贝叶斯估计

用极大似然估计可能会出现所要估计的概率值为0的情况。即在某种特征的条件概率P(B|A) = P(A|B)*P(B) / P(A)为0,使得计算分类的结果为0,产生偏差。
  解决这一问题的方法是采用贝叶斯估计。具体地,在随机变量的各个取值的频数上赋予一个正数X,使得某种特征至少出现一次。 
  修改算法后
先验概率的贝叶斯估计
                    P λ ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) + λ N + K λ {P_\lambda }\left( {Y = {c_k}} \right) = \frac{{\sum\limits_{i = 1}^N {I\left( {{y_i} = {c_k}} \right) + \lambda } }}{{N + K\lambda }} Pλ(Y=ck)=N+Kλi=1NI(yi=ck)+λ
条件概率的贝叶斯估计
                  P λ ( X ( j ) = a j i ∣ Y = c k ) = ∑ i = 1 N I ( x ( j ) = a j i ∣ y i = c k ) + λ ∑ i = 1 N I ( y i = c k ) + S j λ {P_\lambda }\left( {{X^{\left( j \right)}} = {a_{ji}}|Y = {c_k}} \right) = \frac{{\sum\limits_{i = 1}^N {I\left( {{x^{\left( j \right)}} = {a_{ji}}|{y_i} = {c_k}} \right) + \lambda } }}{{\sum\limits_{i = 1}^N {I\left( {{y_i} = {c_k}} \right) + {S_j}\lambda } }} Pλ(X(j)=ajiY=ck)=i=1NI(yi=ck)+Sjλi=1NI(x(j)=ajiyi=ck)+λ

5 朴素贝叶斯的优点和缺点

优点:
1 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
2 对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。
3 对缺失数据不太敏感,算法也比较简单,常用于文本分类。
缺点 :
1 朴素贝叶斯模型的特征条件独立假设在实际应用中往往是不成立的。
2 如果样本数据分布不能很好的代表样本空间分布,那先验概率容易测不准。
3 对输入数据的表达形式很敏感。

6 朴素贝叶斯算法实现及案例

6.1 朴素贝叶斯算法实现

依据《统计学习方法》中的课本案例,用Python来实现朴素贝叶斯算法。

# coding:utf-8
import numpy as np

class Bayes():
    def create_vocab_list(self, dataSet):  # 创建词汇表 create vocab list, like[1, 2, 3, 'S', 'M', 'L']
        vocab_set = set()  # 定义一个set()对象,用于求并集
        for document in dataSet:
            vocab_set = vocab_set | set(document)
        print('训练数据的所有特征:', vocab_set)
        return list(vocab_set)

    def set_of_word2vec(self, vocab_list, input_set):   # 词条向量 return feature vector, like a feature vector is [1, 'S']if vocab_list is [1, 2, 3, 'S', 'M', 'L']return vocab vector [1, 0, 0, 1, 0, 0]
        vocab_vec = [0] * len(vocab_list)    # vocablist大小的零向量 zero vector
        for word in input_set:   # 遍历输入样本的每个特征   iterating every feature
            if word in vocab_list:
                vocab_vec[vocab_list.index(word)] = 1    # 如果发现有匹配的"word"就设置为1
        return vocab_vec

    def train(self, dataSet, labels):   # 训练样本 train
        self._vocab_list = self.create_vocab_list(dataSet)  # 创建特征词汇表 create vocab list
        train_matrix = []    # 多条词条向量的矩阵(一个词条向量代表着一个样本在词条中出现的次数) matrix consists of vocab vector
        for line in dataSet:    # 将每个训练样本转换为词条向量 feature vector to vocab vector
            train_matrix.append(self.set_of_word2vec(self.vocab_list, line))
        train_matrix = np.array(train_matrix)  # 将多条词条向量转化成ndarray矩阵

        n = len(self.vocab_list)  # 词条的特征数   feature num
        negative_feature_num = np.zeros(n)     # 在类别为-1时,出现特征的次数向量(n1 means negative 1,the vector of counting num of every feature when label equal -1
        positve_feature_num = np.zeros(n)    # 在类别为1时,出现特征的次数向量()
        negative_num = 0    # 标签中出现-1的次数
        positive_num = 0    # 标签中出现1的次数

        for i in range(len(train_matrix)):  # len(train_matrix) = 15
            if labels[i] == 1:
                positive_num += 1
                positve_feature_num += train_matrix[i]
            else:
                negative_feature_num += train_matrix[i]  # 与词条向量相加
                negative_num += 1

        self._positive_vec = positve_feature_num / positive_num   #类别为1的各个随机向量(特征)的概率分布    the probability of feture num
        self._negative_vec = negative_feature_num / negative_num
        self._p_positive = positive_num / float(len(labels)) #p(y=1)的概率 the probability of positive label
        # return self._positive_vec, self._negative_vec, self._p_positive

    def predict(self, input_data):   # 预测函数
        input_vec = self.set_of_word2vec(self.vocab_list, input_data)  # 测试样本的词条向量
        p_positive = self.p_positive   # 按照公式需要乘以p(y=1)的值,我们就以此为初始值
        p_negative = (1 - self.p_positive)
        print('P(y=1)时,各特征的概率向量', np.multiply(self.positive_vec, input_vec))
        print('P(y=-1)时,各特征的概率向量', np.multiply(self.negative_vec, input_vec))
        for num in np.multiply(self.positive_vec, input_vec):  # 概率分布和词条向量进行相乘,得出p(x=xi|y=1)的概率,然后相乘
            if (num > 0):
                p_positive *= num
        for num in np.multiply(self.negative_vec, input_vec):
            if (num > 0):
                p_negative *= num
        print('属于y = 1的概率', p_positive)
        print('属于y = -1的概率', p_negative)
        if (p_positive > p_negative):  # 相比,谁大就倾向谁 up to max probability
            return 1
        else:
            return -1

    @property
    def vocab_list(self):
        return self._vocab_list

    @property
    def positive_vec(self):
        return self._positive_vec

    @property
    def negative_vec(self):
        return self._negative_vec

    @property
    def p_positive(self):
        return self._p_positive


if __name__ == "__main__":
    dataSet = [[1, "S"], [1, "M"], [1, "M"], [1, "S"], [1, "S"],
               [2, "S"], [2, "M"], [2, "M"], [2, "L"], [2, "L"],
               [3, "L"], [3, "M"], [3, "M"], [3, "L"], [3, "L"]]
    labels = [-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1]
    bayes = Bayes()
    bayes.train(dataSet, labels)
    print("prediction is:", bayes.predict([2, "S"]))

测试结果:

训练数据的所有特征: {'S', 1, 2, 3, 'L', 'M'}
P(y=1)时,各特征的概率向量 [0.11111111 0.         0.33333333 0.         0.         0.        ]
P(y=-1)时,各特征的概率向量 [0.5        0.         0.33333333 0.         0.         0.        ]
属于y = 1的概率 0.02222222222222222
属于y = -1的概率 0.06666666666666667
prediction is: -1

对于新的样本[2, “S”],通过朴素贝叶斯学习后,所属分类的标签为:-1

6.2 朴素贝叶斯-垃圾邮件分类

朴素贝叶斯 (naive Bayes) 法是基于贝叶斯定理与特征条件独立假设的分类的方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对于给定的输入x,利用贝叶斯定理求出后验概率最大的输出y。

这里也有关于朴素贝叶斯-垃圾邮件分类案例(基于文件处理): 垃圾邮件分类-Python.

学习输入及预测输入:

if __name__ == "__main__":
    # 垃圾邮件的内容
    posting_list = [
        ['my', 'dog', 'has', 'flea', 'problem', 'help', 'please'],
        ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
        ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
        ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
        ['mr', 'licks', 'ate', 'ny', 'steak', 'how', 'to', 'stop', 'him'],
        ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']
    ]
    # 是否是垃圾邮件的标签
    labels = [1, -1, 1, -1, 1, -1]
    bayes = Bayes()
    bayes.train(posting_list, labels)
    print("prediction is:", bayes.predict(['ny', 'licks']))

首先得根据上述文本建立一个词汇表,即把重复的词汇剔除。代码如下:

def createVocabList(self, dataSet):
    vocabSet = set()
    # 创建两个集合的并集
    for document in dataSet:
        vocabSet = vocabSet | set(document)
    return list(vocabSet)

然后需要把每句话转化为词袋模型(bag-of-words model):

def set_of_word2vec(self, vocab_list, input_set):   # 词条向量 return feature vector, like a feature vector is [1, 'S']if vocab_list is [1, 2, 3, 'S', 'M', 'L']return vocab vector [1, 0, 0, 1, 0, 0]
    vocab_vec = [0] * len(vocab_list)    # vocablist大小的零向量 zero vector
    for word in input_set:   # 遍历输入样本的每个特征   iterating every feature
        if word in vocab_list:
            vocab_vec[vocab_list.index(word)] = 1    # 如果发现有匹配的"word"就设置为1
    return vocab_vec

目前为止,我们把每份邮件转化成了一系列的向量形式,向量的长度是词表里面的词的个数,是稀疏矩阵。
接下去就是朴素贝叶斯的步骤了,也就是训练的过程:

def train(self, dataSet, labels):   # 训练样本 train
    self._vocab_list = self.create_vocab_list(dataSet)  # 创建特征词汇表 create vocab list
    train_matrix = []    # 多条词条向量的矩阵(一个词条向量代表着一个样本在词条中出现的次数) matrix consists of vocab vector
    for line in dataSet:    # 将每个训练样本转换为词条向量 feature vector to vocab vector
        train_matrix.append(self.set_of_word2vec(self.vocab_list, line))
    train_matrix = np.array(train_matrix)  # 将多条词条向量转化成ndarray矩阵

    n = len(self.vocab_list)  # 词条的特征数   feature num
    negative_feature_num = np.zeros(n)     # 在类别为-1时,出现特征的次数向量(n1 means negative 1,the vector of counting num of every feature when label equal -1
    positve_feature_num = np.zeros(n)    # 在类别为1时,出现特征的次数向量()
    negative_num = 0    # 标签中出现-1的次数
    positive_num = 0    # 标签中出现1的次数

    for i in range(len(train_matrix)):  # len(train_matrix) = 15
        if labels[i] == 1:
            positive_num += 1
            positve_feature_num += train_matrix[i]
        else:
            negative_feature_num += train_matrix[i]  # 与词条向量相加
            negative_num += 1

    self._positive_vec = positve_feature_num / positive_num   #类别为1的各个随机向量(特征)的概率分布    the probability of feture num
    self._negative_vec = negative_feature_num / negative_num
    self._p_positive = positive_num / float(len(labels)) #p(y=1)的概率 the probability of positive label
    # return self._positive_vec, self._negative_vec, self._p_positive

训练完了,剩下的是对新数据的预测过程:

def predict(self, input_data):   # 预测函数
    input_vec = self.set_of_word2vec(self.vocab_list, input_data)  # 测试样本的词条向量
    p_positive = self.p_positive   # 按照公式需要乘以p(y=1)的值,我们就以此为初始值
    p_negative = (1 - self.p_positive)
    # print('P(y=1)时,各特征的条件概率', np.multiply(self.positive_vec, input_vec))
    # print('P(y=-1)时,各特征的条件概率', np.multiply(self.negative_vec, input_vec))
    for num in np.multiply(self.positive_vec, input_vec):  # 概率分布和词条向量进行相乘,得出p(x=xi|y=1)的概率,然后相乘
        if (num > 0):
            p_positive *= num
    for num in np.multiply(self.negative_vec, input_vec):
        if (num > 0):
            p_negative *= num
    print('属于y = 1的概率', p_positive)
    print('属于y = -1的概率', p_negative)
    if (p_positive > p_negative):  # 相比,谁大就倾向谁 up to max probability
        return 1
    else:
        return -1

测试结果:

属于y = 1的概率 0.05555555555555555
属于y = -1的概率 0.5
prediction is: -1

对于样本[‘ny’, ‘licks’]的分类标签为:-1,即是侮辱性文档。

6.2 朴素贝叶斯-sklearn库

这里基于Python中sklearn库完成朴素贝叶斯分类器。

在sklearn库中,实现了三个朴素见叶斯分类器,如下表所示:

分类器描述
naive_bayes.GussianNB高斯朴素贝叶斯
naive_bayes.GussianNB针对多项式模型的朴素贝叶斯分类器
naive_bayes.GussianNB针对多元伯努利模型的朴素贝叶斯分类器

sklearn库中,可以使用sklearn.naive bayes.GaussianNB,创建一个高斯朴素贝叶斯分类器,其参数有:
  priors: 给定各个类别的先验概率。如果为空,则按训练数据的实际情况进行统计;如果给定先验概率,则在训练过程中不能更改。

导入numpy库,并构造训练数据X和y。

import numpy as np
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
Y = np.array([1, 1, 1, 2, 2, 2])

使用import语句导入朴素贝叶斯分类器。

# 使用import语句导入朴素贝叶斯分类器
from sklearn.naive_bayes import GaussianNB

使用默认参数,创建一个 高斯朴素贝叶斯分类器,并将该分类器赋给变量clf。

# 使用默认参数创建一个高斯朴素贝叶斯分类器,并将该分类器赋值给变量clf
clf = GaussianNB(priors= None)

类似的,使用fit()函数进行训练,并使用predict)函数进行预测,得到预测结果为1。( 测试时可以构造二维数组达到同时预测多个样本的目的)

clf.fit(X, Y)
test_data = clf.predict([[-0.8, -1], [4, 1]])
print('运用 朴素贝叶斯分类器 预测分类结果:',test_data)

完整程序:

import numpy as np
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
Y = np.array([1, 1, 1, 2, 2, 2])
# 使用import语句导入朴素贝叶斯分类器
from sklearn.naive_bayes import GaussianNB
# 使用默认参数创建一个高斯朴素贝叶斯分类器,并将该分类器赋值给变量clf
clf = GaussianNB(priors= None)
clf.fit(X, Y)
test_data = clf.predict([[-0.8, -1], [4, 1]])
print('运用 朴素贝叶斯分类器 预测分类结果:',test_data)

预测结果:

运用 朴素贝叶斯分类器 预测分类结果: [1 2]

朴素贝叶斯是典型的生成学习方法,由训练数据学习联合概率分布,并求得后验概率分布。朴素贝叶斯一般在小规模数据上的表现很好,适合进行多分类任务。

参考文献

[1] 周志华 《机器学习》
[2] 李航《统计学方法》

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值