机器学习入门-西瓜书总结笔记第十五章


一、基本概念

机器学习中的 “规则”(rule) 通常是指语义明确、能描述数据分布所隐含的客观规律或领域概念、可写为“若…,则…”形式的逻辑规则。“规则学习”(rule learning)是从训练数据中学习出一组能用于对未见示例进行判别的规则。
形式化地看,一条规则形如
⊕ ← f 1 ∧ f 2 ∧ ⋯ ∧ f L \oplus\leftarrow f_1\wedge f_2\wedge \cdots\wedge f_L f1f2fL
其中逻辑蕴含符号“ ← \leftarrow ”右边部分称为 “规则体”(body),表示该条规则的前提,左边部分称为 “规则头”(head),表示该条规则的结果。规则体是由逻辑文字(literal) f k f_k fk组成的合取式(conjunction),其中合区符号" ∧ \wedge "用来表示“并且”。每个文字 f k f_k fk都是对示例属性进行检验的布尔表达式,例如“(色泽=乌黑)”或“(根蒂=硬挺)”。L是规则体中逻辑文字的个数,称为规则的长度。规则头的“ ⊕ \oplus ”同样是逻辑文字,一般用来表示规则所判定的目标类别或概念,例如“好瓜”。这样的逻辑规则也被称为“if-then规则”。
与神经网络、支持向量机这样的“黑箱模型”相比,规则学习具有更好的可解释性,能使用户更直观地对判别过程有所了解。另一方面,数理逻辑具有极强的表达能力,绝大多数人类知识都能通过数理逻辑进行简洁的刻画和表达。例如“父亲的父亲是爷爷”这样的知识不易用函数描述,而用一阶逻辑则可方便地写为“爷爷(X,Y) ← \leftarrow 父亲(X,Z) ∧ 父 亲 ( Z , Y ) \wedge父亲(Z,Y) Z,Y”,因此,规则学习能更自然地在学习过程中引入领域知识。此外,逻辑规则的抽象描述能力在处理一些高度负责的AI任务时具有显著优势,例如在问答系统中有时可能遇到非常多、甚至无穷种可能的答案,此时若能基于逻辑规则进行抽象表述或者推理,则将带来极大的便利。
假定我们从西瓜数据集中学得规则集合 R \mathcal R R:
规 则 1 : 好 瓜 ← ( 根 蒂 = 蜷 缩 ) ∧ ( 肚 部 = 凹 陷 ) ; 规 则 2 : ¬ 好 瓜 ← ( 纹 理 = 模 糊 ) \begin{aligned} &规则1:好瓜\leftarrow(根蒂=蜷缩)\wedge(肚部=凹陷);\\ &规则2:\neg 好瓜\leftarrow (纹理=模糊) \end{aligned} 1(=)(=)2¬(=)
规则1的长度为2,它通过判断两个逻辑文字的 赋值(valuation) 来对示例进行判别。符合该规则的样本称为被该规则 “覆盖”(cover)。需注意的是,被规则1覆盖的样本是好瓜,但没被规则1覆盖的未必不是好瓜;只有被规则2这样以“ ¬ \lnot ¬好瓜”为头的规则覆盖的才不是好瓜。
显然,规则集合中的每条规则都可看作一个子模型,规则集合是这个子模型的一个集成。当同一个示例被判别结果不同的多条规则覆盖时,称发生了 “冲突”(conflict),解决冲突的办法称为 “冲突消解”(conflict resolution)。常用的冲突消解策略有投票法、排序法、元规则法等。投票法是将判别相同规则数量最多的结果作为最终结果。排序法是在规则集合上定义一个顺序,在发生冲突时使用排序最前的规则;相应的规则学习过程称为 “带序规则”(ordered rule) 学习或 “优先级规则”(priority rule) 学习。元规则法是根据领域知识事先设定一些 “元规则”(meta-rule),即关于规则的规则,例如“发生冲突时使用长度最小的规则”,然后根据元规则的指导来使用规则集。
此外,从训练集学得的规则集合也许不能覆盖所有可能的未见示例,例如前述规则集合 R \mathcal R R无法对“根蒂=蜷缩”、“脐部=稍凹”且“纹理=清晰”的示例进行判别;这种情况在属性数目很多时常出现。因此,规则学习算法通常会设置一条 “默认规则”(default rule),由它来处理规则集合未覆盖的样本;例如为 R \mathcal R R增加一条默认规则:“未被规则1,2覆盖的都不是好瓜”。
从形式语言表达能力而言,规则可分为两类:“命题规则”(propositionanl rule)“一阶规则”(first-order rule)。前者是由 “原子命题”(propositional atom) 和逻辑连接词“与”( ∧ \wedge )、“或”( ∨ \vee )、“非”( ¬ \lnot ¬)和“蕴含”( ← \leftarrow )构成的简单陈述句;例如规则集 R \mathcal R R就是一个命题规则集,“根蒂=蜷缩” “脐部=凹陷”都是原子命题。后者的基本成分是能描述事物的属性或关系的 “原子公式”(atomic formula),例如表达父子关系的 谓词(predicate) “父亲(X,Y)”就是原子公式,再如表示加一操作“ σ ( X ) = X + 1 \sigma(X)=X+1 σ(X)=X+1”的函数“ σ ( X ) \sigma(X) σ(X)”也是原子公式。如果进一步用谓词“自然数(X)”表示X是自然数,“ ∀ X \forall X X”表示“对于任意X成立”,“ ∃ Y \exist Y Y”表示“存在Y使之成立”,那么“所有自然数加1都是自然数”就可写为“ ∀ X ∃ Y ( 自 然 数 ( Y ) ← 自 然 数 ( X ) ∧ ( Y = σ ( X ) ) ) \forall X \exist Y(自然数(Y)\leftarrow 自然数(X)\wedge(Y=\sigma(X))) XY(YXY=σX)”,或者更简洁的“ ∀ X ( 自 然 数 ( σ ( X ) ) ← 自 然 数 ( X ) ) \forall X(自然数(\sigma(X))\leftarrow 自然数(X)) X(σ(X)X)”。这样的规则就是一阶规则,其中的X和Y称为逻辑变量, ∀ , ∃ \forall,\exist ,分别表示“任意”和“存在”,用于限定变量的取值范围,称为 “量词”(quantifier)。显然,一阶规则能表达复杂的关系,因此也被称为“关系型规则”(relational rule)。以西瓜数据为例,若我们简单地把属性当作谓词来定义示例与属性直接的关系,则命题规则集 R \mathcal R R可改写为一阶规则集 R ′ \mathcal R' R
规 则 1 : 好 瓜 ( X ) ← 根 蒂 ( X , 蜷 缩 ) ∧ 肚 部 ( X , 凹 陷 ) ; 规 则 2 : ¬ 好 瓜 ( X ) ← 纹 理 ( X , 模 糊 ) \begin{aligned} &规则1:好瓜(X)\leftarrow根蒂(X,蜷缩)\wedge肚部(X,凹陷);\\ &规则2:\neg 好瓜(X)\leftarrow 纹理(X,模糊) \end{aligned} 1(X)(X,)(X,)2¬(X)(X,)
显然,从形式语言系统的角度来看,命题规则是一阶规则的特例,因此一阶规则的学习比命题规则要复杂得多。

