机器学习实验报告——Bayes算法

目录

一、算法介绍

1.1算法背景

1.2算法假设

1.3 贝叶斯与朴素贝叶斯

1.4算法原理

二、算法推导

2.1朴素贝叶斯介绍

2.2朴素贝叶斯算法推导

2.2.1先验后验概率

2.2.2条件概率公式

2.3 独立性假设

2.4 朴素贝叶斯推导

三、算法实现

3.1数据集描述

3.2代码实现

四、实验讨论

4.1算法优缺点

4.2关于三种朴素贝叶斯算法使用场合的讨论

4.3关于朴素贝叶斯算法中拉普拉斯平滑修正的讨论

4.4朴素贝叶斯算法的应用

五、实验总结


一、算法介绍

1.1算法背景

贝叶斯算法(Bayesian algorithm)是一种基于贝叶斯公式的概率统计算法,也被称为贝叶斯分类器。它基于先验概率和后验概率之间的关系,通过对数据集进行训练来构建一个模型,并使用该模型对新的数据进行分类。

贝叶斯算法最早由英国数学家托马斯·贝叶斯(Thomas Bayes)在18世纪提出,但直到20世纪才得到广泛应用。贝叶斯算法的基本思想是利用已知的先验概率来计算后验概率,再根据后验概率来做出判断或预测。

1.2算法假设

贝叶斯算法假设的核心是基于贝叶斯定理和条件独立性的假设。下面是贝叶斯算法的主要假设:

(1)条件独立性假设:在朴素贝叶斯算法中,假设每个特征与其他特征之间是相互独立的,即给定类别的情况下,特征之间没有相关性。这个假设简化了计算,并且使得算法具有较好的效率。尽管这个假设在现实世界中往往并不成立,但在许多实际问题中,朴素贝叶斯算法仍然能够给出不错的结果。

(2)先验概率假设:贝叶斯算法需要先验概率作为初始估计,这些先验概率可以通过历史数据、领域知识或经验得到。先验概率假设是指我们能够对事件发生的概率有一定的先验估计。

(3)独立同分布假设:贝叶斯算法假设样本是独立同分布的,即每个样本的产生都是独立的,且来自于同一个分布。这个假设在许多机器学习算法中都是常见的假设,它使得我们能够从有限的样本中进行推断和泛化。

需要注意的是,贝叶斯算法的假设并不总是在所有问题上成立,特别是条件独立性假设。在某些情况下,违反这些假设可能会导致结果的偏差或错误的推断。因此,我们在选择和应用贝叶斯算法时,需要对问题的特性进行仔细分析,并考虑是否满足算法的基本假设。

1.3 贝叶斯与朴素贝叶斯

贝叶斯算法是一种基于贝叶斯定理进行概率推断的方法,而朴素贝叶斯算法是贝叶斯算法在分类问题上的一种具体应用。

本次主要介绍朴素贝叶斯算法。

(1)贝叶斯算法:

贝叶斯算法是一种概率推断的方法,它利用贝叶斯定理计算在已知先验条件下的后验概率。

贝叶斯算法可以用于处理各种问题,包括分类、回归、聚类等,在不同领域都有广泛的应用。

贝叶斯算法的核心思想是通过利用先验信息和观测数据来更新对事件概率的估计,从而得到更准确的后验概率估计。

(2)朴素贝叶斯算法:

朴素贝叶斯算法是贝叶斯算法在分类问题上的一种特殊应用,它基于特征之间的条件独立性假设。

在朴素贝叶斯算法中,假设每个特征与其他特征都是相互独立的,这样可以简化计算,并且使得算法具有较好的效率。

朴素贝叶斯算法通常用于文本分类、垃圾邮件过滤等问题,它在实际应用中表现出较好的性能和效果。

因此,可以说朴素贝叶斯算法是贝叶斯算法在分类问题上的一种具体应用,它利用贝叶斯定理进行概率推断,并且基于特征之间的条件独立性假设,从而实现高效的分类预测。

