决策树DT:ID3、C4.5原理及python实现

2023-12-25 05:18

本文主要是介绍决策树DT:ID3、C4.5原理及python实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 决策树模型与学习
  • 特征选择
    • 信息增益
    • 信息增益比
  • ID3算法
    • 决策树生成
    • ID3算法的不足
  • C4.5算法
    • 连续值处理
    • 缺失值处理
    • C4.5算法的不足
  • 决策树剪枝
  • 程序实现ID3


决策树模型与学习

决策树分类: 从根节点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到对应子节点;若子节点为特征的一个取值,则递归的对实例进行测试并分配,直到到达叶节点(类别)。

决策树与条件概率分布(判别式模型) 特征空间被划分为互不相交的区域,每个区域定义一个类的概率分布,从而构成了一个条件概率分布。
各区域(叶节点)上的条件概率偏向于一个类,决策树分类时,强行将节点的实例划分为条件概率较大的一类。

特征选择

特征选择在于选取具有分类能力的特征,使得每次分割之后,各分支节点所含样本尽可能属于同一类别。这样可加快决策树的生成。

信息增益

信息熵(Information Entropy)是表示随机变量纯度/不确定性的指标。设 X X X为有限取值的随机变量(类别),其概率分布(类别比例)
P ( X = x i ) = p i , ( i = 1 , 2 , ⋯   , ∣ Y ∣ ) P(X=x_i)=p_i, \quad (i = 1, 2, \cdots, \mathcal{|Y|}) P(X=xi)=pi,(i=1,2,,Y)

则随机变量 X X X的信息熵记作 H ( X ) H(X) H(X),即
H ( X ) = − ∑ i = 1 ∣ Y ∣ p i log ⁡ 2 p i H(X)=-\sum_{i=1}^{\mathcal{|Y|}}p_i\log_2p_i H(X)=i=1Ypilog2pi

熵的取值与随机变量取值无关,仅与其概率分布有关。熵值越小,不确定性越低、数据集纯度越高。 0 ≤ H ( p ) ≤ log ⁡ ∣ Y ∣ 0 \leq H(p) \leq \log \mathcal{|Y|} 0H(p)logY

设有随机变量 ( X , Y ) (X, Y) (X,Y),其联合概率分布
P ( X = x i , Y = y i ) = p i j P(X = x_i, Y = y_i)=p_{ij} P(X=xi,Y=yi)=pij

随机变量X和Y的条件熵
H ( Y ∣ X ) = − ∑ i = 1 n ∑ j = 1 m p ( x i , y i ) log ⁡ 2 p ( y i ∣ x i ) = − ∑ i = 1 n ∑ j = 1 m p ( x i ) p ( y i ∣ x i ) log ⁡ 2 p ( y i ∣ x i ) = ∑ i = 1 n p ( x i ) H ( Y ∣ X = x i ) \begin{aligned} H(Y|X) &= - \sum_{i=1}^n \sum_{j=1}^m p(x_i, y_i) \log_2 p(y_i | x_i) \\ & = - \sum_{i=1}^n \sum_{j=1}^m p(x_i)p(y_i|x_i) \log_2 p(y_i | x_i) \\ & = \sum_{i=1}^n p(x_i) H(Y|X=x_i) \end{aligned} H(YX)=i=1nj=1mp(xi,yi)log2p(yixi)=i=1nj=1mp(xi)p(yixi)log2p(yixi)=i=1np(xi)H(YX=xi)

条件熵 H ( Y ∣ X ) H(Y|X) H(YX)表示已知 X X X的条件下 Y Y Y的不确定性,上式为已知 X X X的条件下 Y Y Y的条件概率分布的熵对 X X X的数学期望。当熵和条件熵由数据估计得到时,熵和条件熵分别称为经验熵经验条件熵

信息增益度量得知特征 X X X而使得类 Y Y Y不确定性减少的程度,定义为样本集 D D D的经验熵与已知特征 a a a条件下 D D D的经验条件熵之差,即
g ( D , a ) = H ( D ) − H ( D ∣ a ) g(D,a)=H(D)-H(D|a) g(D,a)=H(D)H(Da)

注:信息增益亦称为类与特征的互信息

图1 联合熵、条件熵与互信息(信息增益)间的关系

