随机森林计算指标重要性—从决策树到随机森林Python实现

文章目录

  • 前言
  • 一、节点
  • 二、决策树
    • 2.1 案例分析——优良的水稻
    • 2.2 案例分析——家庭财富水平
  • 三、随机森林
  • 三、Python代码实现
    • 3.1 关键问题
      • 3.1.1 节点的表示
      • 3.1.2 决策树的表示
      • ** 根节点划分左右子树的依据 **
      • 3.1.3 随机森林的构造与重要性的表示
    • 3.2 节点类
    • 3.2 决策树类
      • 3.2.1 初始化
      • 3.2.2 计算方差
      • 3.2.3 选择最佳划分特征和阈值
      • 3.2.4 构建决策树
      • 3.2.5 训练与预测
      • 3.2.6 计算指标重要性
      • 3.2.6 绘制决策树(调试方法)
    • 3.4 随机森林类
      • 3.4.1 初始化
      • 3.4.2 训练(构造)随机森林
      • 3.4.3 获取特征重要性
  • 四、程序测试
    • 4.1 测试代码
    • 4.2 测试结果
  • 五、完整代码

前言

善始者繁多,克终者盖寡。

在某个评价体系中,计算指标重要性(或者称之为“权重”)的方法有基于经验的方法,例如层次分析法、德尔菲法,有基于统计学的方法,例如熵权法、离差最大化法,机器学习的发展为指标重要性的计算提供了新的思路。

已有大量的研究将神经网络算法应用于指标权重的计算上,最简单的就是三层结构的BP神经网络,但是使用神经网络算法时通常需要输入数据具备相同的量纲,也就是输入数据需要进行归一化处理,当然数据归一化益处多多,但此过程对异常数据极其敏感,可能导致数据分布改变,从而导致原始数据信息损失。而使用决策树则可以很好的避免数据归一化引起的系列问题,除必要的数据清洗外,通常情况下不需要对原始数据进行任何处理就可以应用决策树算法。从数据结构角度看,决策树算法就是构建一棵二叉树的过程,为了提高系统的准确率和泛化能力,通常在数据集中随机选择数据构建决策树,若干决策树组成了森林,于是就有了随机森林

注意:并不是说神经网络和决策树谁好谁差,只不过是两种算法的应用场景有所差异,不知如何选择时可以在相同数据集上使用这两种方法,选择效果最佳的一种。

一、节点

为了交流方便,我们将存放数据的最小单位为“节点”,它至少包含两个信息:数据本身和数据的描述,一个节点可以描述为:

在这里插入图片描述

二、决策树

多个节点共同组成了一颗树,下图所示的都可以称之为“树”:
在这里插入图片描述

根据节点中最大分支个数我们给这些树取名字,例如图1和图2中的树我们称之为“三叉树”,图3中的树我们称之为“二叉树”,这个“二叉树”像极了帮我们做选择的助手,从第一个节点出发后要么走左边的节点,要么走右边的节点,于是我们称这样的结构为“决策树”。

2.1 案例分析——优良的水稻

假设我们可以通过“稻穗大小、稻杆长短、颜色程度”三个指标判断水稻是否为优良品种,优良品种的特征有“稻穗大、稻杆短、颜色金黄”三个特征,主要满足两个就属于优良品种,现已有三份水稻样品:

在这里插入图片描述

按照人的思维和习惯我们可以逐步划分,即得到如下的决策树,我们很容易判断上述表格中三份水稻样品的品质分别为“优良、其他、其他”。

本例中包含3个属性,所以决策树的深度为3(只看圆的,椭圆是判断结果),如果我们先判断“稻杆”或者“颜色”,我们便会得到一棵不同的决策树,但是不论如何选择决策树的最大深度都是3。值得注意的是本例中所有属性的取值都只有两个,但现实世界中的情况往往复杂的多。

在这里插入图片描述

2.2 案例分析——家庭财富水平

假设我们可以通过“月收入、汽车数量、房屋数量”三项指标评估某个家庭的财富水平,已知“月收入>=50000、汽车数量>=5、房屋数量>=5”三项条件中,满足两项及以上的家庭为“富有”,满足一项的家庭为“中等”,一项不满足的家庭为“贫困”,现已收集到三个家庭的数据:

在这里插入图片描述

我们同样可以构造一棵决策树,我们不难判断出上表三个家庭的财富水平分别为“富有、贫困、中等”。

