机器学习_决策树_ID3算法_C4.5算法_CART算法及各个算法Python实现

下面的有些叙述基于我个人理解, 可能与专业书籍描述不同, 但是最终都是表达同一个意思, 如果有不同意见的小伙伴, 请在评论区留言, 我不胜感激.

参考:

周志华-机器学习

https://blog.csdn.net/xiaohukun/article/details/78112917

https://blog.csdn.net/fuqiuai/article/details/79456971

决策树简介

1. 问题背景

常规方式对样本进行分类, 会导致很大的性能问题, 样本需要不断重复检测每一项属性(属性之间还不能存在相关性), 例如: 人的体重由[年龄, 身高] 决定, 当获得一组样本 [20, 178], 可能我们会先将该数据归到20岁的阶段中, 然后判断身高, 最后判断体重, 我们也有可能先使用身高, 然后使用年龄, 最后判断体重, 排列组合的方式得出预测值, 这种毫无准则的选择判断会导致很大的计算量; 然而决策树使用**信息增益(当前属性对样本的贡献率) **, 根据信息增益从大到小选用对应的属性进行判断, 有针对性的选择可以有效地避免无用的计算, 通过选用合适的样本属性按照特定的规则进行判断, 对样本准确的分类, 现在遇到的问题就是如何构建一棵决策树, 构建出来的决策树还能准确预测结果, 下面将针对决策树定义, 信息量, 建立决策树需要遵守的规则, 优化等问题来讲解.

2. 决策树定义

决策树是基于树结构进行决策, 一棵决策树包含一个Root根节点(里面包含所有测试集, 测试集从Root处出发, 按照一定的决策方式, 不同的决策将导致每个样本最终拥有不同的预测结果), 以及若干内部节点和叶子节点, 叶子节点对应最终的决策结果, 每一个内部节点都是一个属性测试, 从Root到叶子节点的路径就是一个样本的决策过程, 当样本到达叶子节点的时候就是样本的预测结果.
决策树如下图:
Root: 包含所有的样本集
DECISION: 决策方式
Result: 决策结果
在这里插入图片描述

构造决策树

1. 问题背景

构建决策树需要有一个构建规则, 不同的构建规则将导致预测结果的不同, 当然, 不同的数据需要使用不同的构建规则, 这样才能最好地预测出结果, 下面将介绍3中不同的构建规则: 信息增益, 信息增益率, 基尼指数

2. 信息熵

信息熵是度量样本属性对最终预测结果的影响程度, 当某一属性的熵在正常情况下比其他属性的熵要大的时候, 我们就可以先选用该属性优先对样本进行分类(越是影响大的属性越容易影响预测结果, 越容易预测正确).
信息熵方程定义:
在这里插入图片描述
pk: 属性在样例中的比例

使用例子说明:
如下图片, 使用age, income, student, credit属性来判断一个人能否买电脑
在这里插入图片描述
使用buys_computer计算总的信息熵:
buys_computer包含2个子集 {yes, no}, 正例比例: 9/14, 反例比例: 5/14, 最终得到 Info(D)
在这里插入图片描述
同理计算age:
age包含3个子集 {youth, middle_aged, senior}, 分别计算youth, middle_aged, senior各自相对于正反例的比例值, 道理同上, 然后得到 Info_youth(D), Info_middle_aged(D), Info_senior(D).
由于不同子集样本相对于age数目不同, 所以:

Info_age(D) = youth_权重*Info_youth + middle_aged_权重*Info_middle_aged(D) + senior_权重*Info_senior(D)

最终age的信息熵计算结果:
在这里插入图片描述

3. 信息增益(ID3算法)

