热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SparkMLlib源代码解读之朴素贝叶斯分类器,NaiveBayes

SparkMLlib朴素贝叶斯NaiveBayes源代码分析基本原理介绍首先是基本的条件概率求解的公式。P(A|B)P(AB)P(B)在现实生活中,我们经常会碰到已知

Spark MLlib 朴素贝叶斯NaiveBayes 源代码分析

基本原理介绍


首先是基本的条件概率求解的公式。

P(A|B)=P(AB)P(B)

在现实生活中,我们经常会碰到已知一个条件概率,求得两个时间交换后的概率的问题。也就是在已知P(A|B)的情况下,如何求得P(B|A). 其中P(A|B)表示在事件B发生的前提下, 事件A发生的概率。 
其中P(A)指的是先验概率或者叫做边缘概率。因为他不需要考虑任何B方面的影响。 
P(A|B)指的是B发生后A的条件概率。 
P(B)是B的先验概率或者是边缘概率,也被称为标准化常量(normalized constant)。 
这里给出贝叶斯的计算公式: 

P(B|A)=P(A|B)P(B)P(A)


对于给定的分类项,求解此分类项在各个类别下出现的概率。哪个最大,哪个就被认为是分好类的类型。

假设 A={a1,a2,a3…}为待分类项,a1,a2是每个待分类项的属性。 
有一个类别的集合B={y1,y2….}.我们需要计算各个类别的先验概率,并取对数,计算公式如下.

p(i)=log(p(yi)) 
=log((i类别的次数+平滑因子)/(总次数+类别数*平滑因子))

我们需要计算P(y1|A),P(y2|A),P(y3|A)等等。求得计算结果的最大值,我们可以认为这个特征属性的类别为y。