本例中我们使用了连续型数据,发现虽然决策树的深度相同,但产生的结果比2.1复杂了许多,随着属性的增多、数据的增多,人工构造决策树的难度会大大提高

在这里插入图片描述

三、随机森林

使用相同的数据可以生成不同的决策树,当数据集足够庞大时我们需要限制每一棵决策树的深度,以增强模型的泛化能力,这就使得每棵决策树产生了差异,随机森林就是考虑每一棵决策树的差异,以期提供最佳决策方案。

确定每棵决策树的深度、森林中决策树的数量是随机森林算法的关键。

三、Python代码实现

3.1 关键问题

3.1.1 节点的表示

一棵树中的节点应当包含如下信息:节点的描述、节点的数据、左子树、右子树。具体到一颗决策树中,这四项信息可以具体描述为:属性(何处对树分支)、阈值(划分左右子树的标准)、左子树(左子树的根节点)、右子树(右子树的根节点)

在这里插入图片描述

3.1.2 决策树的表示

在一棵树中,只有我们知道了一个树的根节点,我们就可以遍历整棵树;为了防止过拟合以及节省系统资源,我们必须指定树的最大深度

根据实际情况,我们需要解决的问题是:计算指标重要性。所有我们还需要知道属性的总个数

那决策树的根节点在选择属性A和阈值x1划分后得到属性A取值全大于等于x1和属性A取值全小于x1的两部分数据,即left和right,那left根节点划分时会不会再次选择A属性进行划分呢????
答案是完全有可能! 所以,我们还需要一个变量用于存储 决策树中使用到的属性的个数

** 根节点划分左右子树的依据 **

方差。本例中使用“方差”考量原系统的聚合程度、划分后系统的聚合程度 。理想状态下,随着决策树的划分,系统的聚合程度越来越高,即系统的方差越来越小,相似的样本被划分到一起,所有决策树最早是被用来解决分类问题。

3.1.3 随机森林的构造与重要性的表示

使用“出现频次”表示属性的重要性。

通过循环构建若干决策树,决策树的集合就构成了随机森林,随机森林中包含若干决策树,统计每棵决策树中各属性出现的频次,出现频次高的属性其重要性强,反之则弱

3.2 节点类

节点的left、right属性存储的是左右子树的根节点
在实际操作中我们使用“ 属性的索引 ”代替具体的属性名称,以方便程序操作。

# 决策树节点
class TreeNode:def __init__(self, feature_index=None, threshold=None, left=None, right=None):# 特征索引(在决策树按哪个特征进行分支)self.feature_index = feature_index# 阈值(在决策树中按某个特征的某个值划分左右子树)self.threshold = threshold# 左子树self.left:TreeNode = left# 右子树self.right:TreeNode = right

3.2 决策树类

3.2.1 初始化

class DecisionTreeRegressor:def __init__(self, max_depth=None,feature_numbers=None):# 指定决策树的最大深度self.max_depth = max_depth# 返回整棵决策树(也就是根节点,可通过根节点遍历整棵树)self.bootnode:TreeNode = None# 属性的总个数self.feature_numbers = np.zeros(feature_numbers)# 树中出现属性的个数self.available_feature_numbers = 0

3.2.2 计算方差

    # 计算数据集的方差(使用方差作为目标函数)def _calculate_variance(self, y):return np.var(y)# 计算划分后的两个数据集的加权方差(用来寻找最合适划分子树的方法,让方差最小)def _calculate_weighted_variance(self, left_y, right_y):n = len(left_y) + len(right_y)left_var = self._calculate_variance(left_y)right_var = self._calculate_variance(right_y)weighted_var = (len(left_y) / n) * left_var + (len(right_y) / n) * right_varreturn weighted_var