信息增益: 样本利用某一属性分类之后得到多少样本, 例如: 样本使用age属性分类, Gain(D, age) = 总的熵(即Info(D)) - Info_age(D)
信息增益方程定义:
在这里插入图片描述
V代表属性种类; D^V代表每种属性对应的样本数目;
Ent(D)代表Info(D); |D^v|/|D| 就是属性数目在样本中权重.
下面直接计算Gain(D, age), 计算age相对于总样本D的信息增益
在前面信息熵的计算中, 我们已经得出Info(D), Info_age(D), 按照公式只需做差
在这里插入图片描述
同理我们可以计算出: Gain(income) = 0.029, Gain(student) = 0.151, Gain(credit_rating)=0.048
因为Gain(age)最大, 就可以得出age对样本的影响程度最高, 因此构建决策树的时候, 选用age作为Root, 得出如下决策树:
注: 在离散型数据下, 使用过的属性就不再使用, 因为该属性对样本的影响在之前已经计算过, 再次使用会导致结果错误
在这里插入图片描述
这只是决策树第一层树的建立, 建立第二层的时候, 同理, 用youth对应的分类样本来说: 我们接下来从 income, student, credit来进行决策, 在当前样本正返例比例的基础上分别计算Info(D’), Info_income(D’), Info_student(D’), Info_credit(D’), 使用Info(D’) - Info_XXX(D’)计算信息增益, 然后从3个属性中选出信息增益最大的属性作为下一个节点, 根据该节点的子集进行分类决策. 整个过程是一个递归的过程, 不断重复, 直到如下条件时终止:

  • 给定结点的所有样本属于同一类(该样本中全是正例或者反例)
  • 没有剩余属性可以用来进一步划分样本(例如: 假如样本经过一系列划分后, 现在只有income, class两个标签, 只有income一个属性, 没有多余的属性进行下一步划分, 划分停止), 在样本中可能存在一部分反例, 一部分正例, 此时使用多数表决, 根据正返例个数决定当前叶子节点的类别.

详细算法流程如下:
在这里插入图片描述
算法文字描述:

  • 树以代表训练样本的单个结点开始(步骤1)。
  • 如果样本都在同一个类,则该结点成为树叶,并用该类标号(步骤2 和3)。
  • 否则,算法使用称为信息增益的基于熵的度量作为启发信息,选择能够最好地将样本分类的属性(步骤6)。该属性成为该结点的“测试”或“判定”属性(步骤7)。在算法的该版本中,所有的属性都是分类的,即离散值。连续属性必须离散化。
  • 对测试属性的每个已知的值,创建一个分枝,并据此划分样本(步骤8-10)。
  • 算法使用同样的过程,递归地形成每个划分上的样本判定树。一旦一个属性出现在一个结点上,就不必该结点的任何后代上考虑它(步骤13)

注: 上面的决策树建立方式是ID3算法, 这种算法很容易受信息增益的影响, 当某一属性对应的样本分布过于分散, 就比如使用样本id作为属性, 那么计算出来的Info_id(D)就会非常大, 对结果造成很大的影响, 下面将介绍信息增益率来减小这种影响
Python实现ID3:

from sklearn.feature_extraction import DictVectorizer
import csv
from sklearn import tree
from sklearn import preprocessing
from sklearn.externals.six import StringIO# Read in the csv file and put features into list of dict and list of class label
allElectronicsData = open(r'/home/zhoumiao/MachineLearning/01decisiontree/AllElectronics.csv', 'rb')
#获取csv文件中内容
reader = csv.reader(allElectronicsData)
headers = reader.next()print(headers)featureList = []
labelList = []#将每一行数据变为字典的形式存入列表中
#例如:[{age:youth, income:high...}, {...}, ...]
#直接使用库将这种格式的数据转变为0, 1格式
for row in reader:#获取每一行数据最后的标签labelList.append(row[len(row)-1])rowDict = {}for i in range(1, len(row)-1):rowDict[headers[i]] = row[i]featureList.append(rowDict)print(featureList)# Vetorize features
#使用本身的库进行转换,转变的只是每行对应0 1,并不满足sklearn需要的格式
vec = DictVectorizer()
dummyX = vec.fit_transform(featureList) .toarray()
print("dummyX: " + str(dummyX))print(vec.get_feature_names())print("labelList: " + str(labelList))# vectorize class labels
#针对每行最后的结果再进一步转换
lb = preprocessing.LabelBinarizer()
dummyY = lb.fit_transform(labelList)
print("dummyY: " + str(dummyY))# Using decision tree for classification
# clf = tree.DecisionTreeClassifier()
#设置分类器,设置不同的参数,使用不同的算法
clf = tree.DecisionTreeClassifier(criterion='entropy')
#建模,传入x,y矩阵
clf = clf.fit(dummyX, dummyY) 
print("clf: " + str(clf))# Visualize model
#将决策树clf转变为原始信息,然后存入dot文件中
with open("allElectronicInformationGainOri.dot", 'w') as f:f = tree.export_graphviz(clf, feature_names=vec.get_feature_names(), out_file=f)oneRowX = dummyX[0, :]
print("oneRowX: " + str(oneRowX))#修改原始数据,根据模型进行预测
newRowX = oneRowX
newRowX[0] = 1
newRowX[2] = 0
print("newRowX: " + str(newRowX))#获得预测结果
predictedY = clf.predict(newRowX)
print("predictedY: " + str(predictedY))

