机器学习:构建随机森林

机器学习:构建随机森林

作者: Wenretium

任务介绍: 用随机森林训练一个 T = 3 T=3 T=3的分类器集成,要求:3个个体学习器对应的决策树,每个决策树最大的划分层次为2层,每个划分节点(根节点和分支节点)对应属性随机选择的控制参数 k = l o g 2 d k=log_{2}d k=log2d( d d d为当前划分节点对应属性集合的大小)、3个决策树分别采用信息增益、增益率和基尼系数来选择最优划分属性。

注意: 文章修改自本人《机器学习》课程作业,全部为本人原创,仅供参考。

完整代码戳这里: 随机森林 代码

数据集:
周志华《机器学习》中西瓜数据集 2.0

共有6个属性:

  • 色泽:青绿,乌黑,浅白

  • 根蒂:蜷缩,稍蜷,硬挺

  • 敲声:浊响,沉闷,清脆

  • 纹理:清晰,稍糊,模糊

  • 脐部:凹陷,稍凹,平坦

  • 触感:硬滑,软粘

一、自助抽样,生成3个训练数据集

​ 使用sklearn的resample函数进行自助抽样。

from sklearn.utils import resample
data = list(range(1,18))
print('data', data)
data1 = resample(data, n_samples=17)
print('data1', data1)
data2= resample(data, n_samples=17)
print('data2', data2)
data3 = resample(data, n_samples=17)
print('data3', data3)

1. 数据集1

data1 = [10, 6, 14, 16, 4, 6, 11, 4, 15, 4, 4, 2, 2, 13, 4, 9, 14]

2. 数据集2

data2 = [3, 4, 13, 14, 9, 7, 14, 9, 4, 3, 2, 7, 5, 13, 12, 2, 1]

3. 数据集3

data3 = [6, 5, 16, 7, 3, 14, 16, 13, 3, 7, 1, 15, 12, 6, 16, 3, 14]

二、分别训练3个决策树

​ 其中,分别采用信息增益、增益率和基尼系数来选择最优划分属性。

1. 信息增益

1.1 原理

  • 信息熵

    ​ 是度量样本集合纯度最常用的一种指标,假定当前样本集合 D D D中第 k k k类样本所占的比例为 p k ( k = 1 , 2 ⋯ , ∣ Y ∣ ) p_k (k=1,2⋯,|Y|) pk(k=1,2,Y),则 D D D的信息熵定义为

    E n t ( D ) = − ∑ k = 1 ∣ y ∣ p k l o g 2 p k Ent(D)=-\sum_{k=1}^{|y|}{p_k log_2 p_k} Ent(D)=k=1ypklog2pk

  • 数据集的信息熵

    训练数据集 D D D中有 K K K个类 C k , k = 1 , 2 , ⋯ , K C_k,k=1,2,⋯,K Ck,k=1,2,,K ∣ D ∣ |D| D为总样本个数, ∣ C k ∣ |C_k | Ck为属于第 k k k类的样本个数,有 ∣ D ∣ = ∑ k = 1 K ∣ C k ∣ |D|=∑_{k=1}^{K}|C_k | D=k=1KCk

    当前样本集合 D D D中第 k k k类样本所占的比例为 p k = ∣ C k ∣ ∣ D ∣ , ( k = 1 , 2 ⋯ , K ) p_k=\frac{|C_k |}{|D|}, (k=1,2⋯,K) pk=DCk,(k=1,2,K),则 D D D的信息熵定义为

    E n t ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ l o g 2 ∣ C k ∣ ∣ D ∣ Ent(D)=-∑_{k=1}^K\frac{|C_k |}{|D|} log_{2} \frac{|C_k |}{|D|} Ent(D)=k=1KDCklog2DCk

  • 信息增益

    G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) Gain(D,a)=Ent(D)-∑_{v=1}^{V}\frac{|D^v |}{|D|} Ent(D^v ) Gain(D,a)=Ent(D)v=1VDDvEnt(Dv)

    信息增益越大,划分效果越好

1.2 计算

1.2.1 第一轮划分