二、序贯覆盖

规则学习得目标是产生一个能覆盖尽可能多得样例得规则集。最直接得做法是 “序贯覆盖”(sequential covering),即逐条归纳:在训练集上每学习到一条规则,就将该规则覆盖得训练样例去除,然后以剩下得训练样例组称训练集重复上述过程。由于每次只处理一部分数据,因此也被称为 “分治”(separate-and-conquer)策略
我们以命题规则学习为例来考察序贯覆盖法。命题规则得规则体是对样例属性值进行评估得布尔函数,如“色泽=青绿”“含糖量 ≤ 0.2 \le 0.2 0.2”等,规则头是样例类别。序贯覆盖法得关键是如何从训练集学出单条规则。显然,对规则学习目标 ⊕ \oplus ,产生一条规则就是寻找最优的一组逻辑文字来构成规则体,这是一个搜素问题。形式化地说,给定正例集合与反例集合,学习任务是基于候选文字集合 F = { f k } \mathcal F = \{f_k\} F={fk}来生成最优规则r。在命题规则学习中,候选文字是形如“R(属性 i _i i,属性值 i , j _{i,j} i,j)”的布尔表达式,其中属性 i _i i表示样例地i个属性,,属性值 i , j _{i,j} i,j表示属性 i _i i第j个候选值, R ( x , y ) R(x,y) R(x,y)则是判断x,y是否满足关系R的二元布尔函数。
最简单的做法是从空规则“ ⊕ ← \oplus\leftarrow ”开始,将正例类别作为规则头,再逐个遍历训练集中的每个属性及取值,尝试将其作为逻辑文字增加到规则体中,若能使当前规则体仅覆盖正例,则由此产生一条规则,然后去除已被覆盖的正例并基于剩余样本尝试生成下一条规则。
以西瓜数据集2.0训练集为例,首先根据第1个样例生成文字“好瓜”和“色泽=青绿”加入规则,得到
好 瓜 ← ( 色 泽 = 青 绿 ) 好瓜\leftarrow(色泽=青绿) (=绿)
这条规则覆盖了多个样例,其中两个正例和两个反例,不符合“当前规则仅覆盖正例”的条件。于是,尝试将该命题替换为基于属性“色泽”形成的其他原子命题,例如“色泽=乌黑”;然而在这个数据集上,这样的操作不能产生符合条件的规则。于是回到“色泽=青绿”,尝试增加一个基于其他属性的原子命题,例如“根蒂=蜷缩”:
好 瓜 ← ( 色 泽 = 青 绿 ) ∧ ( 根 蒂 = 蜷 缩 ) 好瓜\leftarrow(色泽=青绿)\wedge(根蒂=蜷缩) (=绿)(=)
该规则仍覆盖了反例。于是将第二个命题替换为基于该属性形成的其他原子命题,例如“根蒂=稍蜷”:
好 瓜 ← ( 色 泽 = 青 绿 ) ∧ ( 根 蒂 = 稍 蜷 ) 好瓜\leftarrow(色泽=青绿)\wedge(根蒂=稍蜷) (=绿)(=)
这条规则不覆盖任何反例,虽然它仅覆盖一个正例,但已满足“当前规则仅覆盖正例”的条件。因此保留这条规则并去除它覆盖的样例,然后将剩下的9个样例用作训练集。如此继续作,得到规则
在这里插入图片描述这个规则覆盖了所有正例,未覆盖任何反例,这就是序贯覆盖法学得的结果。
上面这种基于穷尽搜索的做法在属性和候选值较多时会由于组合爆炸而不可行。现实任务中一般有两种策略来产生规则:第一种是 “自顶向下”(top-down),即从比较一般的规则开始,逐渐添加新文字以缩小规则覆盖范围,直到满足预定条件为止;亦称为 “生成-测试”(generate-then-test)法,是规则逐渐 “特化”(specialization) 的过程。第二种策略是 “自底向上”(bottom-up),即从比较特殊的规则开始,逐渐删除文字以扩大规则覆盖范围,直至满足条件为止;亦称为 “数据驱动”(data-driven)法,是规则逐渐 “泛化”(generalization) 的过程。第一种策略是覆盖范围从大到小搜索规则,第二种策略则相反;前者通常更容易产生泛化性能较好的规则,而后者则更适合于训练样本较少的情形,此外,前者对噪声的鲁棒性比后者要强得多。因此,在命题规则学习中通常使用第一种策略,而第二种策略在一阶规则学习这类假设空间非常复杂的任务上使用较多。
下面以西瓜数据集2.0训练集为例来展示自顶向下的规则生成法。首先从空规则开始,逐一将“属性=取值”作为原子命题加入空规则进行考察。假定基于训练集准确率来评估规则的优劣,n/m表示加入某命题后新规则在训练集上的准确率,其中m为覆盖的样例总数,n为覆盖的正例数。如下图所示,经过第一轮评估,“色泽=乌黑”和“脐部=凹陷”都达到了最高准确率3/4.
在这里插入图片描述将属性次序最靠前的逻辑文字“色泽=乌黑”加入空规则,得到
好 瓜 ← ( 色 泽 = 乌 黑 ) 好瓜\leftarrow(色泽=乌黑) (=)
然后,对上面这条规则覆盖的样例,通过第二轮评估可发现,将上图中的五个逻辑文字加入规则后都能达到100%准确率,将覆盖样例最多、且属性次序最靠前的逻辑文字加入规则,得到
好 瓜 ← ( 色 泽 = 乌 黑 ) ∧ ( 根 蒂 = 蜷 缩 ) 好瓜\leftarrow(色泽=乌黑)\wedge(根蒂=蜷缩) (=)(=)
规则生成过程中涉及一个评估规则优劣的标准,在上面的例子中使用的标准是:先考虑规则准确率,准确率相同时考虑覆盖样例数,再相同考虑属性次序。现实应用中可根据具体任务情况设计适当的标准。
此外,在上面的例子中每次仅考虑一个“最优”文字,这通常过于贪心,易于陷入局部最优。为了缓解这个问题,可采用一些相对温和的做法,例如采用“集束搜索”(beam search),即每轮保留最优的b个逻辑文字,在下一轮均用于构建候选集,再把候选集中最优的b个留待再下一轮使用。如上图中若采用b=2的集束搜索,则第一轮将保留准确率为3/4的两个逻辑文字,在第二轮评估后就能获得下面这条规则,其准确率仍为100%,但是覆盖率3个正例。
由于贯序覆盖法简单有效,几乎所有规则学习算法都以它为基础框架。它能方便地推广到多分类问题上,只需将每类分别处理即可:当学习关于第c类的规则时,将所有属于类别c的样例作为正例,其他类别的样本作为反例。