首先我们需要计算在每一个类别下的各个特征属性的概率,即P(a1|y1),P(a2|y1),P(a3|y1), 
P(a1|y2),P(a2|y2),P(a3|y2,P(a1|y3),P(a2|y3),P(a3|y3)等。

在各个类别下的各个特征属性的条件概率估计,并取对数。 
theta(i)(j)=log(p(aj|yi)) 
=log(sumTermFreqs(j)+平滑因子)-thetaLogDenom.

其中theta(i)(j)是i类别下j的特征的概率,sumTermFreqs(j)是特征j出现的次数,thetaLogDenom 分为如下的两个类型:

  • 1 多项式模型:thetaLogDenom=log(sumTermFreqs.values.sum+numFeatures*lamda).其中sumTermFreqs.values.sum解释为类i下的单词总数,numFeatures是特征数量,lamda是平滑因子。
  • 2 伯努利模型:thetaLogDenom=log(n+2.0*lamda). 
    文本分类的时候n可以视作是类别i下的单词总数。lamda表示平滑因子。

假设各个特征属性的概率是相互独立的,有贝叶斯定理,我们有,

P(yi|A)=P(A|yi)P(yi)P(A)

由于分母为常数,所以只需要分子求值即可。又因为各个属性相互独立。可以得到:

P(A|yi)P(yi)=P(a1|yi)P(a2|yi)P(a3|yi)=P(yi)j=1m(P(aj|yi))

对上式同取log。

log(p(x|yi)p(yi))=log(p(yi))+j=1mlog(p(aj|yi))


spark 的源码实现分析: 
分布式的实现方法大致如下:首先对样本进行聚合操作,统计所有标签出现的次数,和对应的特征之和。即对labledPoint(label, features)这样子的一个元祖采用一个combineByKey聚合函数:对同一标签数据进行聚合统计操作。 
通过聚合操作后,可以通过聚合结果先验概率,条件概率。然后返回一个贝叶斯模型。 
预测的时候,将需要预测的样本向量乘以theta矩阵,即条件概率矩阵。然后计算每个样本属于每个类别的概率,然后选取其中的最大项作为类别。


NaiveBayes 源码大致框架:

  • 1,NaiveBayes分类伴生对象:NaiveBayes
  • 1.1 包含静态train方法,根据输入参数,初始化NaiveBayes类,通过run方法进行训练。
  • 2,贝叶斯分类:NaiveBayes
  • 2.1 run方法:开始训练贝叶斯模型,这个方法通过计算各个类别下的先验概率和条件概率来计算贝叶斯模型。
  • 3 贝叶斯模型类:NaiveBayesModel:
  • 4 预测计算:predict方法: 根据之前计算的先验概率和条件概率,计算样本属于每个类别的概率。去最大的项做为样本类别。

好了接下来我们来看看NaiveBayes的源代码,首先是其伴生对象。


1,object NaiveBayes: 
伴生对象主要定义了训练静态贝叶斯的分类模型的train方法。train方法通过设置训练参数进行模型训练,主要有如下的参数:

input:训练样本,其格式为RDD[LabeledPoint],其中labeledPoint格式为(label,features)。 
lamda:平滑因子,防止分母出现0.

/***朴素贝叶斯的伴生对象。*/
@Since("0.9.0")
object NaiveBayes {private[spark] val Multinomial: String = "multinomial" //表示的是多项式类型private[spark] val Bernoulli: String = "bernoulli" // 表示的是伯努利类型private[spark] val supportedModelTypes = Set(Multinomial, Bernoulli)//训练贝叶斯模型,根据训练样本,类型为RDD[LabeledPoint]//LabeledPointoink,其格式为(label,features)def train(input: RDD[LabeledPoint]): NaiveBayesModel = {new NaiveBayes().run(input)}@Since("0.9.0")//这个train 方法,除了上一个的基本参数之外,传入了一个平滑因子,lamda//def train(input: RDD[LabeledPoint], lambda: Double): NaiveBayesModel = {new NaiveBayes(lambda, Multinomial).run(input)}@Since("1.4.0")//输入样本,平滑因子,还有模型的类别,分别为多项式类型,和伯努利类型。def train(input: RDD[LabeledPoint], lambda: Double, modelType: String): NaiveBayesModel = {require(supportedModelTypes.contains(modelType),s"NaiveBayes was created with an unknown modelType: $modelType.")new NaiveBayes(lambda, modelType).run(input)}}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

2, 接下来是NaiveBayes的主类: 
class NaiveBayes:我们首先来看看它的基本的构造器和基本方法:

/***朴素贝叶斯分类器的类,训练一个朴素贝叶斯模型,根据rdd样本数据,* 其格式为(label,features).**训练朴素贝叶斯分类器模型,可以通过TF-IDF 生成向量。用于文档分类,*如果让向量为0-1模式,则可以应用于bernoulli NB,输入的特征必须是非负的。**/class NaiveBayes private (private var lambda: Double,private var modelType: String) extends Serializable with Logging {import NaiveBayes.{Bernoulli, Multinomial}@Since("1.4.0")def this(lambda: Double) = this(lambda, NaiveBayes.Multinomial)@Since("0.9.0")def this() = this(1.0, NaiveBayes.Multinomial) //在这个参数里面默认的平滑因子是1/** Set the smoothing parameter. Default: 1.0. */@Since("0.9.0")def setLambda(lambda: Double): NaiveBayes = { //设置平滑因子。this.lambda = lambdathis}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

接下来我们来看看整个朴素贝叶斯最为重要的run方法,所有的核心代码都在这个里面。

  • 1 NaiveBayes的run方法用来训练模型,这个方法主要用于计算先验概率和条件概率。这个方法的实现的逻辑是:首先对样本进行聚合。以label为key,调用combineByKey方法,聚合里面的同一个label的features,得到所有的label的统计(label,(count, features之和))。

  • 2 根据先验概率的计算公式p=log((n+lamda)/(numDocuments+numLabels*lamda))计算每个label的先验概率。根据条件概率log((sumTermFreqs(j)+lamda)/thetaLogDenom)计算每个label的先验概率。

  • 3 根据条件概率log((sumTermFreqs(j)+lamda)/thetaLogDenom)计算在各个label下面的各个features的条件概率,返回的是一个二维数组。

  • 4 最后通过标签列表,类别先验概率,特征的条件概率,类型生成一个朴素贝叶斯模型。

run方法的代码如下:

def run(data: RDD[LabeledPoint]): NaiveBayesModel = {//在这个里面定义了一个函数,来判断输入的特征向量的值。要求所有的向量值非负val requireNonnegativeValues: Vector => Unit = (v: Vector) => {val values = v match { //判断向量的类型,是密集向量还是稀疏向量case sv: SparseVector => sv.values // 根据不同类型的向量,得到其value值。case dv: DenseVector => dv.values}//判断是不是所有的值都大于0,否则抛出一个错误。多项式型需要每一个value值得大于0.if (!values.forall(_ >= 0.0)) {throw new SparkException(s"Naive Bayes requires nonnegative feature values but found $v.")}}//检测所有的伯努利的值,要求所有的向量值为0或者是1.val requireZeroOneBernoulliValues: Vector => Unit = (v: Vector) => {val values = v match {case sv: SparseVector => sv.valuescase dv: DenseVector => dv.values}if (!values.forall(v => v == 0.0 || v == 1.0)) {throw new SparkException(s"Bernoulli naive Bayes requires 0 or 1 feature values but found $v.")}}//从这个地方开始对数据进行计算。//对于每一个特征进行聚合,求得每一个标签的对应的特征的频数,//aggretaded表示通过label为key,聚合同一个label的features特征。他的返回格式是 (label,(计数,features之和))//注意这个combineByKey 算子: 其中,createCombiner表示,当combineByKey第一次遇到值为k的Key时,调用createCombiner函数,将v转换为c//然后是第二个mergeValue: combineByKey不是第一次遇到值为k的Key时,调用mergeValue函数,将v累加到c中//mergeCombiners:将两个c,合并成一个。///注意首先计算的是条件概率,返回个是为(label,(计数,features之和)),//表示每个样本标签的数量的和,和其对应的样本向量的特征之和。val aggregated = data.map(p => (p.label, p.features)).combineByKey[(Long, DenseVector)](//完成从V->C类型的转换,(v:Vector)=》(c:(long,vector))createCombiner = (v: Vector) => { // 根据上面所说的,输入的是一个vector,通过createCombiner函数将if (modelType == Bernoulli) { //将这个v转换成c的格式。格式为(1,densevector)类型。第二步需要做的就是每次遇到一个v,将其合并为c。requireZeroOneBernoulliValues(v)} else {requireNonnegativeValues(v)}(1L, v.copy.toDense) //这个是第一个函数的返回值,即将(c:Vector)=》(v:(Long,DenseVector))},//mergeValue指的是。当接下来遇到vector的时候,将vector合并到c中去。前提是他们的key必须相同。//过程如下:(c:(Long,DenseVector),v:Vector => (c:(Long,DenseVector))) mergeValue = (c: (Long, DenseVector), v: Vector) => {requireNonnegativeValues(v) //判断向量的是否符合条件BLAS.axpy(1.0, v, c._2) //c._2=c._2+v(c._1 + 1L, c._2) //这个地方继续返回一个元祖,其中对于第一个值进行加1操作。这里的c._2表示的是c._2=c._2+v},//接下来对根据相同的key来合并多个c。//mergeCombiners。过程如下(c1:(Long, DenseVector),c2: (Long, DenseVector)) => c:(c:(Long,DenseVector))mergeCombiners = (c1: (Long, DenseVector), c2: (Long, DenseVector)) => {BLAS.axpy(1.0, c2._2, c1._2) //c1._2=c1._2+c2._2(c1._1 + c2._1, c1._2) // 返回一个c。表示在一个key的情况下的每一个特征的数量之和加上其向量之和。}).collect().sortBy(_._1) //有一个排序操作是根据key来排序val numLabels = aggregated.length //aggregated的长度表示的是类别标签的个数var numDocuments = 0L //这个表示文档的数量//注意这个aggredaged的格式。首先它是一个数组。数组的元素的元祖的第二个值的格式为(Long,DenseVector)格式。//下面的这个n表示的是某一个特征下的数量。这个方法主要是对其进行汇总。总文档的数量进行汇总aggregated.foreach { case (_, (n, _)) =>numDocuments += n}//这个是用于计算特征的数量val numFeatures = aggregated.head match { case (_, (_, v)) => v.size }//labels类别标签的列表。val labels = new Array[Double](numLabels)//pi类别的先验概率val pi = new Array[Double](numLabels)//这个表示theta这个特征在各个类别下的概率。是个二维数组,theta[i][j],i表示第i个类别,j表示第j个特征。val theta = Array.fill(numLabels)(new Array[Double](numFeatures))//计算总文档数量的对数值,用于计算theta值。在下面使用到。 val piLogDenom = math.log(numDocuments + numLabels * lambda)var i = 0aggregated.foreach { case (label, (n, sumTermFreqs)) =>//aggregated的每一行表示label,和计数还有其特征向量之和。labels(i) = label //表示取出第一个标签放在lebels(i)里面。pi(i) = math.log(n + lambda) - piLogDenom //计算先验概率,并取log。log((n+lamda)/(numDocuments+numlabels*lamda))val thetaLogDenom = modelType match {case Multinomial => math.log(sumTermFreqs.values.sum + numFeatures * lambda) //多项式模型,比如说计算类a下的文章的总数case Bernoulli =>math.log(n + 2.0 * lambda) //贝努力模型,比如说用于计算类a下的文章的总数。case _ =>throw new UnknownError(s"Invalid modelType: $modelType.")}var j = 0 //每一个i类别下,都需要计算j类别的条件概率,每次j从0开始while (j //这个用于计算各个特征在各个类别下的条件概率//表示的是类别i下这个特征j的次数,除以总的出现次数theta(i)(j) = math.log(sumTermFreqs(j) + lambda) - thetaLogDenomj += 1}i += 1 //这里面有两层循环,i表示的是类别。j表示的是特征。先从类别开始循环。然后在开始对特征进行循环。}//最后生成模型。包括类别标签列表,类别先验概率,各个类别下每个特征的条件概率,多项式和伯努利new NaiveBayesModel(labels, pi, theta, modelType)}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

3 最后是贝叶斯分类模型 class NaiveBayesModel

训练完成后,会生成贝叶斯分类模型。其包含如下参数:labels–类别标签列表. pi–每个类别的先验概率,theta–各个特征在各个类别下的先验概率,modelType–多项式或者是伯努利模型。 
模型类主要包含一下的方法,即predict方法,load方法和save方法。 
首先我们来看看其构造器:

class NaiveBayesModel private[spark] (@Since("1.0.0") val labels: Array[Double], //这个表示的是labels数组@Since("0.9.0") val pi: Array[Double], //这个表示的是先验概率数组@Since("0.9.0") val theta: Array[Array[Double]], //这个表示theta这个特征在各个类别下的概率。条件概率数组,二维数组。@Since("1.4.0") val modelType: String) //这个表示类别extends ClassificationModel with Serializable with Saveable private[mllib] def this(labels: Array[Double], pi: Array[Double], theta: Array[Array[Double]]) =this(labels, pi, theta, NaiveBayes.Multinomial)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

接下来是predict方法,默认的输入参数的类型是RDD[Vector],这个方法内部调用的是predict(testData:Vector)方法。该方法的返回值是一个double类型。

//这个方法会将输入的rdd转换为向量,然后调用下一个predict方法
override def predict(testData: RDD[Vector]): RDD[Double] = {val bcModel = testData.context.broadcast(this) //广播一下模型,testData.mapPartitions { iter => //采用mappartition进行操作,对每一个分区进行操作。val model = bcModel.value //在每个分区里面获取广播变量值,iter.map(model.predict) //对分区的每一个元素,调用predict方法。调用的是下面一个方法。}}override def predict(testData: Vector): Double = {modelType match {case Multinomial => //如果是多项式类型的,则调用multinomialCalculationlabels(multinomialCalculation(testData).argmax) //注意这个地方,会调用求最大值,下面类似case Bernoulli => //如果是伯努利类型的,bernoulliCalculationlabels(bernoulliCalculation(testData).argmax)}}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下面是两个计算方法,分别是multinomialCalculation和bernoulliCalculation。

private def multinomialCalculation(testData: Vector) = {val prob = thetaMatrix.multiply(testData) //用条件概率矩阵,乘以样本向量。 theta*testDataBLAS.axpy(1.0, piVector, prob) //prob=1.0*piVector+prob (本来是相乘的,但是取log之后变成相加,结果是一样的。)prob //得到结果之后,去向量的最大值。}private def bernoulliCalculation(testData: Vector) = {testData.foreachActive((_, value) =>if (value != 0.0 && value != 1.0) { 如果不满足条件的话throw new SparkException(s"Bernoulli naive Bayes requires 0 or 1 feature values but found $testData.")})val prob = thetaMinusNegTheta.get.multiply(testData) //用条件概率矩阵,乘以样本向量。theta*testDataBLAS.axpy(1.0, piVector, prob) //prob=1.0*piVector+probBLAS.axpy(1.0, negThetaSum.get, prob)prob}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

接下来就是最基本的加载和保存的方法了。分为save方法和load方法。

def load(sc: SparkContext, path: String): NaiveBayesModel = {val sqlContext = SQLContext.getOrCreate(sc)// Load Parquet data.val dataRDD = sqlContext.read.parquet(dataPath(path))// Check schema explicitly since erasure makes it hard to use match-case for checking.checkSchema[Data](dataRDD.schema)val dataArray = dataRDD.select("labels", "pi", "theta", "modelType").take(1)assert(dataArray.length == 1, s"Unable to load NaiveBayesModel data from: ${dataPath(path)}")val data = dataArray(0)val labels = data.getAs[Seq[Double]](0).toArrayval pi = data.getAs[Seq[Double]](1).toArrayval theta = data.getAs[Seq[Seq[Double]]](2).map(_.toArray).toArrayval modelType = data.getString(3)new NaiveBayesModel(labels, pi, theta, modelType)}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

def save(sc: SparkContext, path: String, data: Data): Unit = {val sqlContext = SQLContext.getOrCreate(sc)import sqlContext.implicits._// Create JSON metadata.val metadata = compact(render(("class" -> thisClassName) ~ ("version" -> thisFormatVersion) ~("numFeatures" -> data.theta(0).length) ~ ("numClasses" -> data.pi.length)))sc.parallelize(Seq(metadata), 1).saveAsTextFile(metadataPath(path))// Create Parquet data.val dataRDD: DataFrame = sc.parallelize(Seq(data), 1).toDF()dataRDD.write.parquet(dataPath(path))}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

好了,谢谢大家,以上就是我对于spark mllib的朴素贝叶斯的代码的解析。



版权声明:本文为博主原创文章,未经博主允许不得转载。

推荐阅读
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 解决python matplotlib画水平直线的问题
    本文介绍了在使用python的matplotlib库画水平直线时可能遇到的问题,并提供了解决方法。通过导入numpy和matplotlib.pyplot模块,设置绘图对象的宽度和高度,以及使用plot函数绘制水平直线,可以解决该问题。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • Python基础知识:注释、输出和input交互
    本文介绍了Python基础知识,包括注释的使用、输出函数print的用法以及input函数的交互功能。其中涉及到字符串和整数的类型转换等内容。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • Python教学练习二Python1-12练习二一、判断季节用户输入月份,判断这个月是哪个季节?3,4,5月----春 ... [详细]
  • 我用Tkinter制作了一个图形用户界面,有两个主按钮:“开始”和“停止”。请您就如何使用“停止”按钮终止“开始”按钮为以下代码调用的已运行功能提供建议 ... [详细]
  • 在本教程中,我们将看到如何使用FLASK制作第一个用于机器学习模型的RESTAPI。我们将从创建机器学习模型开始。然后,我们将看到使用Flask创建AP ... [详细]
author-avatar
等了哭了累了55
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有