D = { 2 , 2 , 4 , 4 , 4 , 4 , 4 , 6 , 6 , 9 , 10 , 11 , 13 , 14 , 14 , 15 , 16 } D=\left \{2, 2, 4, 4, 4, 4, 4, 6, 6, 9, 10, 11, 13, 14, 14, 15, 16 \right \} D={2,2,4,4,4,4,4,6,6,9,10,11,13,14,14,15,16}

正例正例数反例反例数
2, 2, 4, 4, 4, 4, 4, 6, 699, 10, 11, 13, 14, 14, 15, 168

E n t ( D ) = − ( 9 17 l o g 2 9 17 + 8 17 l o g 2 8 17 ) = 0.9975 Ent(D)=-(\frac{9}{17} log_{2} \frac{9}{17} + \frac{8}{17} log_{2} \frac{8}{17})=0.9975 Ent(D)=(179log2179+178log2178)=0.9975

色泽为例,计算信息增益

青绿乌黑浅白
4, 4, 4, 4, 4, 6, 6, 10, 13(9)2, 2, 9, 15(4)11, 14, 14, 16(4)

E n t ( D 1 ) = − ( 7 9 l o g 2 7 9 + 2 9 l o g 2 2 9 ) = 0.7642 Ent(D^{1})=-(\frac{7}{9} log_{2} \frac{7}{9} + \frac{2}{9} log_{2} \frac{2}{9})=0.7642 Ent(D1)=(97log297+92log292)=0.7642

E n t ( D 2 ) = − ( 2 4 l o g 2 2 4 + 2 4 l o g 2 2 4 ) = 1 Ent(D^{2})=-(\frac{2}{4} log_{2} \frac{2}{4} + \frac{2}{4} log_{2} \frac{2}{4})=1 Ent(D2)=(42log242+42log242)=1

E n t ( D 3 ) = − ( 0 4 l o g 2 0 4 + 4 4 l o g 2 4 4 ) = 0 Ent(D^{3})=-(\frac{0}{4} log_{2} \frac{0}{4} + \frac{4}{4} log_{2} \frac{4}{4})=0 Ent(D3)=(40log240+44log244)=0

KaTeX parse error: No such environment: align* at position 7: \begin{̲a̲l̲i̲g̲n̲*̲}̲ Gain(D,色泽) &= …

在其中随机选出触感根蒂纹理三个属性,同理,有

属性触感根蒂纹理
信息增益0.00080.38630.5549

所以,选择 纹理 作为划分依据

1.2.2 第二轮划分

清 晰 D 1 = { 2 , 2 , 4 , 4 , 4 , 4 , 4 , 6 , 6 , 10 , 15 } 清晰 D^{1}=\left \{2, 2, 4, 4, 4, 4, 4, 6, 6, 10, 15 \right \} D1={2,2,4,4,4,4,4,6,6,10,15}

稍 糊 D 2 = { 9 , 13 , 14 , 14 } 稍糊 D^{2}=\left \{9, 13, 14, 14 \right \} D2={9,13,14,14}

模 糊 D 3 = { 11 , 16 } 模糊 D^{3}=\left \{11, 16 \right \} D3={11,16}

  • D 1 D^{1} D1
正例正例数反例反例数
2, 2, 4, 4, 4, 4, 4, 6, 6910, 152

​ 选出触感根蒂两个属性,分别计算信息增益

属性触感根蒂
信息增益0.32040.4336

​ 所以,选择 根蒂 作为划分依据,取样本多数为标记类型

属性蜷缩稍蜷硬挺
叶结点标记
  • D 2 D^{2} D2

    全为反例,标记为 类叶结点

  • D 3 D^{3} D3

    全为反例,标记为 类叶结点

1.3 生成的决策树

2. 增益率

2.1 原理

​ 离散属性 a a a V V V个可能的取值 { a 1 , a 2 , ⋯ , a V } \left \{a^1,a^2,⋯,a^V \right \} {a1,a2,,aV} ,用 a a a来进行划分,则会产生 V V V个分支结点,其中第 v v v个分支结点包含了 D D D中所有在属性 a a a上取值为 a v a^v av的样本,记为 D v D^v Dv 。则可计算出用属性 a a a对样本集 D D D进行划分所获得的“增益率”:

G a i n − r a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) Gain_{-}ratio(D,a)=\frac{Gain(D,a)}{IV(a)} Gainratio(D,a)=IV(a)Gain(D,a)

