4-Spark高级数据分析-第四章 用决策树算法预测森林植被

预测是非常困难的,更别提预测未来。

4.1 回归简介

随着现代机器学习和数据科学的出现,我们依旧把从“某些值”预测“另外某个值”的思想称为回归。回归是预测一个数值型数量,比如大小、收入和温度,而分类则指预测标号或类别,比如判断邮件是否为“垃圾邮件”,拼图游戏的图案是否为“猫”。

将回归和分类联系在一起是因为两者都可以通过一个(或更多)值预测另一个(或多个)值。为了能够做出预测,两者都需要从一组输入和输出中学习预测规则。在学习的过程中,需要告诉它们问题及问题的答案。因此,它们都属于所谓的监督学习。

分类和回归是分析预测中最古老的话题。支持向量机、逻辑回归、朴素贝叶斯算法、神经网络和深度学习都属于分类和回归技术。

本章将重点关注决策树算法和它的扩展随机决策森林算法,这两个算法灵活且应用广泛,即可用于分类问题,也可用于回归问题。更令人兴奋的是,它们可以帮助我们预测未来,至少是预测我们尚不肯定的事情。比如,根据线上行为来预测购买汽车的概率,根据用词预测邮件是否是垃圾邮件,根据地理位置和土壤的化学成分预测哪块耕地的产量可能更高。

4.2 向量和特征

天气的特征有:

最低气温

最高气温

平均气温

多云、有雨、晴朗

特征有时也被称为维度、预测指标或简单地称为变量。本书将特征只分为两大类:类别型特征和数值型特征。

特征值按顺序排列,就是所谓的特征向量。

4.3 样本训练

某一天,气温12~16摄氏度,湿度10%,晴朗,没有寒流预报,第二天最高气温为17.2摄氏度。

特征向量为学习算法的输入提供一种结构化的方式(比如输入:12.5,15.5,0.10,晴朗,0)。预测的输出(即目标)也被称为一个特征,它是一个数值特征:17.2。

通常我们把目标作为特征向量的一个附加特征。因此可以把整个训练样本列示为:12.5,15.5,0.10,晴朗,0,17.2。所有这些样本的集合称为训练集。

回归和分析的区别在于:回归问题的目标为数值型特征,而分类问题的目标为类别型特征。并不是所有的回归或分类算法都能够处理类别型特征或类别型目标,有些算法只能处理数值型特征。

4.4 决策树和决策森林

决策树算法家族能自然地处理类别型和数值型特征。决策树算法容易并行化。它们对数据中的离群点具有鲁棒性,这意味着一些极端或可能错误的数据点根本不会对预测产生影响。算法可以接受不同类型和量纲的数据,对数据类型和尺度不同的情况不需要做预处理和规范化。

决策树可以推广为更强大的决策森林算法。本章将会把Spark MLib的DecisionTree和RandomForest算法实现应用到一个数据集上。

基于决策树的算法还有一个优点,那就是理解和推理起来相对直观。

4.5 Covtype数据集

下载地址是https://archive.ics.uci.edu/ml/machine-learning-databases/covtype/

或者http://pan.baidu.com/s/1gfkDKlH

covtype.data.gz为压缩数据文件,附带一个描述数据文件的信息文件covtype.txt。记录了美国科罗拉多州不同地块森林植被特征:海拔、坡度、到水源的距离、遮阳情况和土壤类型,并且随同给出了地块的已知森林植被类型。有581012个样本。

4.6 准备数据

Spark MLib将特征向量抽象为LabeledPoint,它由一个包含对个特征值的Spark MLib Vector和一个称为标号(label)的目标值组成。该目标为Double类型,而Vector本质上是对多个Double类型值的抽象。这说明LabeledPoint只适用于数值型特征。但只要经过适当编码,LabeledPoint也可用于类别型特征。

其中一种编码是one-hot或1-of-n编码。在这种编码中,一个有N个不同取值的类别型特征可以变成N个数值型特征,变换后的每个数值型特征的取值为0或1.在这N个特征中,有且只有一个取值为1,其他特征取值都为0。

4.7 第一棵决策树

开始时我们原样使用数据。

Scala:

import org.apache.spark.mllib.linalg._