1.4算法原理

当我们面临一个问题需要做出决策时,我们通常会依靠已有的信息和经验来做出判断。贝叶斯算法就是一种利用这些信息来进行概率推断和决策的方法。

贝叶斯算法的核心是贝叶斯定理,它告诉我们如何更新我们的信念或概率估计,当我们获得新的证据或观测数据时。简单来说,贝叶斯定理可以帮助我们计算在已知先验条件下的后验概率。

举个例子来说明贝叶斯算法的原理。假设你生病了,需要去医院做检查。在医院之前,你对自己的疾病并没有确切的判断,只是有一些症状。这时,你可以将疾病的可能性看作是一个概率分布。这个分布反映了你对不同疾病的先验概率,也就是在没有任何证据的情况下,你认为某种疾病的概率有多大。

当你去医院做检查后,医生会给你一些检查结果,这些结果就是新的证据。根据贝叶斯定理,我们可以使用这些新的证据来更新我们对疾病的概率估计,得到后验概率。换句话说,我们可以通过将先验概率与证据相结合,来得到更准确的估计。

贝叶斯算法的思想就是不断地根据新的证据来更新我们的概率估计,从而得到更准确的结果。这个过程可以迭代进行,每次获得新的证据都会对我们的概率估计进行调整。最终,我们可以基于后验概率来做出决策或预测。

总结:贝叶斯算法利用先验概率和新的证据来进行概率推断和决策。它的核心原理是通过不断更新我们的概率估计,从而得到更准确的后验概率。这个过程可以帮助我们处理各种问题,包括分类、回归、聚类等,并且在实际应用中表现出较好的性能和效果。

本文主要介绍朴素贝叶斯算法,对其算法原理进行探讨,并进行实例测试。

二、算法推导

2.1朴素贝叶斯介绍

朴素贝叶斯是一种有监督学习算法,这种算法基于贝叶斯的一个朴素的假设——每对特征和样本数据都是独立同分布的。最终可以推出朴素贝叶斯分类器的判定准则:

贝叶斯的主要思路就是数数,统计每个条件组合下各种结果的概率,并根据这个概率做出分类。

但是,单纯的贝叶斯在计算机计算的时候会出现计算规模过大的情况,这里就需要 引入朴素条件,化简式子。

最终结果就是在计算时我们只需要统计单个条件下的结果,并据此计算得结果就好了,区别于先自由组合条件在统计结果。

2.2朴素贝叶斯算法推导

2.2.1先验后验概率

先验概率:事件发生前的预判概率。可以是基于历史数据的统计,可以由背景常识得出,也可以是人的主观观点给出。

后验概率:事件发生后求的反向条件概率;或者说,基于先验概率求得的条件概率。

2.2.2条件概率公式

设有事件 A , B,将已知B条件下求A的概率记作P(A|B) ,将A,B两件事

同时发生记作联合分布P(A,B),所有有下列条件概率公式

也即

又因为假设条件独立性,故P(A,B)=P(B,A),所以带入上述公式可得

这就是贝叶斯公式。

2.3 独立性假设

朴素贝叶斯假设条件概率是条件独立的,设X,x 都是n维的向量,X 是定义在空间的随机向量,x 是输入,Y 是类标记,有 Y ∈ { ,,, },独立性可用下述公式来进行表达:

2.4 朴素贝叶斯推导

由贝叶斯公式和条件概率公式有

将式(4) 带入式(5)可得到

这就是朴素贝叶斯的基本公式,所以其分类器可以表示为寻找一个最大的,即

由于对于一个给定的训练集, 式(7) 的分母是不变的,故只需要使得分子最大即可,即

三、算法实现

本次实验采用朴素贝叶斯实现文档分类实验

3.1数据集描述

朴素贝叶斯一个很重要的应用就是文本分类,所以我们以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。过滤这类内容是一个很常见的需求。对此问题建立两个类型:侮辱类和非侮辱类,使用1和0分别表示。