I V ( a ) = − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ l o g 2 ∣ D v ∣ ∣ D ∣ IV(a)=-∑_{v=1}^V \frac{|D^v |}{|D|} log_2 \frac{|D^v |}{|D|} IV(a)=v=1VDDvlog2DDv

增益率越大,划分效果越好

2.2 计算

2.2.1 第一轮划分

D = { 1 , 2 , 2 , 3 , 3 , 4 , 4 , 5 , 7 , 7 , 9 , 9 , 12 , 13 , 13 , 14 , 14 } D=\left \{1, 2, 2, 3, 3, 4, 4, 5, 7, 7, 9, 9, 12, 13, 13, 14, 14 \right \} D={1,2,2,3,3,4,4,5,7,7,9,9,12,13,13,14,14}

正例正例数反例反例数
1, 2, 2, 3, 3, 4, 4, 5, 7, 7109, 9, 12, 13, 13, 14, 147

选择脐部纹理触感三个属性,分别计算增益率

脐部为例

凹陷稍凹平坦
1, 2, 2, 3, 3, 4, 4, 5, 13, 13, 14, 14(12)7, 7, 9, 9(4)12(1)

I V ( 脐 部 ) = − ( 12 17 × l o g 2 12 17 + 4 17 × l o g 2 4 17 + 1 17 × l o g 2 1 17 ) = 1.0863 IV(脐部)=-(\frac{12}{17} \times log_2\frac{12}{17} + \frac{4}{17} \times log_2\frac{4}{17} + \frac{1}{17} \times log_2\frac{1}{17})=1.0863 IV()=(1712×log21712+174×log2174+171×log2171)=1.0863

G a i n ( D , 脐 部 ) = 0.9774 − ( 12 17 × 0.9183 + 4 17 × 1 + 1 17 × 0 ) = 0.0939 Gain(D,脐部)=0.9774-(\frac{12}{17} \times 0.9183+\frac{4}{17} \times 1+\frac{1}{17} \times 0) =0.0939 Gain(D,)=0.9774(1712×0.9183+174×1+171×0)=0.0939

G a i n − r a t i o ( D , 脐 部 ) = G a i n ( D , 脐 部 ) I V ( 脐 部 ) = 0.0865 Gain_{-}ratio(D,脐部)=\frac{Gain(D,脐部)}{IV(脐部)}= 0.0865 Gainratio(D,)=IV()Gain(D,)=0.0865

同理,得到

属性脐部纹理触感
增益率0.08650.47130.006

所以,选择 纹理 作为划分依据

2.2.2 第二轮划分

清 晰 D 1 = { 1 , 2 , 2 , 3 , 3 , 4 , 4 , 5 } 清晰 D^{1}=\left \{1, 2, 2, 3, 3, 4, 4, 5 \right \} D1={1,2,2,3,3,4,4,5}

稍 糊 D 2 = { 7 , 7 , 9 , 9 , 13 , 13 , 14 , 14 } 稍糊 D^{2}=\left \{7, 7, 9, 9, 13, 13, 14, 14 \right \} D2={7,7,9,9,13,13,14,14}

模 糊 D 3 = { 12 } 模糊 D^{3}=\left \{12 \right \} D3={12}

  • D 1 D^{1} D1

    全为正例,标记为 类叶结点

  • D 2 D^{2} D2

    选择脐部触感两个属性,分别计算增益率

属性脐部触感
增益率0.31131.000

​ 所以,选择 触感 作为划分依据,取样本多数为标记类型

属性硬滑软粘
叶结点标记
  • D 3 D^{3} D3

    全为反例,标记为 类叶结点

2.3 生成的决策树

3. 基尼系数