最优划分属性应使划分后的样本信息增益/纯度最大(不确定性降低),即条件熵取最小
a o p t = arg ⁡ min ⁡ A ∑ v = 1 V p v H ( Y ∣ X = x v ) a_{opt} = \arg \min_A \sum_{v=1}^Vp_vH(Y|X=x_v) aopt=argAminv=1VpvH(YX=xv)

可见,信息增益准则偏好于取值较多的属性(V较大)。

表1 西瓜数据集2.0
编号色泽根蒂敲声纹理脐部触感好瓜
1青绿蜷缩浊响清晰凹陷硬滑
2乌黑蜷缩沉闷清晰凹陷硬滑
3乌黑蜷缩浊响清晰凹陷硬滑
4青绿蜷缩沉闷清晰凹陷硬滑
5浅白蜷缩浊响清晰凹陷硬滑
6青绿稍蜷浊响清晰稍凹软粘
7乌黑稍蜷浊响稍糊稍凹软粘
8乌黑稍蜷浊响清晰稍凹硬滑
9乌黑稍蜷沉闷稍糊稍凹硬滑
10青绿硬挺清脆清晰平坦软粘
11浅白硬挺清脆模糊平坦硬滑
12浅白蜷缩浊响模糊平坦软粘
13青绿稍蜷浊响稍糊凹陷硬滑
14浅白稍蜷沉闷稍糊凹陷硬滑
15乌黑稍蜷浊响清晰稍凹软粘
16浅白蜷缩浊响模糊平坦硬滑
17青绿蜷缩沉闷稍糊稍凹硬滑

由上表可知,类别 ∣ Y ∣ = 2 \mathcal{|Y|}=2 Y=2,信息熵
H ( D ) = − 8 17 log ⁡ 2 8 17 − 9 17 log ⁡ 2 9 17 = 0.998 H(D)=-\frac{8}{17} \log_2\frac{8}{17} -\frac{9}{17} \log_2\frac{9}{17} = 0.998 H(D)=178log2178179log2179=0.998

若选择色泽作为划分属性,色泽包含的属性值有{青绿,乌黑,浅白},分别标记位 D 1 D_1 D1 D 2 D_2 D2 D 3 D_3 D3,则
g ( D , 色 泽 ) = H ( D ) − ( 6 17 H ( D 1 ) + 6 17 H ( D 2 ) + 5 17 H ( D 3 ) ) = 0.998 − 1 17 [ 6 ( − 3 6 log ⁡ 2 3 6 − 3 6 log ⁡ 2 3 6 ) + ( − 4 6 log ⁡ 2 4 6 − 2 6 log ⁡ 2 2 6 ) + ( − 4 5 log ⁡ 2 4 5 − 1 5 log ⁡ 2 1 5 ) ] = 0.109 \begin{aligned} g(D, 色泽) &= H(D) - \left(\frac{6}{17}H(D_1)+ \frac{6}{17}H(D_2) + \frac{5}{17}H(D_3)\right) \\ & = 0.998 - \frac{1}{17} \left[ 6\left( -\frac{3}{6} \log_2 \frac{3}{6} -\frac{3}{6} \log_2 \frac{3}{6} \right) + \left( -\frac{4}{6} \log_2 \frac{4}{6} -\frac{2}{6} \log_2 \frac{2}{6} \right) + \left( -\frac{4}{5} \log_2 \frac{4}{5} -\frac{1}{5} \log_2 \frac{1}{5} \right) \right] \\ & = 0.109 \end{aligned} g(D,)=H(D)(176H(D1)+176H(D2)+175H(D3))=0.998171[6(63log26363log263)+(64log26462log262)+(54log25451log251)]=0.109

同理,可计算出其他特征的信息增益,其中具有最大信息增益的属性为 g ( D , 纹 理 ) = 0.381 g(D, 纹理)=0.381 g(D,)=0.381。因此,使用纹理特征对样本集进行划分,所得样本的不确定性最小。

信息增益比

极端情况下,若样本集含n个样本,离散属性a含n个属性。若使用属性a分割样本集,则所得各分支节点的信息熵均为0,此时划分后的样本集纯度最大。但每个分支节点仅含1个样本,所得决策树无泛化能力。