4. 信息增益率(C4.5算法)

相比于ID3算法来说, C4.5算法使用不同的Gain计算方式(计算角度不同, 弱化无关因素对结果预测的影响), 具体Gain计算如下:
信息增益率:
在这里插入图片描述
使用age对上面的公式进行解释:
Gain(D, age) = Info_age(D);
IV(a) = -5/14log(4/14) - 4/14log(4/14) - 5/14log(5/14)
Gain_ratio(D,age) = Info_age(D)/IV(a)
当属性子集越多, 则IV(a)就会越大, 得到的Gain_ratio就会越小, 从而达到: 避免因为属性子集过多而导致信息增长过大影响判断结果.
注:增长率对子集过少的属性也会有偏好, 就比如id与age, 增长率对age将会表现出偏向, 从而使用age作为节点, 而不是id, 避免结果的预测错误.

选用属性方式:

  1. 计算出所有属性的Gain_ratio, 以及平均Gain_ratio
  2. 然后找出高于平均水平的属性
  3. 再从步骤2中找出Gain_ratio最高的属性作为划分依据, 随后的操作就重复即可.
    使用C4.5算法与ID3算法的区别就是选取的Gain不同, 其他操作都是一样的, 最后的递归终止条件与ID3是相同的.

算法描述:

while (当前节点”不纯“)  (1)计算当前节点的类别信息熵Info(D) (以类别取值计算)  (2)计算当前节点各个属性的信息熵Info(Ai) (以属性取值下的类别取值计算)  (3)计算各个属性的信息增益Gain(Ai)=Info(D)-Info(Ai)  (4)计算各个属性的分类信息度量H(Ai) (以属性取值计算)  (5)计算各个属性的信息增益率IGR(Ai)=Gain(Ai)/H(Ai)  
end while  
当前节点设置为叶子节点  

代码如下:

# encoding=utf-8import cv2
import time
import numpy as np
import pandas as pdfrom sklearn.cross_validation import train_test_split
from sklearn.metrics import accuracy_score# 二值化
def binaryzation(img):cv_img = img.astype(np.uint8)cv2.threshold(cv_img,50,1,cv2.THRESH_BINARY_INV,cv_img)return cv_imgdef binaryzation_features(trainset):features = []for img in trainset:img = np.reshape(img,(28,28))cv_img = img.astype(np.uint8)img_b = binaryzation(cv_img)# hog_feature = np.transpose(hog_feature)features.append(img_b)features = np.array(features)features = np.reshape(features,(-1,feature_len))return featuresclass Tree(object):def __init__(self,node_type,Class = None, feature = None):self.node_type = node_type  # 节点类型(internal或leaf)self.dict = {} # dict的键表示特征Ag的可能值ai,值表示根据ai得到的子树 self.Class = Class  # 叶节点表示的类,若是内部节点则为noneself.feature = feature # 表示当前的树即将由第feature个特征划分(即第feature特征是使得当前树中信息增益最大的特征)def add_tree(self,key,tree):self.dict[key] = treedef predict(self,features): if self.node_type == 'leaf' or (features[self.feature] not in self.dict):return self.Classtree = self.dict.get(features[self.feature])return tree.predict(features)# 计算数据集x的经验熵H(x)
def calc_ent(x):x_value_list = set([x[i] for i in range(x.shape[0])])ent = 0.0for x_value in x_value_list:p = float(x[x == x_value].shape[0]) / x.shape[0]logp = np.log2(p)ent -= p * logpreturn ent# 计算条件熵H(y/x)
def calc_condition_ent(x, y):x_value_list = set([x[i] for i in range(x.shape[0])])ent = 0.0for x_value in x_value_list:sub_y = y[x == x_value]temp_ent = calc_ent(sub_y)ent += (float(sub_y.shape[0]) / y.shape[0]) * temp_entreturn ent# 计算信息增益
def calc_ent_grap(x,y):base_ent = calc_ent(y)condition_ent = calc_condition_ent(x, y)ent_grap = base_ent - condition_entreturn ent_grap# C4.5算法
def recurse_train(train_set,train_label,features):LEAF = 'leaf'INTERNAL = 'internal'# 步骤1——如果训练集train_set中的所有实例都属于同一类Cklabel_set = set(train_label)if len(label_set) == 1:return Tree(LEAF,Class = label_set.pop())# 步骤2——如果特征集features为空class_len = [(i,len(list(filter(lambda x:x==i,train_label)))) for i in range(class_num)] # 计算每一个类出现的个数(max_class,max_len) = max(class_len,key = lambda x:x[1])if len(features) == 0:return Tree(LEAF,Class = max_class)# 步骤3——计算信息增益,并选择信息增益最大的特征max_feature = 0max_gda = 0D = train_labelfor feature in features:# print(type(train_set))A = np.array(train_set[:,feature].flat) # 选择训练集中的第feature列(即第feature个特征)gda = calc_ent_grap(A,D)if calc_ent(A) != 0:  ####### 计算信息增益比,这是与ID3算法唯一的不同gda /= calc_ent(A)if gda > max_gda:max_gda,max_feature = gda,feature# 步骤4——信息增益小于阈值if max_gda < epsilon:return Tree(LEAF,Class = max_class)# 步骤5——构建非空子集sub_features = list(filter(lambda x:x!=max_feature,features))tree = Tree(INTERNAL,feature=max_feature)max_feature_col = np.array(train_set[:,max_feature].flat)feature_value_list = set([max_feature_col[i] for i in range(max_feature_col.shape[0])]) # 保存信息增益最大的特征可能的取值 (shape[0]表示计算行数)for feature_value in feature_value_list:index = []for i in range(len(train_label)):if train_set[i][max_feature] == feature_value:index.append(i)sub_train_set = train_set[index]sub_train_label = train_label[index]sub_tree = recurse_train(sub_train_set,sub_train_label,sub_features)tree.add_tree(feature_value,sub_tree)return treedef train(train_set,train_label,features):return recurse_train(train_set,train_label,features)def predict(test_set,tree):result = []for features in test_set:tmp_predict = tree.predict(features)result.append(tmp_predict)return np.array(result)class_num = 10  # MINST数据集有10种labels,分别是“0,1,2,3,4,5,6,7,8,9”
feature_len = 784  # MINST数据集每个image有28*28=784个特征(pixels)
epsilon = 0.001  # 设定阈值if __name__ == '__main__':print("Start read data...")time_1 = time.time()raw_data = pd.read_csv('../data/train.csv', header=0)  # 读取csv数据data = raw_data.valuesimgs = data[::, 1::]features = binaryzation_features(imgs) # 图片二值化(很重要,不然预测准确率很低)labels = data[::, 0]# 避免过拟合,采用交叉验证,随机选取33%数据作为测试集,剩余为训练集train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33, random_state=0)time_2 = time.time()print('read data cost %f seconds' % (time_2 - time_1))# 通过C4.5算法生成决策树print('Start training...')tree = train(train_features,train_labels,list(range(feature_len)))time_3 = time.time()print('training cost %f seconds' % (time_3 - time_2))print('Start predicting...')test_predict = predict(test_features,tree)time_4 = time.time()print('predicting cost %f seconds' % (time_4 - time_3))# print("预测的结果为:")# print(test_predict)for i in range(len(test_predict)):if test_predict[i] == None:test_predict[i] = epsilonscore = accuracy_score(test_labels, test_predict)print("The accruacy score is %f" % score)

5. 基尼指数(CART决策树)

CART决策树使用基尼指数(所谓的信息熵)作为判断属性是否可以作为划分依据,
特点:

  1. CART 既能是分类树,又能是回归树.
  2. 当CART是分类树时,采用GINI值作为节点分裂的依据;当CART是回归树时,采用样本的最小方差作为节点分裂的依据.

基尼指数计算:
在这里插入图片描述
在这里插入图片描述
Gini(D)描述从样本中随机抽取两个样本, 不一样概率的大小, Gini越大说明该属性的样本越少, 因此该属性对样本的总影响就越小.
a属性对样本预测结果的影响, 影响越大,Gini_index(D, a)值越小,反之,则GINI值越大.
其中,pk表示节点中属于类k的概率.
下面使用一个例子说明:
按照职业属性划分, 预测是否结婚
在这里插入图片描述
预测是否结婚:
Gini(married, occupation) = 3/7[1− (2/3)^2 − (1/3)^2] + 4/7[1 − (3/4)^2 − (1/4)^2]=0.4
同理可计算看电视时间, 年龄对是否结婚的Gini

CART决策树算法流程:
每次划分的时候, 需要选择基尼指数最小的属性作为最优划分属性
在这里插入图片描述
Python使用sklearn代码实现CRAT:

from sklearn import datasets
from sklearn import tree
from sklearn.externals.six import StringIO
import pydot# 加载Iris数据集
iris = datasets.load_iris()
#不传入参数, 使用默认算法CRAT实现分类
clf = tree.DecisionTreeClassifier()
clf = clf.fit(iris.data, iris.target)dot_data = StringIO()  
tree.export_graphviz(clf, out_file=dot_data, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True)  
# tree.export_graphviz(clf, out_file=r"tree.dot") #把这行代码放开可以生成决策树的文件
(graph,) = pydot.graph_from_dot_data(dot_data.getvalue())  
graph.write_png('iris.png')

总结:

三种算法各有自己的Grain计算方式, 构建树的过程, 区别就在于Grain计算的不同, 最优属性选择的不同, 剩下都是相同的.

如果有什么问题, 请在下方留言, 感觉不错的话, 请为我点个赞, O(∩_∩)O谢谢

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

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

相关文章

http数据绑定spring mvc详解

转载于:https://www.cnblogs.com/panxuejun/p/6834365.html

ESP32 入门教学,不入门,不教学

&#xff11;.Internet of things &#xff08;iot&#xff09;这个概念非常火&#xff0c;物联网是什么&#xff1f;把所有物品通过射频识别等信息传感设备与互联网连接起来&#xff0c;实现智能化识别和管理。 物联网通过智能感知、识别技术与普适计算、泛在网络的融合应用&a…

一个从华为离职的朋友

1、我在之前的很多文章里面都谈到了我有一个过硬的华为朋友&#xff0c;我很少去炫耀自己有多厉害&#xff0c;认识了谁谁&#xff0c;但是我非常在意那些跟自己有过交情的朋友&#xff0c;这些朋友不是说你离开了就失去了&#xff0c;也不是你落魄了就不能吹水了&#xff0c;今…

机器学习_简单线性回归与多元回归方程原理推导_处理二值数据_最小二乘法解或梯度下降解多元回归方程(详细推导)以及Python代码实现_回归方程度量方式

下面的有些叙述基于我个人理解, 可能与专业书籍描述不同, 但是最终都是表达同一个意思, 如果有不同意见的小伙伴, 请在评论区留言, 我不胜感激. 参考: 周志华-机器学习 最小二乘法求解多元回归方程: https://blog.csdn.net/weixin_39445556/article/details/83543945 梯度下…

手写Java线程池_超详细解说_绝对能运行_代码超详细注释

线程池 问题背景 只是单纯使用 new Thread(runnable).start(); 的方式创建线程, 将会导致严重的程序性能问题: 1.线程创建, 销毁需要消耗很大的系统资源; 2.虚拟机创建线程的数量是有限的; 2.线程调度切换也将使程序性能下降; 针对这些问题, 对线程数量进行管理, 有效地重复利…

分享一个非常 nice 的工具

最近有个问题&#xff0c;我需要经常使用远程连接工具&#xff0c;原因很简单&#xff0c;我需要控制另外一台电脑&#xff0c;我刚开始使用的是 teamviewer 这个软件&#xff0c;刚开始用的时间是非常爽的&#xff0c;不过有一天他给我来了个提示&#xff0c;说我的软件被商用…

推荐周立功先生的一本书

1. 这篇文章主要是推荐周工的一本书&#xff0c;大家在学习嵌入式的时候&#xff0c;很多人不明白嵌入式系统和单片机的区别&#xff0c;又感觉自己对嵌入式有所了解&#xff0c;知道什么是嵌入式&#xff0c;文章里的很多见解我觉得对很多人都非常有帮助&#xff0c;今晚上周工…

图管够!灌篮高手、女儿国…阿里日_这帮程序员太会玩了!

5月10日是阿里一年一度的阿里日&#xff0c;这对阿里人来说&#xff0c;是个非常特别的日子。 那什么是阿里日呢&#xff1f;看看官方介绍&#xff1a; 它起源于2005年4月20日&#xff0c;是为了纪念2003年5月的“非典”时期阿里人的激情和信念。因此阿里巴巴决定&#xff0c;今…

复习Collection_迭代器使用细节_泛型_综合案例

Collection_迭代器使用细节_泛型_综合案例 主要内容 Collection集合迭代器增强for泛型 第一章 Collection集合 1.1 集合概述 集合&#xff1a;集合是java中提供的一种容器&#xff0c;可以用来存储多个数据。 集合和数组既然都是容器&#xff0c;他们之间的区别: 数组的…