3.2.3 选择最佳划分特征和阈值

    # 选择最佳划分特征和阈值def _find_best_split(self, X, y):m, n = X.shape# 计算当前划分方法系统方差变化值(减少量),方差减少的越多越好best_var_reduction = 0best_feature_index = Nonebest_threshold = None# 计算当前节点的方差current_var = self._calculate_variance(y)# 有n个特征值,要进行n次判断for feature_index in range(n):'''找到每一个特征值中的唯一值(返回值是一个列表)依次取出列表中的值作为阈值计算系统方差变化情况'''thresholds = np.unique(X[:, feature_index])for threshold in thresholds:'''np.where方法返回的是元组对象元组中包含了在feature_index特征上取值小于等于阈值的行索引,使用[0]取出'''left_indices = np.where(X[:, feature_index] <= threshold)[0]right_indices = np.where(X[:, feature_index] > threshold)[0]# 如果划分到最后,该节点无法划分出左子树或者右子树,说明该节点已经是叶子节点了,跳过if len(left_indices) == 0 or len(right_indices) == 0:continue# 取出左右子树记录,为计算系统方差做准备left_y = y[left_indices]right_y = y[right_indices]# 计算加权方差的减少量var_reduction = current_var - self._calculate_weighted_variance(left_y, right_y)# 更新最佳划分(减少量越大越好,说明系统方差小)if var_reduction > best_var_reduction:best_var_reduction = var_reductionbest_feature_index = feature_indexbest_threshold = thresholdreturn best_feature_index, best_threshold

3.2.4 构建决策树

    # 递归构建决策树def _build_tree(self, X, y, depth):if depth == self.max_depth or len(np.unique(y)) == 1:return TreeNode(None, None, None, None)# 找到划分的属性和阈值feature_index, threshold = self._find_best_split(X, y)if feature_index is None or threshold is None:return TreeNode(None, None, None, None)left_indices = np.where(X[:, feature_index] <= threshold)[0]right_indices = np.where(X[:, feature_index] > threshold)[0]left_child = self._build_tree(X[left_indices], y[left_indices], depth + 1)right_child = self._build_tree(X[right_indices], y[right_indices], depth + 1)return TreeNode(feature_index, threshold, left_child, right_child)

3.2.5 训练与预测

决策树的训练就是构建决策树的过程。
在决策树中通常采用均值表示某条记录的预测值。(计算指标重要性不需要使用预测方法)

    # 计算数据集的均值def _calculate_mean(self, y):return np.mean(y)# 训练决策树模型def fit(self, X, y):self.bootnode = self._build_tree(X, y, 0)# 预测单个样本def _predict_one(self, x, node):if node.feature_index is None or node.threshold is None:return self._calculate_mean(x)if x[node.feature_index] <= node.threshold:return self._predict_one(x, node.left)else:return self._predict_one(x, node.right)# 批量预测def predict(self, X):return np.array([self._predict_one(x, self.bootnode) for x in X])

3.2.6 计算指标重要性

    # 计算树中各特征值出现频次def _calculate_features(self,node:TreeNode):if node.feature_index is not None:self.feature_numbers[node.feature_index] += 1self.available_feature_numbers += 1self._calculate_features(node.left)self._calculate_features(node.right)# 将树中特征出现频次转换为特征重要性def calculate_importance(self):self._calculate_features(self.bootnode)return self.feature_numbers/self.available_feature_numbers

3.2.6 绘制决策树(调试方法)

像神经网络这样的模型,其结构是在创建之前就设定好了的,但决策树不同,在调试时可以打印出决策树中各节点信息,绘制决策树,以判断程序运行效果是否满足研究的需要。

    def show(self,node:TreeNode):list = ["根","左","右"]if node.feature_index is not None:print(list[0],node.feature_index)# print("->",end="")# print(node.threshold)if node.left is not None:print(list[1],"--", end="")self.show(node.left)else:print(list[1],"--None")if node.right is not None:print(list[2],"--", end="")self.show(node.right)else:print(list[2],"--None")else:print(list[0], "--None")

3.4 随机森林类

3.4.1 初始化

class RandomForestRegressor:def __init__(self, n_estimators=None, max_depth=None, max_features=None):# 若干棵决策树组成森林,树的数量self.n_estimators = n_estimators# 每一棵决策树具有相同的深度self.max_depth = max_depth# 每一棵决策树的特征综素相同self.max_features = max_features# 若干棵决策树组成的列表,就是我们需要的随机森林了self.trees = []

3.4.2 训练(构造)随机森林

    # 训练随机森林,也就是向列表中依次添加决策树def fit(self, X, y):for _ in range(self.n_estimators):# 随机选择数据子集和特征子集n_samples = X.shape[0]# 从样本中随机选择n_samples条记录,记录可重复bootstrap_indices = np.random.choice(n_samples, size=n_samples, replace=True)bootstrap_X = X[bootstrap_indices]bootstrap_y = y[bootstrap_indices]tree = DecisionTreeRegressor(max_depth=self.max_depth,feature_numbers=self.max_features)tree.fit(bootstrap_X, bootstrap_y)self.trees.append(tree)