定义增益率为特征 a a a的信息增益 g ( D , a ) g(D, a) g(D,a)与训练集 D D D关于特征 a a a的值的熵 H a ( D ) H_a(D) Ha(D)之比,即
g R ( D , a ) = g ( D , a ) H a ( D ) g_R(D, a) = \frac{g(D, a)}{H_a(D)} gR(D,a)=Ha(D)g(D,a)

其中分母项为特征a的信息熵 H a ( D ) = ∑ i = v V ∣ D v ∣ D ∣ log ⁡ 2 D v D H_a(D) = \sum_{i=v}^V\dfrac{|D_v}{|D|} \log_2\dfrac{D_v}{D} Ha(D)=i=vVDDvlog2DDv

属性a的取值越多,分母可能越大,增益率准则偏好于较少取值多的属性。因此,最优分割属性应同时具有较高信息增益和增益比,如C.5算法先选择信息增益高于平均值的属性,再从中选择增益率高的属性。

ID3算法

决策树生成

输入:训练集 D D D,特征集 A A A,阈值 ε \varepsilon ε
输出:决策树 T T T

递归生成决策树算法,如下:

  1. 若数据集 D D D中所有实例均属于同一类 C k C_k Ck,则 T T T为单节点树(叶节点),将类别 C k C_k Ck作为节点类标记,返回 T T T
  2. 若特征集 A A A为空,则 T T T为单节点树,将 D D D中含样本最多的类别 C k C_k Ck作为其类标记,返回 T T T
  3. 计算 A A A中各特征的信息增益,选择信息增益最大的特征 a o p t a_{opt} aopt对样本集 D D D进行划分;
  4. a o p t a_{opt} aopt的信息增益小于阈值 ε \varepsilon ε,则置 T T T为单节点树,将 D D D中含样本最多的类别 C k C_k Ck作为其类标记,返回 T T T
  5. 否则,使用 a o p t a_{opt} aopt V V V个不同属性值将 D D D划分为 V V V个不同的子集 D v D_v Dv,每个子集均为节点的一个分支;
  6. 对所有分支节点,令 D = D v D=D_v D=Dv A = A − a o p t A=A-a_{opt} A=Aaopt,递归调用上述步骤,得到分支树并返回;

ID3算法的不足

  1. 未考虑具有连续值的属性;
  2. 极端情况下选择信息增益最大的属性(完全随机性变量)会使模型失去泛化能力;
  3. 未考虑缺失值处理与过拟合问题;

C4.5算法

C4.5对ID3算法进行了改进,使用信息增益比选择每次划分数据集的最优特征,并对缺失值和过拟合问题进行了处理。

连续值处理

  1. 将连续值离散化,如m个样本的特征 a a a m m m个不同的属性值,将属性值升序排列为 a 1 , ⋯   , a m a_1,\cdots,a_m a1,,am
  2. 取相邻属性值的均值作为划分点,共计 m − 1 m-1 m1个,每个划分点 t t t可将 D D D分为子集 D t − D_t^- Dt D t + D_t^+ Dt+
  3. 分别计算 m − 1 m-1 m1个划分点作为二元分类的信息增益,取信息增益最大的点作为分类点;
    g R ( D , a ) = max ⁡ t ∈ T a g R ( D , a , t ) = max ⁡ t ∈ T a ( H ( D ) − ∑ λ ∈ { − , + } ∣ D t λ ∣ ∣ D ∣ H ( D t λ ) ) g_R(D, a) = \max_{t \in T_a} g_R(D, a, t) = \max_{t \in T_a} (H(D)- \sum_{\lambda \in \{-, +\}} \frac{|D_t^\lambda|}{|D|}H(D_t^\lambda)) gR(D,a)=tTamaxgR(D,a,t)=tTamax(H(D)λ{,+}DDtλH(Dtλ))
  4. 以连续属性划分的节点,连续属性还可作为其后代节点的划分属性;

缺失值处理