3.1 原理

  • 基尼值

    假定当前样本集合 D D D中第 k k k类样本所占的比例为 p k ( k = 1 , 2 ⋯ , K ) p_k (k=1,2⋯,K) pk(k=1,2,K),则 D D D的基尼值定义为

    G i n i ( D ) = 1 − ∑ k = 1 K p k 2 Gini(D)=1-∑_{k=1}^Kp_k^2 Gini(D)=1k=1Kpk2

  • 数据集的基尼值

    G i n i ( D ) = 1 − ∑ k = 1 K ( ∣ C k ∣ ∣ D ∣ ) 2 Gini(D)=1-∑_{k=1}^K(\frac{|C_k |}{|D|} )^2 Gini(D)=1k=1K(DCk)2

  • 基尼系数

    G i n i − i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) Gini_{-}index(D,a)=∑_{v=1}^V\frac{|D^v |}{|D|} Gini(D^v ) Giniindex(D,a)=v=1VDDvGini(Dv)

    基尼系数越小,划分效果越好

3.2 计算

3.2.1 第一轮划分

D = { 1 , 3 , 3 , 3 , 5 , 6 , 6 , 7 , 7 , 12 , 13 , 14 , 14 , 15 , 16 , 16 , 16 } D=\left \{1, 3, 3, 3, 5, 6, 6, 7, 7, 12, 13, 14, 14, 15, 16, 16, 16 \right \} D={1,3,3,3,5,6,6,7,7,12,13,14,14,15,16,16,16}

正例正例数反例反例数
1, 2, 2, 3, 3, 4, 4, 5, 7, 7912, 13, 14, 14, 15, 16, 16, 167

选择触感脐部敲声三个属性,分别计算基尼系数

触感为例

硬滑软粘
1, 3, 3, 3, 5, 13, 14, 14, 16, 16, 16(11)6, 6, 7, 7, 12, 15(6)

G i n i − i n d e x ( D , 触 感 ) = 11 17 × ( 1 − ( 5 11 ) 2 − ( 6 11 ) 2 ) + 6 17 × ( 1 − ( 4 6 ) 2 − ( 2 6 ) 2 ) = 0.4777 Gini_{-}index(D,触感)=\frac{11}{17} \times (1-(\frac{5}{11})^{2}-(\frac{6}{11})^{2}) + \frac{6}{17} \times (1-(\frac{4}{6})^{2}-(\frac{2}{6})^{2}) =0.4777 Giniindex(D,)=1711×(1(115)2(116)2)+176×(1(64)2(62)2)=0.4777

同理,得到

属性触感脐部敲声
基尼系数0.47770.31470.4235

所以,选择 脐部 作为划分依据

3.2.2 第二轮划分

凹 陷 D 1 = { 1 , 3 , 3 , 3 , 5 , 13 , 14 , 14 } 凹陷 D^{1}=\left \{1, 3, 3, 3, 5, 13, 14, 14 \right \} D1={1,3,3,3,5,13,14,14}

稍 凹 D 2 = { 6 , 6 , 7 , 7 , 15 } 稍凹D^{2}=\left \{6, 6, 7, 7, 15 \right \} D2={6,6,7,7,15}

平 坦 D 3 = { 12 , 16 , 16 , 16 } 平坦 D^{3}=\left \{12, 16, 16, 16 \right \} D3={12,16,16,16}

  • D 1 D^{1} D1

    选择触感敲声两个属性,分别计算增益率

    属性触感敲声
    增益率0.46880.2083

    所以,选择 敲声 作为划分依据,取样本多数为标记类型

属性浊响沉闷清脆
叶结点标记
  • D 2 D^{2} D2

    选择敲声触感两个属性,分别计算增益率

属性敲声触感
增益率0.32000.3200

​ 所以,选择 敲声 作为划分依据,取样本多数为标记类型

属性浊响沉闷清脆
叶结点标记
  • D 3 D^{3} D3

    全为反例,标记为 类叶结点

3.3 生成的决策树

三、代码实现

1. 相关函数构造

# 计算信息熵
def Ent(D):
    pos, neg = cal_pos_neg(D)
    if pos != 0 and neg != 0:
        return -(pos/len(D)*math.log(pos/len(D), 2)+neg/len(D)*math.log(neg/len(D), 2))
    elif pos == 0 and neg != 0:
        return -(0+neg/len(D)*math.log(neg/len(D), 2))
    elif pos != 0 and neg == 0:
        return -(pos/len(D)*math.log(pos/len(D), 2) + 0)
    else:
        return 0
    
# 统计正反例数量
def cal_pos_neg(D):
    pos = 0
    neg = 0
    for i in D:
        if i['好瓜'] == '是':
            pos += 1
        else:
            neg += 1
    return pos, neg

