决策树

说明:这篇博客是看李航老师的《统计学习方法》做的笔记总结,博客中有很多内容是摘选自李航老师的《统计学习方法》一书,仅供学习交流使用。

决策树(decision tree)是一种基本的分类与回归方法。主要讨论用于分类的决策树。

决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是if-then规则集合,也可以认为是定义在特征空间与类空间上的条件概率分布。其主要优点是模型具有可读性,分类速度快。

简单来说,决策树就是一棵树,一颗决策树包含一个根节点、若干个内部结点和若干个叶结点;叶结点对应于决策结果,其他每个结点则对应于一个特征测试;分类的具体操作是从根节点开始,对实例的每一特征进行测试,根据测试结果,将实例分配到其子节点;这时,每一个子节点对应着给特征的一个取值。如此递归地对实例进行测试并分配,直至达到叶节点。最后将实例分到叶节点的类中。下面直接上个图,帮助大家理解一下:

名字 体温 胎生 类别
小狗狗 恒温 哺乳动物

注:圆框代表内部节点,方框代表叶节点。

决策树通常包括三个步骤:特征选择决策树的生成决策树的修剪

决策树学习的目标:根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。

决策树学习的本质:从训练数据集中归纳出一组分类规则。

决策树学习的策略:以损失函数为目标函数的最小化。

特征选择

特征选择在于选取对训练数据具有分类能力的特征。这样可以提高决策树学习的效率,如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的。经验上扔掉这样的特征对决策树学习的精度影响不大。通常特征选择的准则是信息增益信息增益比

简单来说,就是找出比较好的特征来划分特征空间。比如判断是否为哺乳动物这个例子,其中有体温和胎生两个特征,那么选哪一个作为根节点呢?而特征选择就是用来解决这个问题的方法。

经验熵、经验条件熵

为了便于说明,这里先给出熵和条件熵的定义。

在信息论与概率统计中,熵(entropy)是表示随机变量不确定性的度量。设X是一个取有限个值的离散随机变量,其概率分布为
P ( X = x i ) = p i , i = 1 , 2 , … , n P(X=x_i)=p_i,i=1,2,\dots,n P(X=xi​)=pi​,i=1,2,…,n
则随机变量X的熵定义为
H ( X ) = − ∑ i = 1 n p i l o g 2 p i H(X)=-\sum_{i=1}^np_ilog_2p_i H(X)=−i=1∑n​pi​log2​pi​
熵越大,随机变量的不确定性就越大。

为了更好的理解熵与不确定性的关系,我们可以举一个例子

如一个普通的骰子A,扔出1-6的概率均为1/6

假设一个骰子B,扔出6的概率为50%,扔出1-5的概率为10%

则骰子A的熵为 − ( 1 6 l o g 2 1 6 ) ∗ 6 ≈ 2.585 -(\frac{1}{6}log_2\frac{1}{6})*6≈2.585 −(61​log2​61​)∗6≈2.585

骰子B的熵为 − 1 2 l o g 2 1 2 − 1 10 l o g 2 1 10 ∗ 5 ≈ 2.161 -\frac{1}{2}log_2\frac{1}{2}-\frac{1}{10}log_2\frac{1}{10}*5≈2.161 −21​log2​21​−101​log2​101​∗5≈2.161

条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性。随机变量X给定条件下随机变量Y的条件熵(conditional entropy)H(Y|X),定义为X给定条件下Y的条件概率分布的熵对X的数学期望
H ( Y ∣ X ) = ∑ i = 1 n p i H ( Y ∣ X = x i ) H(Y|X)=\sum_{i=1}^np_iH(Y|X=x_i) H(Y∣X)=i=1∑n​pi​H(Y∣X=xi​)
这里, p i = P ( x = x i ) , i = 1 , 2 , … , n p_i=P(x=x_i),i=1,2,\dots,n pi​=P(x=xi​),i=1,2,…,n。

当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的熵和条件熵分别成为经验熵经验条件熵。