三、剪枝优化

规则生成本质上是一个贪心搜索过程,需有一定的机制来缓解过拟合的风险,最常用的做法是剪枝(pruning)。与决策树相似,剪枝可发生在规则生长过程中,即“预剪枝”,也可发生在规则产生后,即“后剪枝”。通常是基于某种性能度量指标来评估增/删逻辑文字前后的规则性能,或增/删规则前后的规则集性能,从而判断是否要进行剪枝。
剪枝还可借助统计显著性检验来进行。例如CN2算法在预剪枝时,假设用规则集进行预测必须显著优于直接基于训练样例集后验概率分布进行预测。为便于计算,CN2使用了似然率统计量(Likelihood Ratio Statistics,简称LRS)。令 m + , m − m_+,m_- m+,m分别表示训练样例集中的正、反例数目, m ^ + , m ^ − \hat m_+,\hat m_- m^+,m^分别表示规则(集)覆盖的正、反例数目,则有
L R S = 2 ⋅ ( m ^ + log ⁡ 2 ( m ^ + m ^ + + m ^ − ) ( m + m + + m − ) + m ^ − log ⁡ 2 ( m ^ − m ^ + + m ^ − ) ( m − m + + m − ) ) LRS = 2\cdot\Bigg(\hat m_+ \operatorname{log}_2 \frac{(\frac{\hat m_+}{\hat m_+ + \hat m_-})}{(\frac{m_+}{m_+ + m_-})}+\hat m_- \operatorname{log}_2 \frac{(\frac{\hat m_-}{\hat m_+ + \hat m_-})}{(\frac{m_-}{m_+ + m_-})}\Bigg) LRS=2(m^+log2(m++mm+)(m^++m^m^+)+m^log2(m++mm)(m^++m^m^))
这实际上是一种信息量指标,衡量了规则(集)覆盖样例的分布与训练集经验分布的差别:LRS越大,说明采用规则(集)进行预测与直接使用训练集正、反例比率进行猜测的差别越大;LRS越小,说明规则(集)的效果越可能仅是偶然现象。在数据量比较大的现实任务中,通常设置为在LRS很大(例如0.99)时CN2算法才停止规则(集)生长。
后剪枝最常用的策略是“减错剪枝”(Reduced Error Pruning,简称REP),其基本做法是:将样例集划分为训练集和验证集,从训练集上学得规则集 R \mathcal R R后进行多轮剪枝,在每一轮穷举所有可能的剪枝操作,包括删除规则中某个文字、删除规则结尾文字、删除规则结尾多个文字、删除整条规则等,然后用验证集对剪枝产生的所有候选规则集进行评估,保留最好的那个规则集进行下一轮剪枝,如此继续,直至无法通过剪枝提高验证集上的性能为止。
REP剪枝通常很有效,但其复杂度是 O ( m 4 ) O(m^4) O(m4),m为训练样例数目。IREP(Incremental REP)将复杂度降到 O ( m log ⁡ 2 m ) O(m\operatorname{log}^2m) O(mlog2m),其做法是:在生成每条规则前,先将当前样例集划分为训练集和验证集,在训练集上生成一条规则 r \pmb r rrr,立即在验证集上对齐进行REP剪枝,得到规则 r ′ \pmb r' rrr;将 r ′ \pmb r' rrr覆盖的样例去除,在更新后的样例集上重复上述过程。显然,REP是针对规则集进行剪枝,而IREP仅对单条规则进行剪枝,因此后者比前者更高效。
若将剪枝机制与其他一些后处理收单结合起来对规则集进行优化,则往往能获得更好的效果。以著名的规则学习算法RIPPER为例,其泛化性能超过很多决策树算法,而且学习速度也比大多数决策树算法更快,奥妙就在于将剪枝与后处理优化相结合。
RIPPER算法描述如下图。它使用IREP剪枝机制生成规则 R \mathcal R R。IREP是IREP的改进,主要是以 m ^ + + ( m − − m ^ − ) m + + m − \frac{\hat m_++(m_--\hat m_-)}{m_++m_-} m++mm^++(mm^)取代了IREP使用的准确率作为规则性能度量指标,在剪枝时删除规则尾部的多个文字,并在最终得到规则集之后再进行一次IREP剪枝。RIPPER中的后处理机制是为了在剪枝的基础上进一步提升性能。对 R \mathcal R R中的每条规则 r i \pmb r_i rrri,RIPPER为它产生两个变体:

  • r i ′ \pmb r_i' rrri:基于 r i \pmb r_i rrri覆盖的样例,用IREP*重新生成一条规则 r i ′ \pmb r_i' rrri,该规则称为替换规则(replacement rule)
  • r i ′ ′ \pmb r_i'' rrri:对 r i \pmb r_i rrri增加文字进行特化,然后再用IREP*剪枝生成一条规则 r i ′ ′ \pmb r_i'' rrri,该规则称为修订规则(revised rule)
    在这里插入图片描述接下来,把 r i ′ \pmb r_i' rrri r i ′ ′ \pmb r_i'' rrri分别与 R \mathcal R R中除 r i \pmb r_i rrri之外的规则放在一起,组成规则集 R ′ \mathcal R' R R ′ ′ \mathcal R'' R,将它们与 R \mathcal R R一起进行比较,选择最优的规则集保留下来。这就是上图中算法第4行所做的操作。
    为什么RIPPER的优化策略会有效呢?原因很简单:最初生成 R \mathcal R R的时候,规则是按序生成的,每条规则都没有对其后产生的规则加以考虑,这样的贪心算法本质常导致算法陷入局部最优;RIPPER的后处理优化过程将 R \mathcal R R中所有规则放在一起重新加以优化,恰是通过全局的考虑来缓解贪心算法的局部性,从而往往能得到更好的效果。