import org.apache.spark.mllib.regression._

val rawData = sc.textFile("D:/Workspace/AnalysisWithSpark/src/main/java/advanced/chapter4/covtype/covtype.data")

val data = rawData.map { line =>

         val values = line.split(‘,‘).map(_.toDouble)

         val featureVector = Vectors.dense(values.init)

         val label = values.last - 1

         LabeledPoint(label, featureVector)

}

  

Java:

 1 public static JavaRDD<LabeledPoint> readData(JavaSparkContext jsc) {
 2
 3          JavaRDD<String> rawData =jsc.textFile("src/main/java/advanced/chapter4/covtype/covtype.data");
 4
 5
 6
 7          JavaRDD<LabeledPoint> data = rawData.map(line -> {
 8
 9                    String[] values = line.split(",");
10
11                    double[] features = new double[values.length-1];
12
13                    for (int i = 0; i < values.length-1; i++) {
14
15                             features[i] = Double.parseDouble(values[i]);
16
17                    }
18
19                    Vector featureVector = Vectors.dense(features);
20
21                    Double label = (double) (Double.parseDouble(values[values.length-1]) - 1);
22
23                    return new LabeledPoint(label, featureVector);
24
25          });
26
27          return data;
28
29 }
30
31  

本章将数据分成完整的三部分:训练集、交叉检验集(CV)和测试集。在下面的代码中你会看到,训练集占80%,交叉检验集和测试集各占10%。

Scala:

val Array(trainData, cvData, testData) =data.randomSplit(Array(0.8, 0.1, 0.1))

trainData.cache()

cvData.cache()

testData.cache()

  

Java:

 1 //将数据分割为训练集、交叉检验集(CV)和测试集
 2
 3 JavaRDD<LabeledPoint>[] splitArray = data.randomSplit(new double[]{0.8, 0.1, 0.1});
 4
 5 JavaRDD<LabeledPoint> trainData = splitArray[0];
 6
 7 trainData.cache();
 8
 9 JavaRDD<LabeledPoint> cvData = splitArray[1];
10
11 cvData.cache();
12
13 JavaRDD<LabeledPoint> testData = splitArray[2];
14
15 testData.cache();
16
17  

和ALS实现一样,DecisionTree实现也有几个超参数,我们需要为它们选择值。和之前一样,训练集和CV集用于给这些超参数选择一个合适值。这里第三个数据集,也就是测试集,用于对基于选定超参数的模型期望准确度做无偏估计。模型在交叉检验集上的准确度往往有点过于乐观,不是无偏差的。本章我们还将更进一步,以此在测试集上评估最终模型。

我们先来试试在训练集上构造一个DecisionTreeModel模型,参数采用默认值,并用CV集来计算结果模型的指标:

Scala:

import org.apache.spark.mllib.evaluation._

import org.apache.spark.mllib.tree._

import org.apache.spark.mllib.tree.model._

import org.apache.spark.rdd._

def getMetrics(model: DecisionTreeModel, data: RDD[LabeledPoint]):

                   MulticlassMetrics = {

         val predictionsAndLabels = data.map(example =>

                   (model.predict(example.features), example.label)

         )

         new MulticlassMetrics(predictionsAndLabels)

}

val model = DecisionTree.trainClassifier(

         trainData, 7, Map[Int,Int](), "gini", 4, 100)

val metrics = getMetrics(model, cvData)

  

Java:

 1 public static MulticlassMetrics getMetrics(DecisionTreeModel model, JavaRDD<LabeledPoint> data){
 2
 3          JavaPairRDD<Object, Object> predictionsAndLabels = data.mapToPair(example -> {
 4
 5                    return new Tuple2<Object, Object>(model.predict(example.features()), example.label());
 6
 7          });
 8
 9
10
11          return new MulticlassMetrics(JavaPairRDD.toRDD(predictionsAndLabels));
12
13 }
14
15
16
17 //构建DecisionTreeModel
18
19 DecisionTreeModel model = DecisionTree.trainClassifier(trainData, 7, new HashMap<Integer, Integer>(), "gini", 4, 100);
20
21
22
23 //用CV集来计算结果模型的指标
24
25 MulticlassMetrics metrics = getMetrics(model, cvData);
26
27  