我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。简单起见,我们先假设已经将本文切分完毕,存放到列表中,并对词汇向量进行分类标注。

所用到的函数

loadDataSet:创建实验数据集

createVocabList:生成词汇表

setOfWords2Vec:生成词向量

get_trainMat:所有词条向量列表

trainNB:朴素贝叶斯分类器训练函数

classifyNB:朴素贝叶斯分类器分类函数

testingNB:朴素贝叶斯测试函数

3.2代码实现

Bayes.py

from numpy import *

def loadDataSet():
    postingList=[['my', 'dog', 'has', 'flea', 'problems', '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', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    classVec = [0,1,0,1,0,1]    #1 is abusive, 0 not
    return postingList,classVec
                 
def createVocabList(dataSet):
    vocabSet = set([])  #create empty set
    for document in dataSet:
        vocabSet = vocabSet | set(document) #union of the two sets
    return list(vocabSet)

def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else: print ("the word: %s is not in my Vocabulary!" % word)
    return returnVec

def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbusive = sum(trainCategory)/float(numTrainDocs)
    p0Num = ones(numWords); p1Num = ones(numWords)      #change to ones() 
    p0Denom = 2.0; p1Denom = 2.0                        #change to 2.0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect = log(p1Num/p1Denom)          #change to log()
    p0Vect = log(p0Num/p0Denom)          #change to log()
    return p0Vect,p1Vect,pAbusive

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)    #element-wise mult
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else: 
        return 0
    
def bagOfWords2VecMN(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    return returnVec

def testingNB():
    listOPosts,listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
    testEntry = ['love', 'my', 'dalmation']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry = ['stupid', 'garbage']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))

def textParse(bigString):    #input is big string, #output is word list
    import re
    listOfTokens = re.split(r'\W*', bigString)
    return [tok.lower() for tok in listOfTokens if len(tok) > 2] 
    
def spamTest():
    docList=[]; classList = []; fullText =[]
    for i in range(1,26):
        wordList = textParse(open('email/spam/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList = textParse(open('email/ham/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)#create vocabulary
    trainingSet = range(50); testSet=[]           #create test set
    for i in range(10):
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])  
    trainMat=[]; trainClasses = []
    for docIndex in trainingSet:#train the classifier (get probs) trainNB0
        trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:        #classify the remaining items
        wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
        if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
            errorCount += 1
            print ("classification error",docList[docIndex])
    print ('the error rate is: ',float(errorCount)/len(testSet))
    #return vocabList,fullText

def calcMostFreq(vocabList,fullText):
    import operator
    freqDict = {}
    for token in vocabList:
        freqDict[token]=fullText.count(token)
    sortedFreq = sorted(freqDict.iteritems(), key=operator.itemgetter(1), reverse=True) 
    return sortedFreq[:30]       

def localWords(feed1,feed0):
    import feedparser
    docList=[]; classList = []; fullText =[]
    minLen = min(len(feed1['entries']),len(feed0['entries']))
    for i in range(minLen):
        wordList = textParse(feed1['entries'][i]['summary'])
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1) #NY is class 1
        wordList = textParse(feed0['entries'][i]['summary'])
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    vocabList = createVocabList(docList)#create vocabulary
    top30Words = calcMostFreq(vocabList,fullText)   #remove top 30 words
    for pairW in top30Words:
        if pairW[0] in vocabList: vocabList.remove(pairW[0])
    trainingSet = range(2*minLen); testSet=[]           #create test set
    for i in range(20):
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])  
    trainMat=[]; trainClasses = []
    for docIndex in trainingSet:#train the classifier (get probs) trainNB0
        trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:        #classify the remaining items
        wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
        if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
            errorCount += 1
    print ('the error rate is: ',float(errorCount)/len(testSet))
    return vocabList,p0V,p1V