3.4.3 获取特征重要性

特征重要性是在决策树类中计算的,在随机森林中只需要统计各决策树中特征重要性并求均值即可。

    # 获取特征重要性def feature_importances(self, X, y):n_features = X.shape[1]total_importances = np.zeros(n_features)# 计数,统计每一棵树中各特征值出现的频次,出现频次越多说明该特征越重要for one_tree in self.trees:importance = one_tree.calculate_importance()total_importances += importance# 计算n_estimators棵树中,各特征值的平均重要程度(还是通过出现频次表示)return total_importances / self.n_estimators

四、程序测试

4.1 测试代码

load_data_primal方法用于读取数据文件,文件中前3列为基本信息,最后以来为期望输出,其余10列为原始数据。

测试程序中构建了一个包含100棵树、每棵树最大深度为10、输入样本特征为10的随机森林。


def load_data_primal():df = pd.read_excel("data.xlsx")data_temp  = df.iloc[:,3:-1]label_temp = df["综合评分"]data = []label = []for i in range(df.shape[0]):data.append(data_temp.iloc[i].to_list())temp = []temp.append(label_temp[i])label.append(temp)data = np.array(data)label = np.array(label)return data,labelif __name__ == '__main__':# 生成示例数据集X, y = load_data_primal()# print(X)# print(y)# 构建随机森林模型rf = RandomForestRegressor(n_estimators=100, max_depth=10, max_features=10)rf.fit(X, y)#for one_tree in rf.trees:#    one_tree.show(one_tree.bootnode)# 获取特征重要性importances = rf.feature_importances(X, y)# 先使用argsort进行降序排序,再进行反转indices = np.argsort(importances)[::-1]# 打印特征重要性print("Feature ranking:")for f in range(X.shape[1]):print("%d. feature %d (%f)" % (f + 1, indices[f], importances[indices[f]]))# 可视化特征重要性plt.figure()plt.title("Feature importances")plt.bar(range(X.shape[1]), importances[indices], color="r", align="center")plt.xticks(range(X.shape[1]), indices)plt.xlim([-1, X.shape[1]])plt.show()

4.2 测试结果

本例中以“出现频次”作为判断特征重要性的依据,显示的是对频次处理后的结果。

在这里插入图片描述