这里我们使用trainClassifier,而不是trainRegressor,trainClassifier指示每个LabeledPoint里的目标应该当做不同的类别指标,而不是数值型特征。

和MulticlassMetrics一起,Spark还提供了BinaryClassificationMetrics。它提供类似MulticlassMetrics的评价指标实现,不过仅适用常见的类别型目标只有两个可能取值的情况。

查看混淆矩阵:

Scala:

metrics.confusionMatrix

Java:

1 //查看混淆矩阵
2
3 System.out.println(metrics.confusionMatrix());

结果:

14395.0  6552.0   13.0    1.0    0.0   0.0  359.0

5510.0   22020.0  447.0   29.0   6.0   0.0  36.0

0.0      413.0    3033.0  82.0   0.0   0.0  0.0

0.0      0.0      175.0   103.0  0.0   0.0  0.0

0.0      897.0    33.0    0.0    15.0  0.0  0.0

0.0      437.0    1210.0  99.0   0.0   0.0  0.0

1148.0   41.0     0.0     0.0    0.0   0.0  822.0

你得到的值可能稍有不同。构造决策树过程中的一些随机选项会导致分类结果稍有不同。

矩阵每一行对应一个实际的正确类别值,矩阵每一列按序对应预测值。第i行第j列的元素代表一个正确类别为i的样本被预测为类别为j的次数。因此,对角线上的元素代表预测正确的次数,而其他元素则代表预测错误的次数。对角线上的次数多是好的。但也确实出现了一些分类错误的情况,比如上面结果中没将任何一个样本类别预测为6。

查看准确度(或者说精确度):

Scala:

metrics.precision

Java:

1 //查看准确度
2
3 System.out.println(metrics.precision());

结果:

0.7022196201332805

每个类别相对其他类别的精确度

Scala:

(0 until 7).map(

cat => (metrics.precision(cat), metrics.recall(cat))

).foreach(println)

  

Java:

1 //每个类别相对其他类别的精确度
2
3 Arrays.asList(new Integer[]{0,1,2,3,4,5,6}).stream()
4
5 .forEach(cat -> System.out.println(metrics.precision(cat) + "," + metrics.recall(cat)));

结果:

0.6738106679481018,0.6707807118254879

0.7300201914935192,0.7838858581619806

0.6303782269361617,0.8536585365853658

0.4672489082969432,0.3835125448028674

0.0,0.0

0.67,0.03877314814814815

0.6796116504854369,0.4454233969652472

有此可以看到每个类型准确度各有不同。

增加一个准确度评估:

Scala:

import org.apache.spark.rdd._

def classProbabilities(data: RDD[LabeledPoint]): Array[Double] = {

         val countsByCategory = data.map(_.label).countByValue()

         val counts = countsByCategory.toArray.sortBy(_._1).map(_._2)

         counts.map(_.toDouble / counts.sum)

}

val trainPriorProbabilities = classProbabilities(trainData)

val cvPriorProbabilities = classProbabilities(cvData)

trainPriorProbabilities.zip(cvPriorProbabilities).map {

         case (trainProb, cvProb) => trainProb * cvProb

}.sum

  

Java:

 1 public static List<Double> classProbabilities(JavaRDD<LabeledPoint> data) {
 2
 3          //计算数据中每个类的样本数:(类别,样本数)
 4          Map<Double, Long> countsByCategory = data.map( x -> x.label()).countByValue();
 5
 6          //排序
 7          List<Map.Entry<Double, Long>> categoryList = new ArrayList<>(countsByCategory.entrySet());
 8          Collections.sort(categoryList, (m1, m2) -> m1.getKey().intValue()-m2.getKey().intValue());
 9
10          //取出样本数
11          List<Long> counts = categoryList.stream().map(x -> x.getValue()).collect(Collectors.toList());
12          Double sum = counts.stream().reduce((r, e) -> r = r + e ).get().doubleValue();
13          return counts.stream().map(x -> x.doubleValue()/sum).collect(Collectors.toList());
14 }
15
16
17
18 List<Double> trainPriorProbabilities = classProbabilities(trainData);
19 List<Double> cvPriorProbabilities = classProbabilities(cvData);
20
21 //把训练集和CV集中的某个类别的概率结成对,相乘然后相加
22 List<Tuple2<Double, Double>> mergePriorProbabilities = new ArrayList<>();
23 Arrays.asList(new Integer[]{0,1,2,3,4,5,6}).stream().forEach(i -> mergePriorProbabilities.add(new Tuple2<Double, Double>(trainPriorProbabilities.get(i), cvPriorProbabilities.get(i))));
24 System.out.println(mergePriorProbabilities.stream().map(x -> x._1*x._2).reduce((r,e) -> r=r+e).get());