如何在属性值缺失的情况下选择最优划分属性?
给定训练集 D D D和属性 a a a,令 D ~ \tilde D D~表示 D D D在属性 a a a上没有缺失值的样本子集,每个样本 x x x的权重为 w x w_x wx(初始为1),则
ρ = ∑ x ∈ D ~ w x ∑ x ∈ D w x   p ~ k = ∑ x ∈ D ~ k w x ∑ x ∈ D ~ w x ( 1 ≤ k ≤ ∣ Y ∣ )   r ~ v = ∑ x ∈ D ~ v w x ∑ x ∈ D ~ w x ( 1 ≤ v ≤ V ) \begin{aligned} \rho &= \frac{\sum_{x \in \tilde D} w_x}{\sum_{x \in D} w_x} \\ \,\\ \tilde p_k &= \frac{\sum_{x \in \tilde D_k} w_x}{\sum_{x \in \tilde D} w_x} \quad(1 \leq k \leq |\mathcal{Y}|) \\ \,\\ \tilde r_v &= \frac{\sum_{x \in \tilde D^v} w_x}{\sum_{x \in \tilde D} w_x} \quad (1 \leq v \leq V) \end{aligned} ρp~kr~v=xDwxxD~wx=xD~wxxD~kwx(1kY)=xD~wxxD~vwx(1vV)

式中, ρ \rho ρ表示未缺失值比例、 p ~ k \tilde p_k p~k表示 D ~ \tilde D D~中类别为 k k k的样本比例、 r ~ v \tilde r_v r~v表示 D ~ \tilde D D~中属性 a a a取值为 a v a_v av的样本比例。

因此缺失值属性a的信息增益推广为
g ( D , a ) = ρ × g ( D ~ , a ) = ρ × ( H ( D ~ ) − ∑ v = 1 V r ~ v H ( D ~ v ) ) , H ( D ~ v ) = − ∑ k = 1 ∣ Y ∣ p ~ k log ⁡ 2 p k g(D, a) = \rho \times g(\tilde D, a) = \rho \times \left(H(\tilde D) - \sum_{v=1}^V \tilde r_v H(\tilde D^v) \right), \quad H(\tilde D^v) =-\sum_{k=1}^{|\mathcal{Y}|} \tilde p_k \log_2 p_k g(D,a)=ρ×g(D~,a)=ρ×(H(D~)v=1Vr~vH(D~v)),H(D~v)=k=1Yp~klog2pk

给定划分属性,若样本在该属性上值缺失,如何对样本进行分配?

若样本 x x x在划分属性 a a a上取值已知,则将 x x x划入其取值对应的子节点,样本权值保持不变;若取值未知则将样本 x x x划分到所有分支节点,样本权值在 a v a^v av的分支节点中调整为 r ~ v ⋅ w x \tilde r_v \cdot w_x r~vwx

直观上,同一样本以不同概率分配到不同的分支节点。

C4.5算法的不足

  1. 生成的决策树为多叉树(一个父节点含多个子节点),没有二叉树模型效率高;
  2. 只能用于分类,不能用于回归;
  3. 使用熵模型选取最优划分属性,计算复杂,尤其是处理连续值属性;

决策树剪枝

一般情况下递归产生的决策树对训练数据的分类很准确,但有可能对未知数据的分类表现很差。上述现象称为过拟合,一般通过简化决策树复杂度(剪枝)解决。

预剪枝
在划分之前,评估单节点树以及节点按属性值展开后的预测精度,若单节点树的预测精度不低于展开后树的预测精度,则将该节点作为叶节点。

后剪枝
定义决策树的损失函数如下:
C α ( T ) = ∑ t = 1 ∣ T ∣ N t H t ( T ) + α ∣ T ∣ = C ( T ) + α ∣ T ∣ , H t ( T ) = − ∑ k N t k N t log ⁡ N t k N t C_\alpha(T) = \sum_{t=1}^{|T|}N_tH_t(T)+\alpha |T| = C(T) + \alpha |T|, \quad H_t(T)=-\sum_k \frac{N_{tk}}{N_t} \log \frac{N_{tk}}{N_t} Cα(T)=t=1TNtHt(T)+αT=C(T)+αT,Ht(T)=kNtNtklogNtNtk

式中, ∣ T ∣ |T| T为叶节点数目(模型的复杂度), t t t是树 T T T的叶节点, N t N_t Nt为节点 t t t所含样本数, N t k N_{tk} Ntk t t t节点中类别为 k k k的样本数, k = 1 , 2 , ⋯   , K k=1,2,\cdots,K k=1,2,,K H t ( T ) H_t(T) Ht(T) t t t节点的经验熵,可变参数 a ≥ 0 a \geq 0 a0 C ( T ) C(T) C(T)为模型对训练数据的预测误差。