# 根据属性及对应的取值划分数据集 D
def split_att(D, att):
    att_value = att_value_list[att]
    if len(att_value) == 3:
        D1 = []
        D2 = []
        D3 = []
        for melon in D:
            if melon[att] == att_value[0]:
                D1.append(melon)
            elif melon[att] == att_value[1]:
                D2.append(melon)
            else:
                D3.append(melon)
        return D1, D2, D3
    elif len(att_value) == 2:
        D1 = []
        D2 = []
        for melon in D:
            if melon[att] == att_value[0]:
                D1.append(melon)
            else:
                D2.append(melon)
        return D1, D2
    
# 计算信息增益
def Gain(D, att):
    D_spilt = split_att(D, att)
    sum = 0
    for d in D_spilt:
        sum += len(d)/len(D)*Ent(d)
    return Ent(D)-sum

# 计算增益率
def Gain_ratio(D, att):
    D_split = split_att(D, att)
    IV_a = 0
    D_l = len(D)
    for d in D_split:
        if len(d) == 0:
            IV_a += 0
        else:
            IV_a += -len(d)/D_l*math.log(len(d)/D_l, 2)
    if IV_a == 0:  # 取为无穷接近于0的数:1e-10
        IV_a = 1e-10
    return Gain(D, att)/IV_a

# 计算基尼值
def Gini(D):
    pos, neg = cal_pos_neg(D)
    D_l = len(D)
    if D_l != 0:
        return 1-(pos/D_l)**2-(neg/D_l)**2
    else:
        return 1
    
# 计算基尼系数
def Gini_index(D, att):
    D_split = split_att(D, att)
    D_l = len(D)
    Gini_index_a = 0
    for d in D_split:
        Gini_index_a += len(d)/D_l*Gini(d)
    return Gini_index_a

# 检查 D 内元素是否属于一个类别
def check_type(D):
    pos, neg = cal_pos_neg(D)
    if pos*neg == 0:  # 其中一个为 0
        return True
    else:
         return False

2. 决策树算法

# 决策树算法
def Decision_Tree(data, att_list, layer_num, score_function):
    # 控制属性选择范围
    k = int(math.log(len(att_list), 2))+1  # 向上取整
    # print(att_list,k)
    att_list = random.sample(att_list, k)  # 不放回抽样 k 个
    # 特殊情况,结束递归
    # 决策树已达到规定层数
    if layer_num >= 2:
        tpos, tneg = cal_pos_neg(data)
        print('-标记为', end=' ')
        if tpos > tneg:
            print('是', end=' ')
        else:
            print('否', end=' ')
        print('类叶结点')
        return
    # print(att_list)
    # 集合中元素全为同一类型,不用继续划分
    if check_type(data):
        print('-标记为', data[0]['好瓜'], '类叶结点')
        return
    # 用来划分的属性集为空
    elif att_list == []:
        tpos, tneg = cal_pos_neg(data)
        print('-标记为',end=' ')
        if tpos>tneg:
            print('是', end=' ')
        else:
            print('否', end=' ')
        print('类叶结点')
        return

    # 选出最优划分属性
    # 对每个属性逐个计算
    score_list = {}
    for att in att_list:
        score_list[att] = score_function(data, att)
    print('---score---')
    for i in score_list:
        print(i, round(score_list[i], 4))
    # 选出信息增益最大者
    if score_function == Gini_index:
        chosen_att = min(score_list, key=score_list.get)
    else:
        chosen_att = max(score_list, key=score_list.get)

    print('第', layer_num, '层, 选取', chosen_att, '作为划分依据')
    # 对子数据集递归划分
    for i, melon_data_pre in enumerate(split_att(data, chosen_att)):
        print('进入值',att_value_list[chosen_att][i])
        if melon_data_pre == []:
            # print(melon_data_pre)
            print('标记为', data[0]['好瓜'], '类叶结点')
        else:
            # print(layer_num+1, melon_data_pre)
            att_list_c = att_list.copy()
            att_list_c.remove(chosen_att)
            Decision_Tree(melon_data_pre, att_list_c, layer_num+1, score_function)
        print('----------返回父节点')