def getTopWords(ny,sf):
    import operator
    vocabList,p0V,p1V=localWords(ny,sf)
    topNY=[]; topSF=[]
    for i in range(len(p0V)):
        if p0V[i] > -6.0 : topSF.append((vocabList[i],p0V[i]))
        if p1V[i] > -6.0 : topNY.append((vocabList[i],p1V[i]))
    sortedSF = sorted(topSF, key=lambda pair: pair[1], reverse=True)
    print ("SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**")
    for item in sortedSF:
        print (item[0])
    sortedNY = sorted(topNY, key=lambda pair: pair[1], reverse=True)
    print ("NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**")
    for item in sortedNY:
        print (item[0])

  1. 根据给定的实验结果,我们可以看到两个示例样本的分类结果:

['love', 'my', 'dalmation'] 被分类为 0,即非有害类别。这是因为这个样本中包含了一些正面的词汇,如 "love" 和 "dalmation",而这些词汇在非有害样本中出现的频率较高。

['stupid', 'garbage'] 被分类为 1,即有害类别。这是因为这个样本中包含了一些负面的词汇,如 "stupid" 和 "garbage",而这些词汇在有害样本中出现的频率较高。

总的来说,贝叶斯分类器通过学习文本数据中词汇的出现概率,可以对新的文本样本进行分类。然而,该算法的性能还取决于训练数据的质量和特征表示的选择。

四、实验讨论

4.1算法优缺点

(1)优点

朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。

对小规模的数据表现很好,能个处理多分类任务,适合增量式训练。

对缺失数据不太敏感,算法也比较简单,常用于文本分类。

(2)缺点

理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别 的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。

需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致 预测效果不佳。

由于是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。

对输入数据的表达形式很敏感。

4.2关于三种朴素贝叶斯算法使用场合的讨论

在scikit-learn中,一共有3个朴素贝叶斯的分类算法。分别是GaussianNB,MultinomialNB和BernoulliNB。

(1) GaussianNB

GaussianNB就是先验为高斯分布(正态分布)的朴素贝叶斯,假设每个标签的数据都服从简单的正态分布。

其中  为Y的第k类的类别。 和 为需要从训练集估计的值。

(2) MultinomialNB

MultinomialNB就是先验为多项式分布的朴素贝叶斯。它假设特征是由一个简单多项式分布生成的。多项分布可以描述各种类型样本出现次数的概率,因此多项式朴素贝叶斯非常适合用于描述出现次数或者出现次数比例的特征。

该模型常用于文本分类,特征表示的是次数,例如某个词语的出现次数。多项式分布公式如下:

其中,P(=|Y=)是第 k 个类别的第j维特征的第l个取值条件概率。是训练集中输出为第k类的样本个数。 λ为一个大于0的常数,λ通常取1,即为拉普拉斯平滑。

(3) BernoulliNB

BernoulliNB就是先验为伯努利分布的朴素贝叶斯。假设特征的先验概率为二元伯努利分布,即如下式:

其中,只有两种取值,只能取值为0或1。

在伯努利模型中,每个特征的取值是布尔型的,即true和false,或者1和0。在文本分类中,就是一个特征有没有在一个文档中出现。

一般来说:

如果样本特征的分布大部分是连续值,使用GaussianNB会比较好;

如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适;

如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。

4.3关于朴素贝叶斯算法中拉普拉斯平滑修正的讨论

拉普拉斯平滑修正是朴素贝叶斯分类算法中常用的一种平滑技术,用于处理在计算条件概率时可能出现的零概率问题。虽然拉普拉斯平滑修正在某些情况下能够提高模型的鲁棒性和泛化能力,但也存在一些讨论和争议。

过度平滑:有些研究人员认为,拉普拉斯平滑修正可能会引入过度平滑的问题,即对于已经有足够样本支撑的特征,添加额外的伪计数反而会导致条件概率的估计偏离真实情况。这可能会影响模型对数据的拟合能力,使得模型过于简化,错失一些细微的模式。