Kubernetes dashboard集成heapster

图形化展示度量指标的实现需要集成k8s的另外一个Addons组件&#xff1a; Heapster 。 Heapster原生支持K8s(v1.0.6及以后版本)和 CoreOS &#xff0c;并且支持多种存储后端&#xff0c;比如&#xff1a; InfluxDB 、 ElasticSearch 、 Kafka 。 下载源包和images文件 下载地址h…

ESP32 分区介绍

软件设计分区表 如上图是正常运行需要的分区&#xff0c;一个系统的正常运行是需要这么多分区的。 分区表&#xff0c;我们软件默认配置的分区表如下 # Espressif ESP32 Partition Table # Name, Type, SubType, Offset, Size, Flags nvs,data,nvs,0x9000,16K, otadata,data,…

python坦克大战_Life is short,you need Python——Python实现坦克大战(一)

先展示一下效果搓搓小手手&#xff0c;坦克大战即将开始……https://www.zhihu.com/video/1140743290784817152一、游戏引擎的安装安装方式有两种&#xff1a;1.pip安装 windows R --> cmd --> pip install pygame2.pycharm安装 File -->setting -->project -->…

复习Java字节流_字符流使用及案例

字节流_字符流 主要内容 IO流字节流字符流异常处理Properties 第一章 IO概述 1.1 什么是IO 生活中&#xff0c;你肯定经历过这样的场景。当你编辑一个文本文件&#xff0c;忘记了ctrls &#xff0c;可能文件就白白编辑了。当你电脑上插入一个U盘&#xff0c;可以把一个视频…

ESP32 coredump 分析

1. 上次写了一个 ESP32 入门&#xff0c;我想有必要再写这篇文章&#xff0c;这次主要是分析 coredump 的&#xff0c;这就像 Android 和 Linux 系统的死机分析&#xff0c;有意思&#xff0c;也有难度。我们写代码的时候&#xff0c;不可避免的会遇到一些 coredump 的问题&am…

我那个在华为过得很好的朋友

最近华为的事件又上了热搜&#xff0c;不管是微信还是知乎&#xff0c;都在啃这个热点&#xff0c;一种是看热闹不闲事大的&#xff0c;一种是看热闹闲事大的&#xff0c;我呢&#xff1f;昨晚跟我的一个华为朋友玩了几把王者荣耀&#xff0c;虽然不能带他全盘浪&#xff0c;但…

Redis概述_使用命令对redis的数据进行增删改查_Jedis连接redis进行数据操作_redis进行数据缓存案例

学习目标 redis 概念下载安装命令操作 1. 数据结构持久化操作使用Java客户端操作redis Redis 前言(从百度上抄的, 看看了解一下, 懒得排版了) 1. 概念&#xff1a; redis是一款高性能的NOSQL系列的非关系型数据库1.1.什么是NOSQLNoSQL(NoSQL Not Only SQL)&#xff0c;意即…

要有敬畏之心

最近开始周六也没有休息&#xff0c;心理上还是很难接受&#xff0c;也不是说周六上班有多累&#xff0c;就是没有找到对的感觉&#xff0c;就像和一个不喜欢的姑娘相亲&#xff0c;就算姑娘家财万贯&#xff0c;貌美如花&#xff0c;自己还是提不起兴趣&#xff0c;可能这就是…

复习Java_List_Set_HashSet原理_Collections使用_Comparator使用

复习Java_List_Set_HashSet原理_Collections使用_Comparator使用 主要内容 数据结构List集合Set集合Collections 第一章 数据结构 2.1 数据结构有什么用&#xff1f; 加快应用开发, 提高程序健壮性, 提高程序可重用性 2.2 常见的数据结构 数据存储的常用结构有&#xff…

最近,我也要买书了

1.当当网给我做的一个活动&#xff0c;购书优惠&#xff0c;确实是福利了&#xff0c;而且筛选的书籍对我们做嵌入式都是比较有帮助的&#xff0c;你应该知道&#xff0c;做活动的时候&#xff0c;价格都是比较不错&#xff0c;不要错过了时间再想要当时的价格&#xff0c;有需…

复习Java异常处理_异常分类_自定义异常_线程初步了解

复习Java异常处理_异常分类_自定义异常_线程 主要内容 异常、线程 教学目标 第一章 异常 1.1 异常概念 异常&#xff0c;就是不正常的意思。在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是&#xff1a; 异常…