3. 输入数据集

melon_data = [{'色泽':'青绿', '根蒂':'蜷缩','敲声':'浊响','纹理':'清晰','脐部':'凹陷','触感':'硬滑','好瓜':'是'},
        {'色泽':'乌黑', '根蒂':'蜷缩','敲声':'沉闷','纹理':'清晰','脐部':'凹陷','触感':'硬滑','好瓜':'是'},
        {'色泽':'乌黑', '根蒂':'蜷缩','敲声':'浊响','纹理':'清晰','脐部':'凹陷','触感':'硬滑','好瓜':'是'},
        {'色泽':'青绿', '根蒂':'蜷缩','敲声':'沉闷','纹理':'清晰','脐部':'凹陷','触感':'硬滑','好瓜':'是'},
        {'色泽':'浅白', '根蒂':'蜷缩','敲声':'浊响','纹理':'清晰','脐部':'凹陷','触感':'硬滑','好瓜':'是'},
        {'色泽':'青绿', '根蒂':'稍蜷','敲声':'浊响','纹理':'清晰','脐部':'稍凹','触感':'软粘','好瓜':'是'},
        {'色泽':'乌黑', '根蒂':'稍蜷','敲声':'浊响','纹理':'稍糊','脐部':'稍凹','触感':'软粘','好瓜':'是'},
        {'色泽':'乌黑', '根蒂':'稍蜷','敲声':'浊响','纹理':'清晰','脐部':'稍凹','触感':'硬滑','好瓜':'是'},
        {'色泽':'乌黑', '根蒂':'稍蜷','敲声':'沉闷','纹理':'稍糊','脐部':'稍凹','触感':'硬滑','好瓜':'否'},
        {'色泽':'青绿', '根蒂':'硬挺','敲声':'清脆','纹理':'清晰','脐部':'平坦','触感':'软粘','好瓜':'否'},
        {'色泽':'浅白', '根蒂':'硬挺','敲声':'清脆','纹理':'模糊','脐部':'平坦','触感':'硬滑','好瓜':'否'},
        {'色泽':'浅白', '根蒂':'蜷缩','敲声':'浊响','纹理':'模糊','脐部':'平坦','触感':'软粘','好瓜':'否'},
        {'色泽':'青绿', '根蒂':'稍蜷','敲声':'浊响','纹理':'稍糊','脐部':'凹陷','触感':'硬滑','好瓜':'否'},
        {'色泽':'浅白', '根蒂':'稍蜷','敲声':'沉闷','纹理':'稍糊','脐部':'凹陷','触感':'硬滑','好瓜':'否'},
        {'色泽':'乌黑', '根蒂':'稍蜷','敲声':'浊响','纹理':'清晰','脐部':'稍凹','触感':'软粘','好瓜':'否'},
        {'色泽':'浅白', '根蒂':'蜷缩','敲声':'浊响','纹理':'模糊','脐部':'平坦','触感':'硬滑','好瓜':'否'},
        {'色泽':'青绿', '根蒂':'蜷缩','敲声':'沉闷','纹理':'稍糊','脐部':'稍凹','触感':'硬滑','好瓜':'否'}]
att_list = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']
att_value_list = {'色泽':['青绿','乌黑','浅白'],
            '根蒂':['蜷缩','稍蜷','硬挺'],
            '敲声':['浊响','沉闷','清脆'],
            '纹理':['清晰','稍糊','模糊'],
            '脐部':['凹陷','稍凹','平坦'],
            '触感':['硬滑','软粘']}

4. 分别用三种方法构造决策树

4.1 信息增益
for i in data1:
    melon_data_pre.append(melon_data[i-1])

Decision_Tree(melon_data_pre, att_list, 0, Gain)
4.2 增益率
for i in data2:
    melon_data_pre.append(melon_data[i-1])
    
Decision_Tree(melon_data_pre, att_list, 0, Gain_ratio)
4.3 基尼指数
for i in data3:
    melon_data_pre.append(melon_data[i-1])

Decision_Tree(melon_data_pre, att_list, 0, Gini_index)

5. 输出结果

5.1 信息增益
5.2 增益率
5.3 基尼指数

四、T=3 的分类器集成

结果如下:

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值