对大规模数据的影响:在大规模数据集上,拉普拉斯平滑修正可能不如在小规模数据集上有效。因为在大规模数据集上,很多特征都能够获得足够数量的样本支持,不需要额外的平滑来保证条件概率的计算。

其他平滑方法:除了拉普拉斯平滑,还有其他平滑方法,如Lidstone平滑、Good-Turing估计等,它们也可以用于解决零概率问题,并且在不同情况下可能表现更好。

在实际应用中,是否使用拉普拉斯平滑修正取决于数据集的特点以及具体的建模需求。研究人员和实践者们需要根据具体情况权衡平滑方法的利弊,并结合交叉验证等方法选择最适合的方案。

4.4朴素贝叶斯算法的应用

朴素贝叶斯算法是一种简单而有效的分类算法,它在文本分类、垃圾邮件过滤、情感分析等领域有广泛的应用。以下是一些朴素贝叶斯算法的应用示例:

文本分类:朴素贝叶斯算法在文本分类任务中表现出色。它可以通过学习训练集中文本的特征(如单词、词频等)和对应的类别标签,建立一个分类模型。在测试阶段,根据新的文本特征,使用朴素贝叶斯算法计算后验概率,从而将文本分到相应的类别中。

垃圾邮件过滤:朴素贝叶斯算法被广泛应用于垃圾邮件过滤。通过学习已知的垃圾邮件和非垃圾邮件的特征,如发件人、主题、内容等,朴素贝叶斯算法可以对新的邮件进行分类,判断其是否为垃圾邮件。

情感分析:朴素贝叶斯算法可以用于情感分析,即对文本进行情感分类(如正面、负面、中性)。通过学习带有情感标签的文本样本,朴素贝叶斯算法可以根据文本的特征(词汇、句法结构等)来判断其情感倾向。

金融风险预测:在金融领域,朴素贝叶斯算法可以用于预测风险和评估潜在投资项目。通过学习历史数据和与风险相关的特征,朴素贝叶斯算法可以根据当前特征对未来可能的风险进行概率估计。

医学诊断:朴素贝叶斯算法在医学领域中也有应用。它可以利用患者的症状、疾病历史等特征,通过学习已知的病例数据,进行疾病的分类和诊断。

需要注意的是,朴素贝叶斯算法基于独立性假设,即每个特征之间是相互独立的,这在现实情况下并不总是成立。因此,在实际应用中,我们需要根据具体问题和数据的特点,合理选择适当的特征和算法,以获得更好的分类效果。

五、实验总结

本次实验探讨了贝叶斯算法的原理,区分了贝叶斯算法与朴素贝叶斯算法的关系,即贝叶斯算法是一种基于贝叶斯定理进行概率推断的方法,而朴素贝叶斯算法是贝叶斯算法在分类问题上的一种具体应用。

然后对朴素贝叶斯算法进行介绍,并在条件概率及独立性检验的基础上推导算法公式。

在算法实现部分,我采用的朴素贝叶斯实现文档分类实验。以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。过滤这类内容是一个很常见的需求。

最终的分类结果符合预期,证明了该算法的高效性。

在算法讨论部分,我们讨论了朴素贝叶斯算法的优缺点,优点是简单高效,适用于大规模数据集。缺点是假设特征之间相互独立,这在实际情况中可能不成立。

另外讨论的三种朴素贝叶斯算法即GaussianNB,MultinomialNB和BernoulliNB。他们在不同的场合有着各自的优势,需要根据具体情况权衡平滑方法的利弊,并结合交叉验证等方法选择最适合的方案。

总之,通过此次实验,对贝叶斯算法有了更深的认识和理解。贝叶斯算法是一种基于贝叶斯定理的概率模型推断方法,可以对未知参数进行估计和预测,并提供了一种在不确定性和变化中进行决策的框架。贝叶斯算法可以利用先验分布和后验分布来描述不确定性,并通过贝叶斯公式更新后验分布。这是一种常用的机器学习算法,在分类、回归和聚类等领域都有广泛的应用。

2024-1-22

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长安er

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值