假设现在有一个数据集D,|D|表示数据集D的样本容量,即样本个数。而样本中有K个类( k = 1 , 2 , … , K k=1,2,\dots,K k=1,2,…,K), ∣ C k ∣ |C_k| ∣Ck​∣为属于类 C k C_k Ck​的样本数。

此时在数据集D上,经验熵的公式为
H ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ l o g 2 ∣ C k ∣ ∣ D ∣ H(D)=-\sum_{k=1}^K\frac{|C_k|}{|D|}log_2\frac{|C_k|}{|D|} H(D)=−k=1∑K​∣D∣∣Ck​∣​log2​∣D∣∣Ck​∣​
同样在上述的数据集中,特征A的取值有n个(数据集中有n个特征),其取值将数据集D划分为了n个小的子集 D i D_i Di​,而子集 D i D_i Di​属于类 C k C_k Ck​的样本集合记为 D i k D_{ik} Dik​,即 D i k = D i ∩ C k D_{ik}=D_i∩C_k Dik​=Di​∩Ck​。

那么特征A对数据集D的经验条件熵H(D|A)
H ( D ∣ A ) = ∑ i = 1 n ∣ D i ∣ ∣ D ∣ H ( D i ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ l o g 2 ∣ D i k ∣ ∣ D i ∣ H(D|A)=\sum_{i=1}^n\frac{|D_i|}{|D|}H(D_i)=-\sum_{i=1}^n\frac{|D_i|}{|D|}\sum_{k=1}^K\frac{|D_{ik}|}{|D_i|}log_2\frac{|D_{ik}|}{|D_i|} H(D∣A)=i=1∑n​∣D∣∣Di​∣​H(Di​)=−i=1∑n​∣D∣∣Di​∣​k=1∑K​∣Di​∣∣Dik​∣​log2​∣Di​∣∣Dik​∣​
为了更好的理解公式,这里引入《统计学习方法》书中的例子

ID 年龄 有工作 有自己的房子 信贷情况 类别
1 青年 一般
2 青年
3 青年
4 青年 一般
5 青年 一般
6 中年 一般
7 中年
8 中年
9 中年 非常好
10 中年 非常好
11 老年 非常好
12 老年
13 老年
14 老年 非常好
15 老年 一般

该例中类别 C k C_k Ck​的取值有两个否和是, C 否 = 6 , C 是 = 9 C_否=6,C_是=9 C否​=6,C是​=9,则经验熵为
H ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ l o g 2 ∣ C k ∣ ∣ D ∣ = − ∣ C 否 ∣ ∣ D ∣ l o g 2 ∣ C 否 ∣ ∣ D ∣ − ∣ C 是 ∣ ∣ D ∣ l o g 2 ∣ C 是 ∣ ∣ D ∣ = − 6 15 l o g 2 6 15 − 9 15 l o g 2 9 15 = 0.971 \begin{aligned} H(D)&=-\sum_{k=1}^K\frac{|C_k|}{|D|}log_2\frac{|C_k|}{|D|} \\ &=-\frac{|C_否|}{|D|}log_2\frac{|C_否|}{|D|}-\frac{|C_是|}{|D|}log_2\frac{|C_是|}{|D|} \\ &=-\frac{6}{15}log_2\frac{6}{15}-\frac{9}{15}log_2\frac{9}{15} =0.971 \end{aligned} H(D)​=−k=1∑K​∣D∣∣Ck​∣​log2​∣D∣∣Ck​∣​=−∣D∣∣C否​∣​log2​∣D∣∣C否​∣​−∣D∣∣C是​∣​log2​∣D∣∣C是​∣​=−156​log2​156​−159​log2​159​=0.971​
该例中第一个特征的取值有3个,其中 D 1 = D 2 = D 3 = 5 D_1=D_2=D_3=5 D1​=D2​=D3​=5, D 1 否 = 3 , D 1 是 = 2 D_{1否}=3,D_{1是}=2 D1否​=3,D1是​=2, D 2 否 = 2 , D 2 是 = 3 D_{2否}=2,D_{2是}=3 D2否​=2,D2是​=3, D 3 否 = 1 , D 3 是 = 4 D_{3否}=1,D_{3是}=4 D3否​=1,D3是​=4,则经验条件熵为
H ( D ∣ A 1 ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ l o g 2 ∣ D i k ∣ ∣ D i ∣ = − ∣ D 1 ∣ ∣ D ∣ ∑ k = 1 K ∣ D 1 k ∣ ∣ D 1 ∣ l o g 2 ∣ D 1 k ∣ ∣ D 1 ∣ − ∣ D 2 ∣ ∣ D ∣ ∑ k = 1 K ∣ D 2 k ∣ ∣ D 2 ∣ l o g 2 ∣ D 2 k ∣ ∣ D 2 ∣ − ∣ D 3 ∣ ∣ D ∣ ∑ k = 1 K ∣ D 3 k ∣ ∣ D 3 ∣ l o g 2 ∣ D 3 k ∣ ∣ D 3 ∣ = − 5 15 ( 3 5 l o g 2 3 5 + 2 5 l o g 2 2 5 ) − 5 15 ( 2 5 l o g 2 2 5 + 3 5 l o g 2 3 5 ) − 5 15 ( 1 5 l o g 2 1 5 + 4 5 l o g 2 4 5 ) = 0.8879432 ≈ 0.888 \begin{aligned} H(D|A_1)&=-\sum_{i=1}^n\frac{|D_i|}{|D|}\sum_{k=1}^K\frac{|D_{ik}|}{|D_i|}log_2\frac{|D_{ik}|}{|D_i|} \\ &=-\frac{|D_1|}{|D|}\sum_{k=1}^K\frac{|D_{1k}|}{|D_1|}log_2\frac{|D_{1k}|}{|D_1|}-\frac{|D_2|}{|D|}\sum_{k=1}^K\frac{|D_{2k}|}{|D_2|}log_2\frac{|D_{2k}|}{|D_2|}-\frac{|D_3|}{|D|}\sum_{k=1}^K\frac{|D_{3k}|}{|D_3|}log_2\frac{|D_{3k}|}{|D_3|} \\ &=-\frac{5}{15}(\frac{3}{5}log_2\frac{3}{5}+\frac{2}{5}log_2\frac{2}{5})-\frac{5}{15}(\frac{2}{5}log_2\frac{2}{5}+\frac{3}{5}log_2\frac{3}{5})-\frac{5}{15}(\frac{1}{5}log_2\frac{1}{5}+\frac{4}{5}log_2\frac{4}{5}) \\ &=0.8879432≈0.888 \end{aligned} H(D∣A1​)​=−i=1∑n​∣D∣∣Di​∣​k=1∑K​∣Di​∣∣Dik​∣​log2​∣Di​∣∣Dik​∣​=−∣D∣∣D1​∣​k=1∑K​∣D1​∣∣D1k​∣​log2​∣D1​∣∣D1k​∣​−∣D∣∣D2​∣​k=1∑K​∣D2​∣∣D2k​∣​log2​∣D2​∣∣D2k​∣​−∣D∣∣D3​∣​k=1∑K​∣D3​∣∣D3k​∣​log2​∣D3​∣∣D3k​∣​=−155​(53​log2​53​+52​log2​52​)−155​(52​log2​52​+53​log2​53​)−155​(51​log2​51​+54​log2​54​)=0.8879432≈0.888​

第二个特征(有工作)的取值有2两个,其中 D 1 = 10 ( 没 有 工 作 ) , D 2 = 5 ( 有 工 作 ) D_1=10(没有工作),D_2=5(有工作) D1​=10(没有工作),D2​=5(有工作), D 1 否 = 6 , D 1 是 = 4 D_{1否}=6,D_{1是}=4 D1否​=6,D1是​=4, D 2 是 = 5 D_{2是}=5 D2是​=5,则经验条件熵为
H ( D ∣ A 1 ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ ∑ k = 1 K ∣ D i k ∣ ∣ D i ∣ l o g 2 ∣ D i k ∣ ∣ D i ∣ = − 10 15 H ( D 1 ) − 5 15 H ( D 2 ) = − 10 15 ( 4 10 l o g 2 4 10 + 6 10 l o g 2 6 10 ) − 5 15 ∗ 0 ≈ 0.324 \begin{aligned} H(D|A_1)&=-\sum_{i=1}^n\frac{|D_i|}{|D|}\sum_{k=1}^K\frac{|D_{ik}|}{|D_i|}log_2\frac{|D_{ik}|}{|D_i|} \\ &=-\frac{10}{15}H(D_1)-\frac{5}{15}H(D_2) \\ &=-\frac{10}{15}(\frac{4}{10}log_2\frac{4}{10}+\frac{6}{10}log_2\frac{6}{10})-\frac{5}{15}*0 \\ &≈0.324 \end{aligned} H(D∣A1​)​=−i=1∑n​∣D∣∣Di​∣​k=1∑K​∣Di​∣∣Dik​∣​log2​∣Di​∣∣Dik​∣​=−1510​H(D1​)−155​H(D2​)=−1510​(104​log2​104​+106​log2​106​)−155​∗0≈0.324​
其他特征同理。

代码实现经验熵、经验条件熵

代码实现经验熵计算

from math import log
# 数据集
dataSet=[[0, 0, 0, 0, 'no'],[0, 0, 0, 1, 'no'],[0, 1, 0, 1, 'yes'],[0, 1, 1, 0, 'yes'],[0, 0, 0, 0, 'no'],[1, 0, 0, 0, 'no'],[1, 0, 0, 1, 'no'],[1, 1, 1, 1, 'yes'],[1, 0, 1, 2, 'yes'],[1, 0, 1, 2, 'yes'],[2, 0, 1, 2, 'yes'],[2, 0, 1, 1, 'yes'],[2, 1, 0, 1, 'yes'],[2, 1, 0, 2, 'yes'],[2, 0, 0, 0, 'no']]
#数据集D的样本个数
num_D=len(dataSet)
#记录类别的字典
labelCounts={}
#记录数据集中的类别,并统计其个数
for featVec in dataSet:currentLabel=featVec[-1]                     #读取类别信息if currentLabel not in labelCounts.keys():   #如果读取的类别没有放入统计次数的字典,添加进去labelCounts[currentLabel]=0              #默认值为0labelCounts[currentLabel]+=1                 #计数entropy=0.0                                   #经验熵
#计算经验熵
for key in labelCounts:prob=float(labelCounts[key])/num_Dentropy-=prob*log(prob,2)                 #利用公式计算
print("数据集D的经验熵H(D):",format(entropy,'.3f'))
数据集D的经验熵H(D): 0.971

代码实现经验条件熵计算

from math import log
# 数据集
dataSet=[[0, 0, 0, 0, 'no'],[0, 0, 0, 1, 'no'],[0, 1, 0, 1, 'yes'],[0, 1, 1, 0, 'yes'],[0, 0, 0, 0, 'no'],[1, 0, 0, 0, 'no'],[1, 0, 0, 1, 'no'],[1, 1, 1, 1, 'yes'],[1, 0, 1, 2, 'yes'],[1, 0, 1, 2, 'yes'],[2, 0, 1, 2, 'yes'],[2, 0, 1, 1, 'yes'],[2, 1, 0, 1, 'yes'],[2, 1, 0, 2, 'yes'],[2, 0, 0, 0, 'no']]
'''
将数据集D按照特征划分为一个个子集
'''
def splitDataSet(dataSet, axis, value):retDataSet=[]for featVec in dataSet:if featVec[axis] == value:reduceFeatVec=featVec[:axis]reduceFeatVec.extend(featVec[axis+1:])retDataSet.append(reduceFeatVec)return retDataSet
'''
计算数据集的经验熵
'''
def empiricalEnt(dataSet):#数据集D的样本个数num_D=len(dataSet)#记录类别的字典labelCounts={}#记录数据集中的类别,并统计其个数for featVec in dataSet:currentLabel=featVec[-1]                     #读取类别信息if currentLabel not in labelCounts.keys():   #如果读取的类别没有放入统计次数的字典,添加进去labelCounts[currentLabel]=0              #默认值为0labelCounts[currentLabel]+=1                 #计数entropy=0.0                                   #经验熵#计算经验熵for key in labelCounts:prob=float(labelCounts[key])/num_Dentropy-=prob*log(prob,2)                 #利用公式计算return entropy
'''
计算经验条件熵
'''
#特征数
features = len(dataSet[0])-1
for i in range(features):#获取第i个特征的所有值featList = [example[i] for example in dataSet]#创建集合uniqueValue,元素不可重复uniqueValue = set(featList)#经验条件熵conditionalEnt = 0.0#计算经验信息熵for value in uniqueValue:#划分子集subDataSet = splitDataSet(dataSet, i, value)#子集与原数据集之比prob = len(subDataSet)/float(len(dataSet))#子集经验熵conditionalEnt += prob*empiricalEnt(subDataSet)print(format(conditionalEnt,'.3f'))'''info = empiricalEnt(dataSet)-conditionalEntprint('第%d个特征的信息增益%.3f' %(i, info))'''
0.888
0.647
0.551
0.608

信息增益

特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D,A)=H(D)-H(D|A) g(D,A)=H(D)−H(D∣A)
其中经验熵H(D)表示对数据集D进行分类的不确定性,而经验条件熵H(D|A)表示在特征A给定的条件下对数据集D进行分类的不确定性。那么**信息增益就表示由于特征A而使得对数据集D进行分类得不确定性减少的程度。**那么在进行分类的时候肯定选择信息增益大的作为根节点。

而对信息增益的代码实现也很简单,只需要在上述经验条件熵的第二个for循环后加上如下代码即可

info = empiricalEnt(dataSet)-conditionalEnt
print('第%d个特征的信息增益%.3f' %(i, info))
第0个特征的信息增益0.083
第1个特征的信息增益0.324
第2个特征的信息增益0.420
第3个特征的信息增益0.363

信息增益比

在使用信息增益作为划分训练数据集的特征时,存在偏向于选择取值较多的特征的问题,使用信息增益比可以对这一问题进行校正。

定义:特征A对训练数据集D的信息增益比 g R ( D , A ) g_R(D,A) gR​(D,A)定义为其信息增益g(D,A)与训练数据集D关于特征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)​
其中, H A ( D ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ l o g 2 ∣ D i ∣ ∣ D ∣ H_A(D)=-\sum_{i=1}^n\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|} HA​(D)=−∑i=1n​∣D∣∣Di​∣​log2​∣D∣∣Di​∣​,n是特征A的取值个数。

参考文章:

https://blog.csdn.net/u012328159/article/details/70184415

https://blog.csdn.net/jiaoyangwm/article/details/79525237

决策树(一)——构建决策树相关推荐

  1. 决策树算法(六)——构建决策树

    写在前面的话 我就是一俗人.我俗我开心. 递归构建决策树 之前我们已经学习了怎么根据信息论的方法,把一个数据集从杂乱无章的数据集中划分出来,我们使用信息论来构建决策树一级一级分类的方法就是一个递归的过 ...

  2. R语言使用party包中的ctree函数构建条件推理决策树的流程和步骤、条件推理决策树是传统决策树的一个重要变体、条件推理树的分裂是基于显著性测试而不是熵/纯度/同质性度量来选择分裂

    R语言使用party包中的ctree函数构建条件推理决策树的流程和步骤(Conditional inference trees).条件推理决策树是传统决策树的一个重要变体.条件推理树的分裂是基于显著性 ...

  3. R语言使用rpart包构建决策树模型、使用prune函数进行树的剪枝、交叉验证预防过拟合、plotcp可视化复杂度、rpart.plot包可视化决策树、使用table函数计算混淆矩阵评估分类模型性能

    R语言使用rpart包构建决策树模型.使用prune函数进行树的剪枝.使用10折交叉验证选择预测误差最低的树来预防过拟合.plotcp可视化决策树复杂度.rpart.plot包可视化最终决策树.使用t ...

  4. R语言构建决策树(decision trees)模型并进行调优和解释

    R语言构建决策树(decision trees)模型并进行调优和解释 目录 R语言构建决策树(decision trees)

  5. 决策树(Decision Tree)、决策树的构建、决策树流程、树的生长、熵、信息增益比、基尼系数

    决策树(Decision Tree).决策树的构建.决策树流程.树的生长.熵.信息增益比.基尼系数 目录

  6. 12_信息熵,信息熵公式,信息增益,决策树、常见决策树使用的算法、决策树的流程、决策树API、决策树案例、随机森林、随机森林的构建过程、随机森林API、随机森林的优缺点、随机森林案例

    1 信息熵 以下来自:https://www.zhihu.com/question/22178202/answer/161732605 1.2 信息熵的公式 先抛出信息熵公式如下: 1.2 信息熵 信 ...

  7. dt决策树_决策树:构建DT的分步方法

    dt决策树 介绍 (Introduction) Decision Trees (DTs) are a non-parametric supervised learning method used fo ...

  8. 超级简单易懂的决策树介绍:什么是决策树,如何构建决策树

    这个笔记是根据我看这个视频来记的:https://www.youtube.com/watch?v=7VeUPuFGJHk&t=0s&list=PLyeGvkJQKy7nDT5kH9S9 ...

  9. 一个完整决策树的构建案例

    """数据样本展示:#x1,x2,x3, Y是,单身,125,否否,已婚,100,否否,单身,100,否是,已婚,110,否是,离婚,60,否否,离婚,95,是否,单身, ...

  10. 【机器学习】什么是决策树模型?如何去构建决策树?何时使用决策树?何时使用神经网络?

    系列文章目录 第十三章 Python 机器学习入门之决策树 目录 系列文章目录 前言 一.决策树模型 1 什么是决策树模型? 2 决策树学习的过程 二.如何确定在节点使用的特征 1 熵的定义 2 什么 ...

最新文章

  1. 解决WebClient或HttpWebRequest首次连接缓慢问题
  2. DF标志和串传送指令
  3. 雨棚板弹性法计算简图_钢结构工程量计算、报价要点
  4. Koa -- 基于 Node.js 平台的下一代 web 开发框架
  5. [HEOI2016/TJOI2016]字符串 (后缀数组+主席树+二分)
  6. centos tar安装mysql_centos系统通过tar.gz包安装mysql5.7.19
  7. 【codevs1074】食物链
  8. 用matlab做元胞自动机预测,元胞自动机(Cellular Automata)与城市规划及其MATLAB实现——莆田市城市发展预测...
  9. UI调试--初步尝试心得总结
  10. 一篇故事看懂从 session-cookie 到 JWT 的技术演变
  11. 代码审查和不良编程习惯
  12. lstm原文_对时间序列分类的LSTM全卷积网络的见解
  13. 多智能体一致性(Consensus)中的矩阵理论(Matrix Theory)
  14. 直升机的扭力与反扭力
  15. 使用Monkey做一次APP的压力测试
  16. 文件一键上传、汉字转拼音、excel文件上传下载功能模块的实现
  17. 小白:关于处理“can't find '__main__' module in ”这个问题的详细处理方式!
  18. 解决:win10下修改mac地址的方法
  19. 爱阅书香之书源制作 POST请求方式
  20. 跟着别人学学优化自己的Ubuntu 操作系统

热门文章

  1. 用 Python 加密文件
  2. BFS和DFS算法原理(通俗易懂版)
  3. python免费课程全套-为了学习Python,我汇总了这10个免费的视频课程!
  4. 搭建SecureCRT
  5. windows AD域的特点
  6. 苹果鼠标右键怎么按_Mac触控板常用的手势操作,让你告别Windows鼠标!
  7. 【时间序列分析】差分运算及延迟算子的性质
  8. hd printer lexmark / dazifuyin / dayin / fuyin
  9. 安卓系统定制开发[安卓平台环境搭建]
  10. 程序员需要了解的 现代散文精选翻译