四、一阶规则学习

处理对象之间的“关系”(relation),而关系信息在很多任务中非常重要。例如,在现实世界挑选西瓜时,通常很难把水果摊上所有西瓜的特征用属性值描述出来,很难判断:色泽看起来多深才叫“色泽青绿”,敲起来多低才叫“敲声沉闷”,比较现实的做法是将西瓜进行相互比较。然而,这已超过了命题逻辑的表达能力,需用一阶逻辑表示,并且要使用一阶规则学习。
在这里插入图片描述在这里插入图片描述于是,西瓜数据集2.0训练集就转化为上表的西瓜数据集5.0。这样的数据直接描述了样本间的关系,称为 “关系数据”(relational data),其中由原样本转化而来的“色泽更深”“根蒂更蜷”等原子公式称为 “背景知识”(background knowledge),而由样本类别转化而来的关于“更好”“ ¬ \lnot ¬更好”的原子公式称为关系数据样例(examples)。从西瓜数据集5.0可学出这样的一阶规则:
( ∀ X , ∀ Y ) ( 更 好 ( X , Y ) ) ← 根 蒂 更 蜷 ( X , Y ) ∧ 脐 部 更 凹 ( X , Y ) (\forall X,\forall Y)(更好(X,Y))\leftarrow 根蒂更蜷(X,Y)\wedge 脐部更凹(X,Y) (X,Y)((X,Y))(X,Y)(X,Y)
其规则头、规则体都是一阶逻辑表达式,“更好 ( ⋅ , ⋅ ) (\cdot,\cdot) (,)”、“根蒂更蜷 ( ⋅ , ⋅ ) (\cdot,\cdot) (,)”、“脐部更凹 ( ⋅ , ⋅ ) (\cdot,\cdot) (,)”是关系描述所定义的谓词,个体对象“瓜1”、“瓜2”被逻辑变量“X”、“Y”替换。全称量词“ ∀ \forall ”表示该规则对所有个体都成立;通常,在一阶规则中所有出现的变量都被全称量词限定,因此下面在不影响理解的情况下将省略量词部分。
一阶规则有强大的表达能力,例如它能简洁地表达递归概念,如
更 好 ( X , Y ) ← 更 好 ( X , Y ) ∧ 更 好 ( Z , Y ) 更好(X,Y)\leftarrow 更好(X,Y)\wedge更好(Z,Y) (X,Y)(X,Y)(Z,Y)
一阶规则学习能容易地引入领域知识,这是它相对于命题规则学习的另一个大优势。在命题规则学习乃至一般的统计学习中,若欲引入领域知识,通常有两种做法:在现有属性的基础上基于领域知识构造新属性,或基于领域知识设计某种函数机制(例如正则化)来对假设空间加以约束。然而,现实任务中并非所有的领域知识都能容易地通过属性重构和函数约束来表达。例如,假定获得了包含某未知元素的化合物X,欲通过试验来发现它与已知化合物Y的反应方程式。可多次重复试验,测出每次结果中化合物的组分含量。虽然对反应中的未知元素性质一无所知,但知道一些普遍成立的化学原理,例如金属原子一般产生离子键、氢键之间一般都是共价键等,并且也了解已知元素间可能发生的反应。有了这些领域知识,重复几次试验后就不难学出X和Y的反应方程式,还可能推测出X的性质、甚至发现新的分子和元素。类似这样的领域知识充斥在日常生活与各类任务中,但在基于命题表示的学习中加以利用确非常困难。
FOIL(First-Order Inductive Learner)是著名的一阶规则学习算法,它遵循序贯覆盖框架且采用子顶向下的规则归纳策略,与第二节中的命题规则学习过程很相似。但由于逻辑变量的存在,FOIL在规则生成时需考虑不同的变量组合。例如在西瓜数据集5.0上,对“更好(X,Y)”这个概念,最初的空规则是
更 好 ( X , Y ) ← 更好(X,Y) \leftarrow (X,Y)
接下来要考虑数据中所有其他谓词以及各种变量搭配作为候选文字。新加入的文字应包含至少一个已出现的变量,否则没有任何实质意义。在这个例子中考虑下列候选文字:
从FOIL使用“FOIL增益”(FOIL gain)来选择文字
F _ G a i n = m ^ + × ( log ⁡ 2 m ^ + m ^ + + m ^ − − log ⁡ 2 m + m + + m − ) F\_Gain = \hat m_+ \times \bigg(\operatorname{log}_2\frac{\hat m_+}{\hat m_++\hat m_-}-\operatorname{log}_2\frac{m_+}{m_++m_-}\bigg) F_Gain=m^+×(log2m^++m^m^+log2m++mm+)
其中, m ^ + , m ^ − \hat m_+,\hat m_- m^+,m^分别为增加候选文字后新规则所覆盖的正、反例数; m + , m − m_+,m_- m+,m为原规则覆盖的正、反例数。FOIL增益与决策树使用的信息增益不同,它仅考虑正例的信息量,并且用新规则覆盖的正例数作为权重。这是由于关系数据中正例数往往远小于反例数,因此通常对正例应赋予更多的关注。
在西瓜数据集5.0的例子中,只需给初始的空规则体加入“色泽更深(X,Y)”或“脐部更凹(X,Y)”,新规则就能覆盖16个正例和2个反例,所对应的FOIL增益为候选最大值 16 × ( log ⁡ 2 16 18 − log ⁡ 2 25 50 ) = 13.28 16\times(\operatorname{log}_2\frac{16}{18}-\operatorname{log}_2\frac{25}{50})=13.28 16×(log21816log25025)=13.28。假定前者被选中,则得到
更 好 ( X , Y ) ← 色 泽 更 深 ( X , Y ) 更好(X,Y)\leftarrow 色泽更深(X,Y) (X,Y)(X,Y)
该规则仍覆盖2个反例。于是,FOIL像命题规则学习那样继续增加规则体长度,最终生成合适的单条规则加入规则集。此后,FOIL使用规则集对规则集进行优化。
若允许将目标谓词作为候选文字加入规则体,则FOIL能学出递归规则;若允许将否定形式的文字 ¬ f \lnot f ¬f作为候选,则往往能得到更简洁的规则集。
FOIL可大致看作命题规则学习与归纳逻辑程序设计之间的过度,其自顶向下的规则生成过程不能支持函数和逻辑表达式嵌套,因此规则表达能力仍有不足;但它是把命题规则学习过程通过变量替换等操作直接转化为一阶规则学习,因此比一般归纳逻辑程序设计更高效。