结果:

0.3762360562429304

随机猜猜的准确度为37%,所以我们前面得到的70%的准确度看起来还不错。如果在决策树构建过程中试试超参数的其他值,准确度还可以提高。

4.8 决策树的超参数

控制决策树选择过程的参数为最大深度、最大桶数和不纯性度量。

最大深度只是对决策树的层数做出限制。限制判断次数有利于避免对训练数据产生过拟合。

好规则把训练集数据的目标值分为相对是同类或“纯”(pure)的子集。选择最好的规则也就意味着最小化规则对应的两个子集的不纯性。不纯性有两种常用度量方式:Gini不纯度或熵。

Gini不纯度直接和随机猜测分类器的准确度相关。熵是另一种度量不纯性的方式,它来源于信息论。Spark的实现默认采用Gini不纯度。

4.9 决策树调优

我们取不同的参数进行测验:

Scala:

val evaluations =

         for (impurity <- Array("gini", "entropy");

                   depth <- Array(1, 20);

                   bins <- Array(10, 300))

         yield {

                   val model = DecisionTree.trainClassifier(

                            trainData, 7, Map[Int,Int](), impurity, depth, bins)

                   val predictionsAndLabels = cvData.map(example =>

                            (model.predict(example.features), example.label)

                   )

                   val accuracy =

                            new MulticlassMetrics(predictionsAndLabels).precision

                   ((impurity, depth, bins), accuracy)

         }

evaluations.sortBy(_._2).reverse.foreach(println)

  

Java新建一个类:Hyperparameters进行测试

Java:

 1 //决策树调优
 2
 3 List<Tuple2<Tuple3<String, Integer, Integer>, Double>> evaluations = new ArrayList<>();
 4
 5
 6
 7 String[] impuritySet = new String[]{"gini", "entropy"};
 8 Integer[] depthSet = new Integer[]{1, 20};
 9 Integer[] binsSet = new Integer[]{10, 300};
10 for (String impurity : impuritySet) {
11          for (Integer depth : depthSet) {
12                    for (Integer bins : binsSet) {
13                             //构建DecisionTreeModel
14                             DecisionTreeModel model = DecisionTree.trainClassifier(trainData, 7, new HashMap<Integer, Integer>(), impurity, depth, bins);
15                             //用CV集来计算结果模型的指标
16                             MulticlassMetrics metrics = getMetrics(model, cvData);
17
18                             evaluations.add(new Tuple2<Tuple3<String, Integer, Integer>, Double>(new Tuple3<String, Integer, Integer>(impurity, depth, bins), metrics.precision()));
19                    }
20          }
21 }
22
23 Collections.sort(evaluations, (m1, m2) -> (int)((m2._2-m1._2)*1000));
24 evaluations.forEach(x -> System.out.println(x._1._1() + "," + x._1._2() + "," + x._1._3() + "," + x._2));

结果:

entropy,20,300,0.909348831610984

gini,20,300,0.9034338084839314

entropy,20,10,0.8934436095396943

gini,20,10,0.8906752411575563

gini,1,10,0.6348504909125299

gini,1,300,0.634283061368365

entropy,1,10,0.4892962154168888

entropy,1,300,0.4892962154168888

前面的测试表明,目前最佳选择是:不纯性度量采用熵,最大深度为20,桶数为300,这时准确度为90.9%。

想要真正评估这个最佳模型在将来的样本上的表现,当然需要在没有用于训练的样本上进行评估。也就是使用第三个子集进行测试:

Scala:

val model = DecisionTree.trainClassifier(

trainData.union(cvData), 7, Map[Int,Int](), "entropy", 20, 300)

Java:

1 DecisionTreeModel modelR = DecisionTree.trainClassifier(trainData.union(cvData), 7, new HashMap<Integer, Integer>(), "entropy", 20, 300);
2 MulticlassMetrics metricsR = getMetrics(modelR, testData);
3 System.out.println(metricsR.precision());

结果:

0.91562526784949

结果准确度为91.6%。估计还算可靠吧。决策树在一定程度上存在对训练数据的过拟合。减小最大深度可能会使过拟合问题有所改善。

4.10 重谈类别型特征

数据中类别型特征使用one-hot编码,这种编码迫使决策树算法在底层要单独考虑类别型特征的每一个值,增加内存使用量并且减慢决策速度。我们取消one-hot编码:

Scala:

val data = rawData.map { line =>

         val values = line.split(‘,‘).map(_.toDouble)

         val wilderness = values.slice(10, 14).indexOf(1.0).toDouble

         val soil = values.slice(14, 54).indexOf(1.0).toDouble

         val featureVector =

                   Vectors.dense(values.slice(0, 10) :+ wilderness :+ soil)

         val label = values.last - 1

         LabeledPoint(label, featureVector)

}

val evaluations =

         for (impurity <- Array("gini", "entropy");

                   depth <- Array(10, 20, 30);

                   bins <- Array(40, 300))

         yield {

                   val model = DecisionTree.trainClassifier(

                            trainData, 7, Map(10 -> 4, 11 -> 40),

                            impurity, depth, bins)

                   val trainAccuracy = getMetrics(model, trainData).precision

                   val cvAccuracy = getMetrics(model, cvData).precision

                   ((impurity, depth, bins), (trainAccuracy, cvAccuracy))

         }

  

复制Hyperparameters命名为CategoricalFeatures,修改readData和决策树参数。

Java:

 1 public static JavaRDD<LabeledPoint> readData(JavaSparkContext jsc) {
 2          JavaRDD<String> rawData =jsc.textFile("src/main/java/advanced/chapter4/covtype/covtype.data");
 3
 4          JavaRDD<LabeledPoint> data = rawData.map(line -> {
 5                    String[] values = line.split(",");
 6                    double[] features = new double[12];
 7                    for (int i = 0; i < 10; i++) {
 8                             features[i] = Double.parseDouble(values[i]);
 9                    }
10                    for (int i = 10; i < 14; i++) {
11                             if(Double.parseDouble(values[i]) == 1.0){
12                                      features[10] = i-10;
13                             }
14                    }
15
16                    for (int i = 14; i < 54; i++) {
17                             if(Double.parseDouble(values[i]) == 1.0){
18                                      features[11] = i-14;
19                             }
20                    }
21
22                    Vector featureVector = Vectors.dense(features);
23                    Double label = (double) (Double.parseDouble(values[values.length-1]) - 1);
24                    return new LabeledPoint(label, featureVector);
25          });
26          return data;
27 }
28
29
30
31 List<Tuple2<Tuple3<String, Integer, Integer>, Double>> evaluations = new ArrayList<>();
32 Map<Integer, Integer> map = new HashMap<Integer, Integer>();
33 map.put(10, 4);
34 map.put(11, 40);
35 String[] impuritySet = new String[]{"gini", "entropy"};
36 Integer[] depthSet = new Integer[]{10, 20, 30};
37 Integer[] binsSet = new Integer[]{40, 300};
38 for (String impurity : impuritySet) {
39          for (Integer depth : depthSet) {
40                    for (Integer bins : binsSet) {
41                             //构建DecisionTreeModel
42                             DecisionTreeModel model = DecisionTree.trainClassifier(trainData, 7, map, impurity, depth, bins);
43                             //用CV集来计算结果模型的指标
44                             MulticlassMetrics metrics = getMetrics(model, cvData);
45
46                             evaluations.add(new Tuple2<Tuple3<String, Integer, Integer>, Double>(new Tuple3<String, Integer, Integer>(impurity, depth, bins), metrics.precision()));
47                    }
48          }
49 }
50
51 Collections.sort(evaluations, (m1, m2) -> (int)((m2._2-m1._2)*1000));
52 evaluations.forEach(x -> System.out.println(x._1._1() + "," + x._1._2() + "," + x._1._3() + "," + x._2));
53
54  