五、完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt# 决策树节点
class TreeNode:def __init__(self, feature_index=None, threshold=None, left=None, right=None):# 特征索引(在决策树按哪个特征进行分支)self.feature_index = feature_index# 阈值(在决策树中按某个特征的某个值划分左右子树)self.threshold = threshold# 左子树self.left:TreeNode = left# 右子树self.right:TreeNode = right# 决策树模型(通过递归创建)
class DecisionTreeRegressor:def __init__(self, max_depth=None,feature_numbers=None):# 指定决策树的最大深度self.max_depth = max_depth# 返回整棵决策树(也就是根节点,可通过根节点遍历整棵树)self.bootnode:TreeNode = None# 属性的总个数self.feature_numbers = np.zeros(feature_numbers)# 树中出现属性的个数self.available_feature_numbers = 0# 计算数据集的方差(使用方差作为目标函数)def _calculate_variance(self, y):return np.var(y)# 计算数据集的均值def _calculate_mean(self, y):return np.mean(y)# 计算树中各特征值出现频次def _calculate_features(self,node:TreeNode):if node.feature_index is not None:self.feature_numbers[node.feature_index] += 1self.available_feature_numbers += 1self._calculate_features(node.left)self._calculate_features(node.right)# 将树中特征出现频次转换为特征重要性def calculate_importance(self):self._calculate_features(self.bootnode)return self.feature_numbers/self.available_feature_numbers# 计算划分后的两个数据集的加权方差(用来寻找最合适划分子树的方法,让方差最小)def _calculate_weighted_variance(self, left_y, right_y):n = len(left_y) + len(right_y)left_var = self._calculate_variance(left_y)right_var = self._calculate_variance(right_y)weighted_var = (len(left_y) / n) * left_var + (len(right_y) / n) * right_varreturn weighted_var# 选择最佳划分特征和阈值def _find_best_split(self, X, y):m, n = X.shape# 计算当前划分方法系统方差变化值(减少量),方差减少的越多越好best_var_reduction = 0best_feature_index = Nonebest_threshold = None# 计算当前节点的方差current_var = self._calculate_variance(y)# 有n个特征值,要进行n次判断for feature_index in range(n):'''找到每一个特征值中的唯一值(返回值是一个列表)依次取出列表中的值作为阈值计算系统方差变化情况'''thresholds = np.unique(X[:, feature_index])for threshold in thresholds:'''np.where方法返回的是元组对象元组中包含了在feature_index特征上取值小于等于阈值的行索引,使用[0]取出'''left_indices = np.where(X[:, feature_index] <= threshold)[0]right_indices = np.where(X[:, feature_index] > threshold)[0]# 如果划分到最后,该节点无法划分出左子树或者右子树,说明该节点已经是叶子节点了,跳过if len(left_indices) == 0 or len(right_indices) == 0:continue# 取出左右子树记录,为计算系统方差做准备left_y = y[left_indices]right_y = y[right_indices]# 计算加权方差的减少量var_reduction = current_var - self._calculate_weighted_variance(left_y, right_y)# 更新最佳划分(减少量越大越好,说明系统方差小)if var_reduction > best_var_reduction:best_var_reduction = var_reductionbest_feature_index = feature_indexbest_threshold = thresholdreturn best_feature_index, best_threshold# 递归构建决策树def _build_tree(self, X, y, depth):if depth == self.max_depth or len(np.unique(y)) == 1:return TreeNode(None, None, None, None)# 找到划分的属性和阈值feature_index, threshold = self._find_best_split(X, y)if feature_index is None or threshold is None:return TreeNode(None, None, None, None)left_indices = np.where(X[:, feature_index] <= threshold)[0]right_indices = np.where(X[:, feature_index] > threshold)[0]left_child = self._build_tree(X[left_indices], y[left_indices], depth + 1)right_child = self._build_tree(X[right_indices], y[right_indices], depth + 1)return TreeNode(feature_index, threshold, left_child, right_child)# 训练决策树模型def fit(self, X, y):self.bootnode = self._build_tree(X, y, 0)# 预测单个样本def _predict_one(self, x, node):if node.feature_index is None or node.threshold is None:return self._calculate_mean(x)if x[node.feature_index] <= node.threshold:return self._predict_one(x, node.left)else:return self._predict_one(x, node.right)# 批量预测def predict(self, X):return np.array([self._predict_one(x, self.bootnode) for x in X])def show(self,node:TreeNode):list = ["根","左","右"]if node.feature_index is not None:print(list[0],node.feature_index)# print("->",end="")# print(node.threshold)if node.left is not None:print(list[1],"--", end="")self.show(node.left)else:print(list[1],"--None")if node.right is not None:print(list[2],"--", end="")self.show(node.right)else:print(list[2],"--None")else:print(list[0], "--None")# 定义随机森林模型
class RandomForestRegressor:def __init__(self, n_estimators=None, max_depth=None, max_features=None):# 若干棵决策树组成森林,树的数量self.n_estimators = n_estimators# 每一棵决策树具有相同的深度self.max_depth = max_depth# 每一棵决策树的特征综素相同self.max_features = max_features# 若干棵决策树组成的列表,就是我们需要的随机森林了self.trees = []# 训练随机森林,也就是向列表中依次添加决策树def fit(self, X, y):for _ in range(self.n_estimators):# 随机选择数据子集和特征子集n_samples = X.shape[0]# 从样本中随机选择n_samples条记录,记录可重复bootstrap_indices = np.random.choice(n_samples, size=n_samples, replace=True)bootstrap_X = X[bootstrap_indices]bootstrap_y = y[bootstrap_indices]tree = DecisionTreeRegressor(max_depth=self.max_depth,feature_numbers=self.max_features)tree.fit(bootstrap_X, bootstrap_y)self.trees.append(tree)# 获取特征重要性def feature_importances(self, X, y):n_features = X.shape[1]total_importances = np.zeros(n_features)# 计数,统计每一棵树中各特征值出现的频次,出现频次越多说明该特征越重要for one_tree in self.trees:importance = one_tree.calculate_importance()total_importances += importance# 计算n_estimators棵树中,各特征值的平均重要程度(还是通过出现频次表示)return total_importances / self.n_estimatorsdef load_data_primal():df = pd.read_excel("数据汇总3(数据完整)_决策树用.xlsx")data_temp  = df.iloc[:,3:-1]label_temp = df["综合评分"]data = []label = []for i in range(df.shape[0]):data.append(data_temp.iloc[i].to_list())temp = []temp.append(label_temp[i])label.append(temp)data = np.array(data)label = np.array(label)return data,labelif __name__ == '__main__':# 生成示例数据集X, y = load_data_primal()# print(X)# print(y)# 构建随机森林模型rf = RandomForestRegressor(n_estimators=100, max_depth=10, max_features=10)rf.fit(X, y)# for one_tree in rf.trees:#     one_tree.show(one_tree.bootnode)# 获取特征重要性importances = rf.feature_importances(X, y)# 先使用argsort进行降序排序,再进行反转indices = np.argsort(importances)[::-1]# 打印特征重要性print("Feature ranking:")for f in range(X.shape[1]):print("%d. feature %d (%f)" % (f + 1, indices[f], importances[indices[f]]))# 可视化特征重要性plt.figure()plt.title("Feature importances")plt.bar(range(X.shape[1]), importances[indices], color="r", align="center")plt.xticks(range(X.shape[1]), indices)plt.xlim([-1, X.shape[1]])plt.show()

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

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