五、归纳逻辑程序设计

归纳逻辑程序设计(Inductive Logic Programming,简称ILP)在一阶规则学习中引入了函数和逻辑表达式嵌套。一方面,这使得机器学习系统具备了更为强大的表达能力;另一方面,ILP可看作机器学习技术来解决基于背景知识的逻辑程序(logic program)归纳,其学得的“规则”可被PROLOG等逻辑程序设计语言直接使用。
然而,函数和逻辑表达式嵌套的引入也带来了计算上的巨大挑战。例如,给定一元谓词P和医院函数 f f f,它们能组成的文字有 P ( X ) , P ( f ( X ) ) , P ( f ( f ( X ) ) ) P(X),P(f(X)),P(f(f(X))) P(X),P(f(X)),P(f(f(X)))等无穷多个,这就使得规则学习过程中可能的候选原子公式有无穷多个。若仍采用命题逻辑规则或FOIL学习那样自顶向下的规则生成过程,则在增加规则长度时将因无法列举所有候选文字而失败。实际困难还不知这些,例如计算FOIL增益需对规则覆盖的全部正反力计算,而引入函数和逻辑表达式嵌套之后这也变得不可行

1.最小一般泛化

归纳逻辑程序设计采用自底向上的规则生成策略,直接将一个或多个正例所对应的具体事实(grounded fact)作为初始规则,再对规则逐步进行泛化以增加其对样例的覆盖率。泛化操作可以是将规则中的常量替换为逻辑变量,也可以是删除规则体中的某个文字。
以西瓜数据集5.0为例,为了简便起见,暂且假定“更好(X,Y)”仅决定于(X,Y)取值相同的关系,正例“更好(1,10)”和“更好(1,15)”所对应的初始规则分别为
更 好 ( 1 , 10 ) ← 根 蒂 更 蜷 ( 1 , 10 ) ∧ 声 音 更 沉 ( 1 , 10 ) ∧ 脐 部 更 凹 ( 1 , 10 ) ∧ 触 感 更 硬 ( 1 , 10 ) ; 更 好 ( 1 , 15 ) ← 根 蒂 更 蜷 ( 1 , 15 ) ∧ 脐 部 更 凹 ( 1 , 15 ) ∧ 触 感 更 硬 ( 1 , 15 ) ; \begin{aligned} &更好(1,10)\leftarrow 根蒂更蜷(1,10)\wedge 声音更沉(1,10)\wedge 脐部更凹(1,10)\wedge 触感更硬(1,10);\\ &&更好(1,15)\leftarrow 根蒂更蜷(1,15)\wedge 脐部更凹(1,15)\wedge 触感更硬(1,15);\\ \end{aligned} (1,10)(1,10)(1,10)(1,10)(1,10);(1,15)(1,15)(1,15)(1,15);
显然,这两条规则只对应了特殊的关系数据样例,难以具有泛化能力。因此,希望把这样的“特殊”规则转变为更“一般”的规则。为达到这个目的,最基础的技术是“最小一般泛化”(Least General Generalization,简称LGG)。
给定一阶公式 r 1 \pmb r_1 rrr1 r 2 \pmb r_2 rrr2,LGG先找出涉及相同谓词的文字,然后对文字中每个未知的常量逐一进行考察,若常量在两个文字中相同则保持不变,记为 L G G ( t , t ) = t LGG(t,t)=t LGG(t,t)=t;否则将它们替换为同一个新变量,并将该替换应用于公式的所有其他位置:假定这两个不同的常量分别为是s,t,新变量为V,则记为 L G G ( s , t ) = V LGG(s,t)=V LGG(s,t)=V,并在以后所有出现 L G G ( s , t ) LGG(s,t) LGG(s,t)的位置用V来替代。例如对上面例子中的两条规则,先比较“更好(1,10)”和“更好(1,15)”,由于文字中常量"10" ≠ \ne ="15",因此将它们都替换为Y,并在 r 1 \pmb r_1 rrr1 r 2 \pmb r_2 rrr2中将其余位置上成对出现的"10"和"15"都替换为Y,得到
更 好 ( 1 , Y ) ← 根 蒂 更 蜷 ( 1 , Y ) ∧ 声 音 更 沉 ( 1 , Y ) ∧ 脐 部 更 凹 ( 1 , Y ) ∧ 触 感 更 硬 ( 1 , Y ) ; 更 好 ( 1 , Y ) ← 根 蒂 更 蜷 ( 1 , Y ) ∧ 脐 部 更 凹 ( 1 , Y ) ∧ 触 感 更 硬 ( 1 , Y ) ; \begin{aligned} &更好(1,Y)\leftarrow 根蒂更蜷(1,Y)\wedge 声音更沉(1,Y)\wedge 脐部更凹(1,Y)\wedge 触感更硬(1,Y);\\ &&更好(1,Y)\leftarrow 根蒂更蜷(1,Y)\wedge 脐部更凹(1,Y)\wedge 触感更硬(1,Y);\\ \end{aligned} (1,Y)(1,Y)(1,Y)(1,Y)(1,Y);(1,Y)(1,Y)(1,Y)(1,Y);
然后,LGG忽略 r 1 \pmb r_1 rrr1 r 2 \pmb r_2 rrr2中不含共同谓词的文字,因为若LGG包含某条公式所没有的谓词,则LGG无法特化为那条公式。容易看出,在这个例子中需忽略“声音更沉(1,10)”这个文字,于是得到LGG为
更 好 ( 1 , Y ) ← 根 蒂 更 蜷 ( 1 , Y ) ∧ 脐 部 更 凹 ( 1 , Y ) ∧ 触 感 更 硬 ( 1 , Y ) ; 更好(1,Y)\leftarrow 根蒂更蜷(1,Y)\wedge 脐部更凹(1,Y)\wedge 触感更硬(1,Y); (1,Y)(1,Y)(1,Y)(1,Y);
上式仅能判断瓜1是否比其他瓜更好。为了提升其泛化能力,假定另有一条关于瓜2的初始化规则
更 好 ( 2 , 10 ) ← 颜 色 更 深 ( 2 , 10 ) ∧ 根 蒂 更 蜷 ( 2 , 10 ) ∧ 敲 声 更 沉 ( 2 , 10 ) ∧ 脐 部 更 凹 ( 2 , 10 ) ∧ 触 感 更 硬 ( 2 , 10 ) 更好(2,10)\leftarrow 颜色更深(2,10)\wedge 根蒂更蜷(2,10)\wedge 敲声更沉(2,10)\wedge 脐部更凹(2,10)\wedge 触感更硬(2,10) (2,10)(2,10)(2,10)(2,10)(2,10)(2,10)
于是可求取上面两式的LGG。注意到文字“更好(2,10)”和“更好(1,Y)”的所对应位置同时出现了常量“10”与变量“Y”,于是可令 L G G ( 10 , Y ) = Y 2 LGG(10,Y)=Y_2 LGG(10,Y)=Y2,并将所有"10"与”Y“成对出现的位置均替换为 Y 2 Y_2 Y2。最后,令 L G G ( 2 , 1 ) = X LGG(2,1)=X LGG(2,1)=X并删去谓词不同的文字,就得到如下这条不包含常量的一般规则:
更 好 ( X , Y 2 ) ← 根 蒂 更 蜷 ( X , Y 2 ) ∧ 脐 部 更 凹 ( X , Y 2 ) ∧ 触 感 更 硬 ( X , Y 2 ) 更好(X,Y_2)\leftarrow 根蒂更蜷(X,Y_2)\wedge 脐部更凹(X,Y_2)\wedge 触感更硬(X,Y_2) (X,Y2)(X,Y2)(X,Y2)(X,Y2)
上面的例子中仅考虑了肯定文字,未使用“ ¬ \lnot ¬”符号。实际上LGG还能进行更复杂的泛化操作。此外,上面还假定“更好(X,Y)”的初始规则仅包含变量同为(X,Y)的关系,而背景知识中往往包含其他一些有用的关系,因此许多ILP系统采用了不同的初始规则选择方法。最常用的是RLGG(Relative Least General Generalizaition),它在计算LGG时考虑所有的背景知识,将样例e的初始规则定义为 e ← K e\leftarrow K eK,其中K是背景知识中所有原子的合取。
容易证明,LGG是能特化为 r 1 \pmb r_1 rrr1 r 2 \pmb r_2 rrr2的所有一阶公式中最特殊的一个:不存在即能特化为 r 1 \pmb r_1 rrr1 r 2 \pmb r_2 rrr2,也能泛化为它们的LGG的一阶公式 r ′ \pmb r' rrr
在归纳逻辑程序设计中,获得LGG之后,可将其看作单挑规则加入规则集,最后再用前几节介绍的技术进一步优化,例如对规则集进行后剪枝。