参数 α \alpha α的值可平衡模型复杂度和训练误差。 α = 0 \alpha=0 α=0时,表示不考虑模型复杂程度,只考虑训练误差。较大的 α \alpha α偏向于较简单的模型( T T T小,训练误差大),较小的 α \alpha α偏向于较复杂的模型( T T T大,训练误差小)。

决策树的生成只考虑拟合效果(局部模型),而决策树剪枝是通过优化损失函数。


程序实现ID3

from collections import Counter
from itertools import chain
from math import log2import numpy as npfrom_iterable = chain.from_iterabledef cal_entropy(array):"""计算信息熵"""total = 1. * len(array)ent = 0.0for value in Counter(array).values():prob = value / totalent -= prob * log2(prob)return entdef cal_gain(feat_values, categories):"""计算某特征的信息增益"""uniques = set(feat_values)nums = len(uniques)feat_dict = dict(zip(uniques, range(nums)))# 提取各特征值的子集sub_labels = [[] for _ in range(nums)]for value, category in zip(feat_values, categories):sub_labels[feat_dict[value]].append(category)# 计算条件熵cond_ent = 0.0total = len(categories)for array in sub_labels:cond_ent += cal_entropy(array) * len(array) / total# 返回信息增益return cal_entropy(categories) - cond_entdef tree_depth(tree):"""计算决策树深度,字典形式存储"""if isinstance(tree, dict):branches = [value for value in tree.values()][0]return max(tree_depth(node) for node in branches.values()) + 1else:return 1class DecisionTree_ID3:def __int__(self):self.tree = Nonepassdef train(self, X, y, names=None):self._feat_names = ['FEAT_{}'.format(i) for i inrange(len(X[0]))] if names is None else namesunique = list(set(y))category2num = dict((category, num) for category, num inzip(unique, range(len(unique))))self._names = uniquecategories = [category2num[i] for i in y]data_set = np.hstack((X, np.array([categories]).T))# 生成决策树self.tree = self._make_tree(data_set, self._feat_names)def _make_tree(self, data_set, feat_names):"""生成决策树"""categories = data_set[:, -1]# 当前节点包含的样本为同一类别category = categories[0]if np.all(categories == category):return self._names[int(category)]# 当前属性集为空,返回样本中频数最大的类别if len(data_set[0]) == 1:return Counter(categories).most_common(1)[0][0]best_num = self.best_feat(data_set)best_name = feat_names[best_num]# 以当前节点为根的树my_tree = {best_name: {}}node = my_tree[best_name]# 最优特征values = data_set[:, best_num]# 遍历各属性值data_set = np.delete(data_set, best_num, axis=1)feat_names = np.delete(feat_names, best_num)for value in set(values):sub_data_set = data_set[values == value]node[value] = self._make_tree(sub_data_set, feat_names)return my_treedef best_feat(self, data_set):"""计算最优特征,ID3算法每次选取信息增益最大的特征"""categories = data_set[:, -1]nums = len(data_set[0]) - 1gains = [cal_gain(data_set[:, i], categories) for i in range(nums)]# 找到最大信息增益特征的所在列位置num = 0max_gain = gains[0]for i, gain in enumerate(gains[1:]):if max_gain < gain:num = i + 1max_gain = gainreturn numif __name__ == '__main__':X = [['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'],['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑'],['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'],['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑'],['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑'],['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘'],['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘'],['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑'],['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑'],['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘'],['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑'],['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘'],['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑'],['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑'],['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘'],['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑'],['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑']]y = ['好瓜', '好瓜', '好瓜', '好瓜', '好瓜', '好瓜', '好瓜', '好瓜', '坏瓜', '坏瓜', '坏瓜', '坏瓜','坏瓜', '坏瓜', '坏瓜', '坏瓜', '坏瓜']names = ['色泽', '根蒂', '敲击', '纹理', '脐部', '触感']tree = DecisionTree_ID3()tree.train(X, y, names)print(tree.tree)    # print(tree_depth(tree.tree))

这篇关于决策树DT:ID3、C4.5原理及python实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/534362

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形