结果:

entropy,30,300,0.9420165175498968

entropy,30,40,0.9400378527185134

gini,30,40,0.9340674466620784

gini,30,300,0.9330006882312457

gini,20,40,0.9227288368891947

entropy,20,40,0.923554714384033

entropy,20,300,0.9233138334480385

gini,20,300,0.9211286992429456

gini,10,40,0.7867859600825877

gini,10,300,0.7862869924294563

entropy,10,40,0.7863214039917412

entropy,10,300,0.779525120440468

准确度为94.2%。比以前更好。

4.11 随机决策森林

随机决策森林是由多个决策树独立构造而成。

Scala:

val forest = RandomForest.trainClassifier(

trainData, 7, Map(10 -> 4, 11 -> 40), 20,

"auto", "entropy", 30, 300)

  

Java:

 1 Map<Integer, Integer> map = new HashMap<Integer, Integer>();
 2 map.put(10, 4);
 3 map.put(11, 40);
 4
 5 //构建RandomForestModel
 6 RandomForestModel model = RandomForest.trainClassifier(trainData, 7, map, 20, "auto", "entropy", 30, 300, Utils.random().nextInt());
 7
 8 //用CV集来计算结果模型的指标
 9 MulticlassMetrics metrics = getMetrics(model, cvData);
10 System.out.println(metrics.precision());

结果:

0.964827502890772

准确率96.5%。

在大数据背景下,随机决策森林非常有吸引力,因为决策树往往是独立构造的,诸如Spark和MapReduce这样的大数据技术本质上适合数据并行问题。

4.12 进行预测

Scala:

val input = "2709,125,28,67,23,3224,253,207,61,6094,0,29"

val vector = Vectors.dense(input.split(‘,‘).map(_.toDouble))

forest.predict(vector)

Java:

1 double[] input = new double[] {(double) 2709,(double) 125,(double) 28,(double) 67,(double) 23,(double) 3224,(double) 253,(double) 207,(double) 61,(double) 6094,(double) 0,(double) 29};
2 Vector vector = Vectors.dense(input);
3 System.out.println(model.predict(vector));

结果:

4.0

4.0对应原始Covtype数据集中的类别5(元素特征从1开始)。(在本地算了半个小时 ㄒoㄒ )。

4.13 小结

本章介绍分类和回归。介绍概念:特征、向量、训练和交叉检验。

一般情况,准确度超过95%是很难达到的。通常,通过包括更多特征,或将已有特征转换成预测性更好的形式,我们可以进一步提高准确度。

分类和回归算法不只包括决策树和决策森林,Spark Mlib 实现的算法也不限于决策树和决策森林。对分类问题,Spark MLib提供的实现包括:

朴素贝叶斯

支持向量机

逻辑回归

他们接受一个LabeledPoint类型的RDD作为输入,需要通过将输入数据划分为训练集、交叉检验集和测试集来选择超参数。

时间: 2025-01-13 15:07:03

4-Spark高级数据分析-第四章 用决策树算法预测森林植被的相关文章

Spark高级数据分析-第2章 用Scala和Spark进行数据分析

2.4 小试牛刀:Spark shell和SparkContext 本章使用的资料来自加州大学欧文分校机器学习资料库(UC Irvine Machine Learning Repository),这个资料库为研究和教学提供了大量非常好的数据源, 这些数据源非常有意义,并且是免费的.由于网络原因,无法从原始地址下载数据集,这里可以从以下链接获取: https://pan.baidu.com/s/1dENp41V 或 http://pan.baidu.com/s/1c29fBVy 获取数据集以后,可

《Spark高级数据分析》pdf格式下载免费电子书下载

<Spark高级数据分析>pdf格式下载免费电子书下载https://u253469.ctfile.com/fs/253469-300325651 更多电子书下载: http://hadoopall.com/book 内容简介 本书是使用Spark进行大规模数据分析的实战宝典,由著名大数据公司Cloudera的数据科学家撰写.四位作者首先结合数据科学和大数据分析的广阔背景讲解了Spark,然后介绍了用Spark和Scala进行数据处理的基础知识,接着讨论了如何将Spark用于机器学习,同时介绍

3-Spark高级数据分析-第三章 音乐推荐和Audioscrobbler数据集