相关文章

安装Fake UserAgent 库的方法最终解答!_Python库

安装Python库Fake UserAgent 我的环境&#xff1a;Window10&#xff0c;Python3.7&#xff0c;Anaconda3&#xff0c;Pycharm2023.1.3 Fake UserAgent Fake UserAgent 是一个Python库&#xff0c;用于生成随机或特定的用户代理&#xff08;UserAgent&#xff09;字符串。用户…

明日周刊-第7期

转眼间就又快到了五一假期&#xff0c;小长假有什么计划吗。封面配图是杭州高架上的月季花&#xff0c;非常好看。 文章目录 一周热点资源分享言论歌曲推荐 一周热点 鸿蒙系统持续扩大影响力&#xff1a;近期&#xff0c;华为官方宣布广东省已有超过600款应用加入鸿蒙系统&…

【自用】个人の画版规范

供电 总结起来就是&#xff1a;从正面看。从左到右的顺序是 VCC GND VEE&#xff0c;若是单电源则是VEE GND GND。 尽量用3p的。 XH2.54 接线端子

每天五分钟机器学习:神经网络模型参数的选择

本文重点 在深度学习和人工智能的浪潮中,神经网络作为其中的核心力量,发挥着举足轻重的作用。然而,神经网络的性能并非一蹴而就,而是需要经过精心的参数选择和调优。 神经网络由大量的神经元组成,每个神经元之间通过权重进行连接。这些权重,以及神经元的偏置、激活函数…

9.Eureka服务发现+Ribbon+RestTemplate服务调用

order-service服务通过服务名称来代替 ip:port的方式访问user-service服务的接口。 原来的请求代码&#xff1a; Service public class OrderServiceImpl implements OrderService {Autowiredprivate OrderMapper orderMapper;Autowiredprivate RestTemplate restTemplate;Ov…

PHP反序列化漏洞原理(附带pikachu靶场演示)

1.反序列化概念 序列化:是将变量转换为可保存或传输的字符串的过程;实现函数是serialize()反序列化:就是在适当的时候把这个字符串再转化成原来的变量使用&#xff0c;就是序列化的逆过程。实现函数是unserialize() 直白一点就是&#xff1a;序列化是把对象转换成字节流&#…

SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析

文章目录 系列文档索引六、EnableAspectJAutoProxy源码分析1、AnnotationAwareAspectJAutoProxyCreator源码&#xff08;1&#xff09;wrapIfNecessary方法&#xff08;2&#xff09;createProxy 2、getAdvicesAndAdvisorsForBean查找所有Advisor&#xff08;1&#xff09;find…

深入理解CAS机制-基础使用与三大问题

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1. 前言 2. 原子性问题 3. 乐观锁与悲观锁 4. CAS操作 5. CAS算法带来的三大…

Dynamic Wallpaper for Mac激活版:视频动态壁纸软件

Dynamic Wallpaper for Mac 是一款为Mac电脑量身打造的视频动态壁纸应用&#xff0c;为您的桌面带来无限生机和创意。这款应用提供了丰富多样的视频壁纸选择&#xff0c;涵盖了自然风景、抽象艺术、科幻奇观等多种主题&#xff0c;让您的桌面成为一幅活生生的艺术画作。 Dynami…