2.逆归结

在逻辑学中,“演绎”(deduction)与“归纳”(induction)是人类认识世界的两种基本方式。大致来说,演绎是从一般性规律出发来探讨具体事物,而归纳则是从个别事物出发概括出一般性规律。一般数学定理证明是演绎实践的代表,而机器学习显然属于归纳的范畴。1965年,逻辑学家提出,一阶谓词演算中的演绎推理能用一条十分简洁的规则描述,这就是数理逻辑中著名的 归纳原理(resolution principle)。二十多年后,计算机学家针对归纳推理提出了 “逆归结”(inverse resolution),这对归纳逻辑程序涉及的发展起到了重要作用。
基于归纳原理,可将貌似复杂的逻辑规则与背景知识联系起来化繁为简;而基于逆归结,可基于背景知识来发明新的概念和关系。下面先以较为简单的命题演算为例,来看看归结、逆归结是怎么回事。
假定两个逻辑表达式 C 1 C_1 C1 C 2 C_2 C2成立,且分别包含了互补项 L 1 L_1 L1 L 2 L_2 L2;不是一般性,令 L = L 1 = ¬ L 2 , C 1 = A ∨ L , C 2 = B ∨ ¬ L L=L_1=\lnot L_2,C_1=A\vee L,C_2=B\vee \lnot L L=L1=¬L2,C1=AL,C2=B¬L。归结原理告诉我们,通过演绎推理能消去L而得到“归结项” C = A ∨ B C=A\vee B C=AB。若定义析合范式的删除操作
( A ∨ B ) − { B } = A (A\vee B) -\{B\} = A (AB){B}=A
则归结过程可表述为
C = ( C 1 − { L } ) ∨ ( C 2 − { ¬ L } ) C = (C_1-\{L\})\vee(C_2-\{\lnot L\}) C=(C1{L})(C2{¬L})
简记为
C = C 1 ⋅ C 2 C = C_1\cdot C_2 C=C1C2
在这里插入图片描述与上面的过程相反,逆归结研究的是在已知 C C C和某个 C i C_i Ci的情况下如何得到 C j ( i ≠ j ) C_j(i\ne j) Cj(i=j)。假定已知 C C C C 1 C_1 C1 C 2 C_2 C2,则该过程可表述为
C 2 = ( C − ( C 1 − { L } ) ) ∨ { ¬ L } C_2 = (C-(C_1-\{L\}))\vee \{\lnot L\} C2=(C(C1{L})){¬L}
在逻辑推理实践中如何实现逆归结呢?定义了四种完备的逆归结操作。若以规则形式 p ← q p\leftarrow q pq等价地表达 p ∨ ¬ q p\vee \lnot q p¬q,并假定用小写字母表示逻辑文字、大写字母表示合取式组成的逻辑子句,则这四种操作是
吸 收 ( a b s o r p t i o n ) : p ← A ∧ B q ← A p ← q ∧ B q ← A 辨 识 ( i d e n t i f i c a t i o n ) : p ← A ∧ B p ← A ∧ q q ← B p ← A ∧ q 内 构 ( i n t r a − c o n s t r u c t i o n ) : p ← A ∧ B p ← A ∧ C q ← B p ← A ∧ q q ← C 互 构 ( i n t e r − c o n s t r u c t i o n ) : p ← A ∧ B q ← A ∧ C p ← r ∧ B r ← A q ← r ∧ C \begin{aligned} &吸收(absorption):\frac{p\leftarrow A\wedge B \quad q\leftarrow A}{p\leftarrow q\wedge B \quad q\leftarrow A}\\ &辨识(identification):\frac{p\leftarrow A\wedge B \quad p\leftarrow A\wedge q}{q\leftarrow B \quad p\leftarrow A\wedge q}\\ &内构(intra-construction):\frac{p\leftarrow A\wedge B \quad p\leftarrow A\wedge C}{q\leftarrow B \quad p\leftarrow A\wedge q\quad q\leftarrow C}\\ &互构(inter-construction):\frac{p\leftarrow A\wedge B \quad q\leftarrow A\wedge C}{p\leftarrow r\wedge B \quad r\leftarrow A\quad q\leftarrow r\wedge C}\\ \end{aligned} (absorption):pqBqApABqA(identification):qBpAqpABpAq(intraconstruction):qBpAqqCpABpAC(interconstruction):prBrAqrCpABqAC
这里用 X Y \frac{X}{Y} YX表示X蕴含Y,在数理逻辑里写作 X ⊢ Y X\vdash Y XY。在上述规则中,X的子句或是Y的归结项,或是Y的某个子句的等价项;而Y中出现的新逻辑文字则可看作通过归纳学到的新命题。
归纳、逆归结都能容易地拓展为一阶逻辑形式;与命题逻辑的主要不同之处是,一阶逻辑的归结、逆归结通常需进行合一置换操作。
“置换”(substitution) 是用某些项来替换逻辑表达式中的变量。例如用 θ = { 1 / X , 2 / Y } \theta = \{1/X,2/Y\} θ={1/X,2/Y}置换“ C = 色 泽 更 深 ( X , Y ) ∧ 敲 声 更 沉 ( X , Y ) C=色泽更深(X,Y)\wedge 敲声更沉(X,Y) C=(X,Y)(X,Y)”可得到“ C ′ = C θ = 色 泽 更 深 ( 1 , 2 ) ∧ 敲 声 更 沉 ( 1 , 2 ) C'=C\theta = 色泽更深(1,2)\wedge敲声更沉(1,2) C=Cθ=(1,2)(1,2)”,其中 { X , Y } \{X,Y\} {X,Y}称为 θ \theta θ的作用域(domain)。与代数中的置换类似,一阶逻辑中也有“复合置换”和“逆置换”。例如先用 θ = { Y / X } \theta = \{Y/X\} θ={Y/X}将X替换为Y,再用 λ = { 1 / Y } \lambda=\{1/Y\} λ={1/Y}将Y替换为1,这样的操作记为 θ ∘ λ \theta\circ\lambda θλ θ \theta θ的逆置换记为 θ − 1 = { X / Y } \theta^{-1} = \{X/Y\} θ1={X/Y}
“合一”(unification) 是用一种变量置换令两个或多个逻辑表达式相等。例如对“ A = 色 泽 更 深 ( 1 , X ) A=色泽更深(1,X) A=(1,X)”和“ B = 色 泽 更 深 ( Y , 2 ) B=色泽更深(Y,2) B=(Y,2)”,可用 θ = { 2 / X , 1 / Y } \theta=\{2/X,1/Y\} θ={2/X,1/Y}使“ A θ = B θ = 色 泽 更 深 ( 1 , 2 ) A\theta=B\theta=色泽更深(1,2) Aθ=Bθ=(1,2)”;此时称A和B是 “可合一”(unifiable),称 θ \theta θ为A和B的 “合一化子”(unifier)。若 δ \delta δ是一组一阶逻辑表达式W的合一化子,且对W的任意合一化子 θ \theta θ均存在相应的置换 λ \lambda λ使 θ = δ ∘ λ \theta=\delta\circ\lambda θ=δλ,则称 δ \delta δ为W的“最一般合一置换”或“最一般合一化子”(most general unifier,简记为MGU),这是归纳逻辑程序中最重要的概念之一。例如“色泽更深(1,Y)”和“色泽更深(X,Y)”能被 θ 1 = { 1 / X } , θ 2 = { 1 / X , 2 / Y } , θ 3 = { 1 / Z , Z / X } \theta_1=\{1/X\},\theta_2=\{1/X,2/Y\},\theta_3=\{1/Z,Z/X\} θ1={1/X},θ2={1/X,2/Y},θ3={1/Z,Z/X}合一,但仅有 θ 1 \theta_1 θ1是它们的MGU。
一阶逻辑进行归结时,需利用合一操作来搜索互补项 L 1 L_1 L1 L 2 L_2 L2。对两个一阶逻辑表达式 C 1 = A ∨ L 1 C_1=A\vee L_1 C1=AL1 C 2 = B ∨ L 2 C_2 = B\vee L_2 C2=BL2,若存在合一化子 θ \theta θ使 L 1 θ = ¬ L 2 θ L_1\theta = \lnot L_2\theta L1θ=¬L2θ,则可对其进行归结:
C = ( C 1 − { L 1 } ) θ ∨ ( C 2 − { L 2 } ) θ C=(C_1-\{L_1\})\theta\vee(C_2-\{L_2\})\theta C=(C1{L1})θ(C2{L2})θ
类似的,可利用合一化进行推展得到一阶逻辑的逆归结。定义 C 1 = C / C 2 C_1=C/C_2 C1=C/C2 C 2 = C / C 1 C_2=C/C_1 C2=C/C1“归结商”(resolution quotient),于是,逆归结的目标就是在已知 C C C C 1 C_1 C1时求出归结商 C 2 C_2 C2。对某个 L 1 ∈ C 1 L_1\in C_1 L1C1,假定 ϕ 1 \phi_1 ϕ1是一个置换,它能使
( C 1 − { L 1 } ) ϕ ⊢ C , (C_1-\{L_1\})\phi \vdash C, (C1{L1})ϕC,
这里 ϕ 1 \phi_1 ϕ1的作用域是 C 1 C_1 C1中所有变量,记为 vars ⁡ ( C 1 ) \operatorname{vars}(C_1) vars(C1),其作用是使 C 1 − { L 1 } C_1-\{L_1\} C1{L1}与C中的对应文字能合一。令 ϕ 2 \phi_2 ϕ2为作用域是 vars ⁡ ( L 1 ) − vars ⁡ ( C 1 − { L 1 } ) \operatorname{vars}(L_1)-\operatorname{vars}(C_1-\{L_1\}) vars(L1)vars(C1{L1})的置换, L 2 L_2 L2为归结商 C 2 C_2 C2中将被消去的文字, θ 2 \theta_2 θ2是以 vars ⁡ ( L 2 ) \operatorname{vars}(L_2) vars(L2)为作用域的置换, ϕ 2 \phi_2 ϕ2 ϕ 1 \phi_1 ϕ1共同作用域 L 1 L_1 L1,使得 ¬ L 1 ϕ 1 ∘ ϕ 2 = L 2 θ 2 \lnot L_1 \phi_1\circ\phi_2 = L_2\theta_2 ¬L1ϕ1ϕ2=L2θ2,于是 ϕ 1 ∘ ϕ 2 ∘ θ \phi_1\circ\phi_2\circ\theta ϕ1ϕ2θ ¬ L 1 \lnot L_1 ¬L1 L 2 L_2 L2的MGU。将前两步的复合置换 ϕ 1 ∘ ϕ 2 \phi_1\circ\phi_2 ϕ1ϕ2记为 θ 1 \theta_1 θ1,用 θ 2 − 1 \theta_2^{-1} θ21表示 θ 2 \theta_2 θ2的逆置换,则有 ( ¬ L 1 θ 1 ) θ 2 − 1 = L 2 (\lnot L_1\theta_1)\theta_2^{-1}=L_2 (¬L1θ1)θ21=L2。于是,类似的,一阶逆归结是
C 2 = ( C − ( C 1 − { L 1 } ) θ 1 ∨ { ¬ L 1 θ 1 } ) θ 2 − 1 C_2 = (C-(C_1-\{L_1\})\theta_1\vee \{\lnot L_1 \theta_1\})\theta_2^{-1} C2=(C(C1{L1})θ1{¬L1θ1})θ21
在一阶情形下 L 1 、 L 2 、 θ 1 L_1、L_2、\theta_1 L1L2θ1 θ 2 \theta_2 θ2的选择通常都不唯一,这时需通过一些其他判断标准来取舍,例如覆盖率、准确率、信息熵等。
以西瓜数据集5.0为例,假定通过一些步骤已得到规则
C 1 = 更 好 ( 1 , X ) ← 根 蒂 更 蜷 ( 1 , X ) ∧ 纹 理 更 清 ( 1 , X ) ; C 2 = 更 好 ( 1 , Y ) ← 根 蒂 更 蜷 ( 1 , Y ) ∧ 敲 声 更 沉 ( 1 , Y ) ; C_1 = 更好(1,X)\leftarrow 根蒂更蜷(1,X)\wedge纹理更清(1,X);\\ C_2 = 更好(1,Y)\leftarrow 根蒂更蜷(1,Y)\wedge敲声更沉(1,Y); C1=(1,X)(1,X)(1,X);C2=(1,Y)(1,Y)(1,Y);
容易看出它们是“ p ← A ∧ B p\leftarrow A\wedge B pAB”和“ p ← A ∧ C p\leftarrow A\wedge C pAC”的形式,于是可使用内构操作来进行逆归结。由于 C 1 , C 2 C_1,C_2 C1,C2中的谓词都是二元的,为了保持新规则描述信息的完整性,创造一个新的二元谓词 q ( M , N ) q(M,N) q(M,N),并得到
C ′ = 更 好 ( 1 , Z ) ← 根 蒂 更 蜷 ( 1 , Z ) ∧ q ( M , N ) C' = 更好(1,Z)\leftarrow 根蒂更蜷(1,Z)\wedge q(M,N) C=(1,Z)(1,Z)q(M,N)
内构公式中横线下方的另两项分别是 C 1 / C ′ C_1/C' C1/C C 2 / C ′ C_2/C' C2/C的归结商。对 C 1 / C ′ C_1/C' C1/C,容易发现 C ′ C' C中通过归结消去 L 1 L_1 L1的选择可以有“ ¬ 根 蒂 更 蜷 ( 1 , Z ) \lnot 根蒂更蜷(1,Z) ¬(1,Z)”和“ ¬ q ( M , N ) \lnot q(M,N) ¬q(M,N)”。q是新发明的谓词,迟早需学习一条新规则“ q ( M , N ) ← ? q(M,N)\leftarrow ? q(M,N)?”来定义它;根据奥卡姆剃刀原则,同等描述能力下学得的规则越少越好,因此我们将“ ¬ q ( M , N ) \lnot q(M,N) ¬q(M,N)”作为 L 1 L_1 L1。存在解: L 2 = q ( 1 , S ) , ϕ 1 = { X , Z } , ϕ 2 = { 1 / M , X / N } , θ 2 = { X / S } L_2=q(1,S),\phi_1=\{X,Z\},\phi_2=\{1/M,X/N\},\theta_2=\{X/S\} L2=q(1,S),ϕ1={X,Z},ϕ2={1/M,X/N},θ2={X/S}。通过简单的演算即可求出归结商“ q ( 1 , S ) ← 纹 理 更 清 ( 1 , S ) q(1,S)\leftarrow 纹理更清(1,S) q(1,S)(1,S)”。类似地可求出 C 2 / C ′ C_2/C' C2/C的归结商 q ( 1 , T ) ← 敲 声 更 沉 ( 1 , T ) q(1,T)\leftarrow 敲声更沉(1,T) q(1,T)(1,T)
逆归结的一大特点是能自动发明新谓词,这些新谓词可能对于样例属性和背景知识中不存在的新知识,对知识发现与精华有重要意义。但自动发明新谓词究竟对应于什么语义,例如“q”意味着“更新鲜”?“更甜”?这只是通过使用者对任务领域的进一步理解才能确定。
上面的例子中只介绍了如何基于两条规则进行逆归结。在现实任务中,ILP系统通常先自底向上生成一组规则,然后再结合最小一般泛化与逆归结做进一步学习1。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值