偏好是无法度量的. 相比其他的机器学习算法,推荐引擎的输出更直观,更容易理解. 接下来三章主要讲述Spark中主要的机器学习算法.其中一章围绕推荐引擎展开,主要介绍音乐推荐.在随后的章节中我们先介绍Spark和MLib的实际应用,接着介绍一些机器学习的基本思想. 3.1 数据集 用户和艺术家的关系是通过其他行动隐含提现出来的,例如播放歌曲或专辑,而不是通过显式的评分或者点赞得到的.这被称为隐式反馈数据.现在的家用电视点播也是这样,用户一般不会主动评分. 数据集在http://www-etud.i

【读书笔记】C#高级编程 第四章 继承

(一)继承的类型 1.实现继承和接口继承 在面向对象的编程中,有两种截然不同的继承类型:实现继承和接口继承. 实现继承:表示一个类型派生于一个基类型,它拥有该基类型的所有成员字段和函数.在实现继承中,派生类型采用基类型的每个函数代码,除非在派生类型的定义中指定重写某个函数的实现代码.在需要给现有的类型添加功能,或许多相关的类型共享一组重要的公共功能时,这种类型的继承非常有用. 接口继承:表示一个类型只继承了函数的签名,没有继承任何实现代码.在需要制定该类型具有某些可用的特性时,最好使用这种类型的

js 高级程序设计 第四章总结

变量,作用域和内存问题 ES变量包含两种不同数据类型的值,基本类型和引用类型. 基本类型有五种:Undefined, Null, Boolean, Number, String. 引用类型是保存在内存中的对象. 我们在访问基本类型和引用类型的时候会有一些差别. 1.1.1 复制变量值 var num1 = 5; var num2 = num1; 此时内存中 num1 和 num2 是完全独立的,修改任一个变量的值对另一个变量都不会有影响.因为 5 是一个基本类型值,从一个变量向另一个变量复制基本

读书笔记 - js高级程序设计 - 第四章 变量 作用域 和 内存问题

5种基本数据类型 可以直接对值操作 判断引用类型 var result = instanceof Array 执行环境 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中 执行环境的销毁 某个执行环境中的所有代码执行完毕后 该环境被销毁 保存在其中的所有变量了函数定义也会随之销毁 作用域链中的对象 全局执行环境的变更对象始终都是作用域链中的最后一个对象 没有块级作用域 if 和 for 内的变量 外部也可以访问 标记清除 不同浏览器 只不过垃圾时间的长短不同 引

JavaScript高级程序设计-第四章-变量、作用域和内存问题

ECMAScript变量 基本类型:5 引用类型 存于内存栈 实际对象位于内存堆 按值访问,可操作保存在变量中实际的值 js不能直接操作对象的内存空间,而是操作它的引用 不可添加属性和方法 可添加属性和方法 变量复制是一个实际的值,互不干扰 变量复制是一个指针,指向相同的对象,改变其中一个变量会影响另一个 Undefined   Null   Boolean   Number   String           variable typeof v v instanceof constructo

javascript高级程序设计第四章 变量、作用域和内存问题

变量包含两种,,基本类型和引用类型 基本类型是指一些简单的字段: 引用类型是?由多个值构成的对象  引用类型的值是保存在内存中的对象,在javascript中是不允许直接访问内存中的位置; 函数的参数是按照值类型进行传递的,函数的参数可以看作是一个局部变量. 检测类型: typeOf  用来检测基本类型的值用处大,在检测引用类型的值得时候用处不是很大  检测到的Null类型返回结果为Object, insctanceof 用来检测引用类型的值,当检测的对象是引用类型的值或者Object时返回tr

Spark 实践——用Scala和Spark进行数据分析

本文基于<Spark 高级数据分析>第2章 用Scala和Spark进行数据分析. 完整代码见 https://github.com/libaoquan95/aasPractice/tree/master/c2/Into 1.获取数据集 数据集来自加州大学欧文分校机器学习资料库(UC Irvine Machine Learning Repository),这个资料库为研究和教学提供了大量非常好的数据源, 这些数据源非常有意义,并且是免费的. 我们要分析的数据集来源于一项记录关联研究,这项研究是