【教程】MySQL数据库学习笔记(五)——约束(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 第四章 《数据操…

Linux基本命令之正则表达式(转义字符)

一&#xff1a;查看二进制文件 strings 命令&#xff1a;strings 文件名 生成链接文件 ln 命令&#xff1a;ln 选项 源文件(f1) 链接文件&#xff08;f2&#xff09; 软连接&#xff1a;eg:ln -s f1 f2 软链接不能跨分区链接&#xff0c;但可以在同一分区的不同目录下链接…

go+react实现远程vCenter虚拟机管理终端

文章目录 React-VcenterDemoQuick Start React-Vcenter 基于go & react实现远程vSphere vcenter虚拟机终端console页面&#xff0c;提供与vcenter管理中的Launch Web Console相同的功能。 项目地址&#xff1a;react-vcenter Demo URL: http://localhost:3000 Quick St…

3-氨基苯硼酸接枝的透明质酸(HA-PBA)和聚乙烯醇(PVA )水凝胶负载胶束和药物

3-氨基苯硼酸接枝的透明质酸&#xff08;HA-PBA&#xff09;和聚乙烯醇&#xff08;PVA &#xff09;水凝胶负载胶束和药物 苯硼酸酯交联形成水凝胶的步骤&#xff1a; HA-PBA的制备&#xff1a;首先&#xff0c;3-氨基苯硼酸通过与透明质酸&#xff08;HA&#xff09;中的羧基…

Selenium web自动化测试环境搭建

Selenium web自动化环境搭建主要要经历以下几个步骤&#xff1a; 1、安装python 在python官网&#xff1a;Welcome to Python.org&#xff0c;根据各自对应平台如&#xff1a;windows&#xff0c;下载相应的python版本。 ​ 下载成功后&#xff0c;点击安装包&#xff0c;一直…

数据结构10:堆和堆排序

文章目录 树的概念及结构树的概念树的相关概念树的表示树在实际中的应用表示文件系统的目录树结构 二叉树概念及结构概念特殊的二叉树二叉树的性质二叉树的存储结构顺序存储链式存储 二叉树的顺序结构及实现二叉树的顺序结构堆的概念及结构 堆的实现堆的插入堆的删除堆的创建向…

【数据结构】08排序

08 排序 1. 冒泡排序&#xff08;BubbleSort&#xff09;1.1 循环嵌套实现1.2 递归实现 2. 选择排序2.1 嵌套循环实现2.2 递归实现 3. 插入排序4. 希尔排序4.1 代码实现 5. 快速排序5.1 代码实现6. 归并排序6.1 递归实现6.2 循环实现 7. 堆排序7.1 构建大顶堆7.2 堆排序7.3 代码…

春秋云镜 CVE-2023-51048

靶标介绍&#xff1a; S-CMS v5.0 被发现存在SQLI。 开启靶场 根据题目查找S-CMS v5.0漏洞&#xff0c;百度没有查询到&#xff0c;使用必应搜索S-CMS v5.0 查找到githubCVE-2023-51052的描述 S-CMS v5.0 was discovered to contain a SQL injection... CVE-2023-51052 Git…

达梦数据库的AWR报告

达梦数据库的AWR报告 数据库快照是一个只读的静态的数据库。 DM 快照功能是基于数据库实现的&#xff0c;每个快照是基于数据库的只读镜像。通过检索快照&#xff0c;可以获取源数据库在快照创建时间点的相关数据信息。 为了方便管理自动工作集负载信息库 AWR&#xff08;Auto…

C++修炼之路之多态---多态的原理(虚函数表)

目录 一&#xff1a;多态的原理 1.虚函数表 2.原理分析 3.对于虚表存在哪里的探讨 4.对于是不是所有的虚函数都要存进虚函数表的探讨 二&#xff1a;多继承中的虚函数表 三&#xff1a;常见的问答题 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗--…

Vue3+TS版本Uniapp:封装uni.request请求配置

作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者✍/CSDN百万访问博主/B站千粉前端up主 封装请求配置项 封装拦截器封装uni.request 封装拦截器 uniapp的封装逻辑不同于Vue3项目中直接使用axios.create()方法创建实例&#xff08;在create方法中写入请求…