药方的量化方法笔记(学习与尝试):第二回 第四次 药方的拆解 量化方法的形式的发展 对药的量化分析

药方拆解

皮炎湿疹荨麻疹相关药方

详细内容见 第二回 第三次,这里只保留文章的标题目录,因为文章中有太多 Latex 公式,所以编辑起来太卡了,只能分几次更新。)

全虫方 · 赵炳南

全虫方在 第二回 第二次 已经写给出,但是后面还要以它为例,给出上次提及的的方法二,所以为了阅读方便,这里重新再列出来一遍。

方中刺蒺藜 15-30g,取平均值22.5g;炒槐花 15-30g,取平均值 22.5g;威灵仙 12-30g,取平均值 21g。

药名 用量 药性 药味 归经 功效
全蝎 6g 息风_止痉_通络_止痛_攻毒_散结
皂角刺 12g 肝,胃 消肿_托毒_排脓_杀虫
猪牙皂 6g 辛,咸 肺,大肠 祛痰_开窍_散结_消肿
蒺藜 22.5g 微温 苦,辛 平肝_潜阳_疏肝_解郁_活血_祛风_明目_止痒
炒槐花 22.5g 微寒 肝,大肠 凉血_止血_清肝_泻火
威灵仙 21g 辛,咸 膀胱 祛风_除湿_通络_止痛_消鱼鲠
苦参 6g 心,肝,胃,大肠,膀胱 清热_燥湿_杀虫_利尿
白鲜皮 15g 胃,脾,膀胱 清热_燥湿_祛风_解毒
黄柏 15g 肾,大肠,膀胱 清热_燥湿_泻火_解毒_除蒸_疗疮

量化方法形式的发展——方药用量的斟酌

注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!! \color{red}\small\text{注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!!} 注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!!
注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!! \color{red}\small\text{注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!!} 注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!!
注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!! \color{red}\small\text{注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!!} 注意,这只是一个试探,并没有临床的或者现实的经验,仅仅引起一个思考或者启发!!!

详细内容见上一次,这里只列出目录。

方法一:转化为熵函数在有约束条件下的最优化问题

详细内容见上一次,这里只列出目录。

方法二:拆分数的方法与方剂药量配比

拆分数的方法如何应用于方剂药物配比问题上呢?对于含有 Q Q Q 味中药的药方,考虑如下函数
y = 1 ( 1 − ζ 1 ) ( 1 − ζ 2 ) … ( 1 − ζ Q ) = ∏ m = 1 Q ( 1 − ζ m ) − 1 \displaystyle \begin{array}{lllll} y = \displaystyle \frac{1}{ \left(1-\zeta_{1}\right) \left(1-\zeta_{2}\right) \dots \left(1-\zeta_{Q}\right) } = \displaystyle \prod_{m=1}^{Q} \left(1-\zeta_{m}\right)^{-1} \end{array} y=(1ζ1)(1ζ2)(1ζQ)1=m=1Q(1ζm)1
如果展开 y y y 为级数的形式,就可以得到
y = 1 + ζ 1 + ⋯ + ζ j 1 ⏟ 1 ≤ j 1 ≤ Q + ⋯ + ζ Q ⏟ 所有的 1 次项 + ζ 1 ζ 1 + ⋯ + ζ j 1 ζ j 2 ⏟ 1 ≤ j 1 , j 2 ≤ Q + ⋯ + ζ Q ζ Q ⏟ 所有的 2 次项 + … + ζ 1 … ζ 1 ⏟ 一共 k 个 ζ 1 + ⋯ + ζ j 1 … ζ j k ⏟ 1 ≤ j 1 , … , j k ≤ Q + ⋯ + ζ Q … ζ Q ⏟ 一共 k 个 ζ Q ⏟ 所有的 k 次项 + … \displaystyle \begin{array}{llllll} y & = & 1 + \underbrace{\zeta_{1} + \dots + \underbrace{\zeta_{j_1}}_{1 \le j_1 \le Q} + \dots + \zeta_{Q}}_{\text{所有的 1 次项}} \\ \\ & + & \underbrace{\zeta_{1} \zeta_{1} + \dots + \underbrace{\zeta_{j_1} \zeta_{j_2}}_{1\le j_1,j_2 \le Q} + \dots + \zeta_{Q} \zeta_{Q}}_{\text{所有的 2 次项}} \\ \\ & + & \dots \\ \\ & + & \underbrace{ \underbrace{ \zeta_{1} \dots \zeta_{1} }_{ 一共 k 个 \zeta_{1} } + \dots + \underbrace{ \zeta_{j_1} \dots \zeta_{j_k} }_{ 1\le j_1,\dots,j_k \le Q} + \dots + \underbrace{ \zeta_{Q} \dots \zeta_{Q} }_{ 一共 k 个 \zeta_{Q} }}_{所有的 k 次项} \\ \\ & + & \dots \\ \end{array} y=++++1+所有的 1 次项 ζ1++1j1Q ζj1++ζQ所有的 2 次项 ζ1ζ1++1j1,j2Q ζj1ζj2++ζQζQ所有的k次项 一共kζ1 ζ1ζ1++1j1,,jkQ ζj1ζjk++一共kζQ ζQζQ
其中,所有的 1 1 1 次项表示只用 1 1 1 份药,这份药来自 ζ j 1 \zeta_{j_1} ζj1;所有的 2 2 2 次项表示,用 2 2 2 份药,一份来自 ζ j 1 \zeta_{j_1} ζj1,一份来自 ζ j 2 \zeta_{j_2} ζj2;所有的 k k k 次项表示,用 k k k 份药,一份来自 ζ j 1 , … , ζ j k \zeta_{j_1}, \dots, \zeta_{j_k} ζj1,,ζjk 各一份,以此类推。从公式中一看到, ζ j p \zeta_{j_p} ζjp ζ j q \zeta_{j_q} ζjq 可以是重复的,或者换句话说, ζ j \zeta_{j} ζj 的幂次就代表了它在药方中的份数,即配比。

如果这个时候将药物的功效写做药方的功效,进行普通的乘法,就可以得到对应药剂配比下功效的配比。具体来讲就是,对于第 m m m 味中药
ζ m → ∏ e ∈ 第 m 味药的功效 ( ϵ e ) P m e \displaystyle \begin{array}{llll} \zeta_{m} \rightarrow \displaystyle \prod_{e \in \text{第 m 味药的功效}} \left(\epsilon_{e}\right)^{P_m^e} \end{array} ζme m 味药的功效(ϵe)Pme
其中, ϵ e \epsilon_{e} ϵe 表示药方中的第 e e e 个功效, P m e P_m^e Pme 为第二回第二次中的功效矩阵。有了上面的准备,只要将对应的药物进行普通乘法,就可以得到对应的功效配比。例如,两份全蝎和一份威灵仙,
ζ 全蝎 2 × ζ 威灵仙 = ( ϵ 息风 ) 2 6 ( ϵ 止痉 ) 2 6 ( ϵ 通络 ) 2 6 ( ϵ 止痛 ) 2 6 ( ϵ 攻毒 ) 2 6 ( ϵ 散结 ) 2 6 s p c × ( ϵ 祛风 ) 1 5 ( ϵ 除湿 ) 1 5 ( ϵ 通络 ) 1 5 ( ϵ 止痛 ) 1 5 ( ϵ 消鱼鲠 ) 1 5 = ( ϵ 息风 ) 1 3 ( ϵ 止痉 ) 1 3 ( ϵ 通络 ) 8 15 ( ϵ 止痛 ) 8 15 ( ϵ 攻毒 ) 1 3 ( ϵ 散结 ) 1 3 ( ϵ 祛风 ) 1 5 ( ϵ 除湿 ) 1 5 ( ϵ 消鱼鲠 ) 1 5 \begin{array}{llll} \displaystyle \zeta_{\displaystyle \tiny 全蝎}^{2} \times \zeta_{\displaystyle \tiny 威灵仙} & = & \left(\displaystyle \epsilon_{\tiny \text{息风}}\right)^{\tiny \frac{2}{6}} \left(\displaystyle \epsilon_{\tiny \text{止痉}}\right)^{\tiny \frac{2}{6}} \left(\displaystyle \epsilon_{\tiny \text{通络}}\right)^{\tiny \frac{2}{6}} \left(\displaystyle \epsilon_{\tiny \text{止痛}}\right)^{\tiny \frac{2}{6}} \left(\displaystyle \epsilon_{\tiny \text{攻毒}}\right)^{\tiny \frac{2}{6}} \left(\displaystyle \epsilon_{\tiny \text{散结}}\right)^{\tiny \frac{2}{6}} \\ \\ & & \phantom{spc} \times \left(\displaystyle \epsilon_{\tiny \text{祛风}}\right)^{\tiny \frac{1}{5}} \left(\displaystyle \epsilon_{\tiny \text{除湿}}\right)^{\tiny \frac{1}{5}} \left(\displaystyle \epsilon_{\tiny \text{通络}}\right)^{\tiny \frac{1}{5}} \left(\displaystyle \epsilon_{\tiny \text{止痛}}\right)^{\tiny \frac{1}{5}} \left(\displaystyle \epsilon_{\tiny \text{消鱼鲠}}\right)^{\tiny \frac{1}{5}} \\ \\ & = & \left(\displaystyle \epsilon_{\tiny \text{息风}}\right)^{\tiny \frac{1}{3}} \left(\displaystyle \epsilon_{\tiny \text{止痉}}\right)^{\tiny \frac{1}{3}} \left(\displaystyle \epsilon_{\tiny \text{通络}}\right)^{\tiny \frac{8}{15}} \left(\displaystyle \epsilon_{\tiny \text{止痛}}\right)^{\tiny \frac{8}{15}} \left(\displaystyle \epsilon_{\tiny \text{攻毒}}\right)^{\tiny \frac{1}{3}} \left(\displaystyle \epsilon_{\tiny \text{散结}}\right)^{\tiny \frac{1}{3}} \left(\displaystyle \epsilon_{\tiny \text{祛风}}\right)^{\tiny \frac{1}{5}} \left(\displaystyle \epsilon_{\tiny \text{除湿}}\right)^{\tiny \frac{1}{5}} \left(\displaystyle \epsilon_{\tiny \text{消鱼鲠}}\right)^{\tiny \frac{1}{5}} \\ \end{array} ζ全蝎2×ζ威灵仙==(ϵ息风)62(ϵ止痉)62(ϵ通络)62(ϵ止痛)62(ϵ攻毒)62(ϵ散结)62spc×(ϵ祛风)51(ϵ除湿)51(ϵ通络)51(ϵ止痛)51(ϵ消鱼鲠)51(ϵ息风)31(ϵ止痉)31(ϵ通络)158(ϵ止痛)158(ϵ攻毒)31(ϵ散结)31(ϵ祛风)51(ϵ除湿)51(ϵ消鱼鲠)51
它的意思是,这个组合息风的占比为 1 / 3 1/3 1/3, 止痉的占比为 1 / 3 1/3 1/3,通络的占比结合了二者之和,为 8 / 15 8/15 8/15,以此类推。

函数 y = ∏ m = 1 Q ( 1 − ζ m ) − 1 y=\prod_{m=1}^{Q} \left(1-\zeta_{m}\right)^{-1} y=m=1Q(1ζm)1 的幂级数展开涵盖了所有可能的组合。未知数 ζ \zeta ζ 的总幂次表示用药的总份数。一次幂项表示只选取1份药的功效,也只能选择一种药;二次幂项表示只选取2份药的功效,这两份药可能是1种药,也可能是2种药。每一个未知数 ζ m \zeta_{m} ζm 自己的幂次,则表示自己在总份数中所占的份数。随着幂次的升高,用药种类和药量搭配的组合会迅速变大,不过随着份数越来越细,所以各味药剂的配比也会越来越细致。

再换一个角度来看 y y y。先考虑其中的因子 1 / ( 1 − ζ m ) 1 / \left( 1- \zeta_{m} \right) 1/(1ζm) 的级数
1 1 − ζ m = 1 + ζ m + ζ m 2 + ζ m 3 + ⋯ + ζ m k + … \begin{array}{lllll} \displaystyle \frac{1}{1- \zeta_{m}} = 1 + \zeta_{m} + \zeta_{m}^{2} + \zeta_{m}^{3} + \dots + \zeta_{m}^{k} + \dots \\ \end{array} 1ζm1=1+ζm+ζm2+ζm3++ζmk+
它可以看成是不用第 m m m 味药,使用 1 1 1 份第 m m m 味药,使用 2 2 2 份第 m m m 味药,使用 3 3 3 份第 m m m 味药, … \dots ,使用 k k k 份第 m m m 味药,以此类推。所以,函数 y y y 的级数为
y = 1 1 − ζ 1 … 1 1 − ζ Q = ( 1 + ζ 1 + ζ 1 2 + ζ 1 3 + ⋯ + ζ 1 k + …   ) … ( 1 + ζ Q + ζ Q 2 + ζ Q 3 + ⋯ + ζ Q k + …   ) = 1 + ⋯ + ( ζ 1 j 1 … ζ Q j Q ) + … \begin{array}{llllll} y & = & \displaystyle \frac{1}{1-\zeta_{1}} \dots \frac{1}{1-\zeta_{Q}} \\ \\ & = & \left( 1 + \zeta_{1} + \zeta_{1}^{2} + \zeta_{1}^{3} + \dots + \zeta_{1}^{k} + \dots \right) \dots \left( 1 + \zeta_{Q} + \zeta_{Q}^{2} + \zeta_{Q}^{3} + \dots + \zeta_{Q}^{k} + \dots \right) \\ \\ & = & 1 + \dots + \left( \zeta_{1}^{j_1} \dots \zeta_{Q}^{j_Q} \right) + \dots \end{array} y===1ζ111ζQ1(1+ζ1+ζ12+ζ13++ζ1k+)(1+ζQ+ζQ2+ζQ3++ζQk+)1++(ζ1j1ζQjQ)+
由此可以看出, y y y 的每一项都表示使用第 1 1 1 味药 j 1 j_1 j1 份, … \dots ,第 Q Q Q 味药 j Q j_Q jQ 份。 y y y 就是在限定的 Q Q Q 味药中,所有可能的配比的总和。

这一段的代码本来打算忠实于前面的公式编写,可是 SymPy 包可以实现符号运算,可是它展开级数的表现太慢了。不过,前面说过,实际上就是给定的总份数下,找到药方的药物占各种可能份数的全组合。所以,这里的思路是,在给定总份数下,给出所有可能的拆分数。然后,根据拆分数的个数,选出药的味数。例如,全虫方中一共9味药,如果药方总质量平均分配成20份,其中的一个拆分数是 12 + 3 + 2 + 1 + 1 + 1 = 20 12 + 3 + 2 + 1 + 1 + 1= 20 12+3+2+1+1+1=20,那么这组拆分数就是代表从原方的 9 9 9 味药中选取 6 6 6 味,每一味的占比分别是 12 , 3 , 2 , 1 , 1 , 1 12, 3, 2, 1, 1, 1 12,3,2,1,1,1;如果某组拆分数为 7 + 3 + 2 + 2 + 2 + 1 + 1 + 1 + 1 = 20 7 + 3 + 2 + 2 + 2 + 1 + 1 + 1 + 1 = 20 7+3+2+2+2+1+1+1+1=20 就表示原方的 9 9 9 味药同时取用,每味药的占比分别为 7 , 3 , 2 , 2 , 2 , 1 , 1 , 1 , 1 7, 3, 2, 2, 2, 1, 1, 1, 1 7,3,2,2,2,1,1,1,1;如果某组拆分数为 5 + 3 + 3 + 2 + 2 + 1 + 1 + 1 + 1 + 1 = 20 5 + 3 + 3 + 2 + 2 + 1 + 1 + 1 + 1 + 1= 20 5+3+3+2+2+1+1+1+1+1=20,这组拆分数是 10 10 10 个数组成的,而原方中只有 9 9 9 味药,所以这组拆分数不是可能的拆分,不被允许。同时,考虑到药方中份数表示占比,所以会除以最大公约数。例如, 20 20 20 拆分为 10 , 4 , 6 10, 4, 6 10,4,6 时,会被除以最大公约数 2 2 2,得到 5 , 2 , 3 5, 2, 3 5,2,3。最后,给出从药方中选出的药的全排列,以字典的方式,搭配对应的那组除以过最大公约数拆分数。之所以,以字典的方式,是因为 python 中关键字和数值相同的字典,被看做相同的字典。例如,{“黄芪”: 2, “白术”: 1, “防风”: 1} 与 {“黄芪”: 2, “防风”: 1, “白术”: 1},虽然防风和白术的顺序调整了,但是它们是相同的字典。

# 函数 __partitions__ 为引用别人的代码
# Chris Smith, Tim Peters, https://code.activestate.com/recipes/218332-generator-for-integer-partitions/
# 给出所有整数 n 的拆分数,其中每个拆分数的不大于 k,也可以没有这个要求。
def __partitions__(n, k=None):
    """Generate all partitions of integer n (>= 0) using integers no
    greater than k (default, None, allows the partition to contain n).
    Each partition is represented as a multiset, i.e. a dictionary
    mapping an integer to the number of copies of that integer in
    the partition.  For example, the partitions of 4 are {4: 1},
    {3: 1, 1: 1}, {2: 2}, {2: 1, 1: 2}, and {1: 4} corresponding to
    [4], [1, 3], [2, 2], [1, 1, 2] and [1, 1, 1, 1], respectively.
    In general, sum(k * v for k, v in a_partition.iteritems()) == n, and
    len(a_partition) is never larger than about sqrt(2*n).
    Note that the _same_ dictionary object is returned each time.
    This is for speed:  generating each partition goes quickly,
    taking constant time independent of n. If you want to build a list
    of returned values then use .copy() to get copies of the returned
    values:
    >>> p_all = []
    >>> for p in partitions(6, 2):
    ...         p_all.append(p.copy())
    ...
    >>> print p_all
    [{2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}]
    Reference
    ---------
    Modified from Tim Peter's posting to accomodate a k value:
    http://code.activestate.com/recipes/218332/
    """
    if n < 0:
        raise ValueError("n must be >= 0")
    if n == 0:
        yield {}
        return
    if k is None or k > n:
        k = n
    q, r = divmod(n, k)
    ms = {k : q}
    keys = [k]
    if r:
        ms[r] = 1
        keys.append(r)
    yield ms
    while keys != [1]:
        # Reuse any 1's.
        if keys[-1] == 1:
            del keys[-1]
            reuse = ms.pop(1)
        else:
            reuse = 0
        # Let i be the smallest key larger than 1.  Reuse one
        # instance of i.
        i = keys[-1]
        newcount = ms[i] = ms[i] - 1
        reuse += i
        if newcount == 0:
            del keys[-1], ms[i]
        # Break the remainder into pieces of size i-1.
        i -= 1
        q, r = divmod(reuse, i)
        ms[i] = q
        keys.append(i)
        if r:
            ms[r] = 1
            keys.append(r)
        yield ms

# 根据上面的函数,得到一个整数拆分后的 list
def partitions(n_, k_=None) -> list:
    p_all_ = list()
    for p_ in __partitions__(n_, k_):
        p_all_.append(p_.copy())
    return p_all_

# 求出一组数的最大公约数
import sympy as sym
def gcd_of_a_list_or_tuple(vars_):
    if len(vars_) <= 1:
        return 1
    else:
        code_ = "sym.igcd(vars_[0]"
        for i_ in range(1, len(vars_)):
            code_= code_ + ', vars_[' + str(i_) + ']'
        code_ = code_ + ')'
        return eval(code_)

# 给出药方 medicines 总共平均分成 shares 份,所有可能的分法。
from itertools import permutations
def all_permitted_proportions(medicines, shares) -> list:

	# 得到 shares 份的所有拆分数
	partition = partitions(shares) 
    partition = [list(partition[p].items()) for p in range(0, len(partition))]
    
	# 选出拆分数的个数不多余药方中药材味数的情况
    ks = np.array([sum([partition[p][i][1] for i in range(0, len(partition[p]))]) for p in range(0, len(partition))])
    positions = np.where(ks <= len(medicines))
    partition = list(np.array(partition, dtype=list)[positions])
    ks = list(ks[positions])
    ks = [int(ks[i]) for i in range(0, len(ks))]
    
	# 按照选中的药材味数排序
    partition.sort(key=lambda x: sum([x[i][1] for i in range(0, len(x))]))
    ks.sort()
	
    all_proportions = list() # 用于记录所有可能的配比
    for p in range(0, len(partition)):
        proportion = list()
        for i in range(0, len(partition[p])):
            proportion.extend([partition[p][i][0] for j in range(0, partition[p][i][1])])
        # 求出最大公约数,并除之
        gcd = gcd_of_a_list_or_tuple(proportion)
        proportion = [int(proportion[i] / gcd) for i in range(0, len(proportion))]
        proportion = tuple(proportion)
		# 求出从药方 medicines 中选出 ks[p] 味药的全排列
        pmtt = list(permutations(medicines, ks[p]))
        for i in range(0, len(pmtt)):
            proportion_dict = dict() # 
            for j in range(0, len(pmtt[i])):
                proportion_dict[pmtt[i][j]] = proportion[j]
            complement = list(set(medicines).symmetric_difference(pmtt[i]))
            for c in range(0, len(complement)):
                proportion_dict[complement[c]] = 0
            if proportion_dict not in pei_wu:
                all_proportions.append(proportion_dict)

    # 按照药材名排序
    for p in range(0, len(all_proportions)):
        all_proportions[p] = list(all_proportions[p].items())
        all_proportions[p].sort(key= lambda x: x[0])
    
    return all_proportions

# end

在运行代码之前,首先对药方所有可能的情况的数量级做一个大致估计。影响排列情况多少的,最主要的是两个因素。一个是药方药材种类的多少,一个是拆分数的个数。药方总量分的份数越多,拆分数的情况就越多。药方药材味数越多,排列就越多。尽管,在某些拆分下,某些药材占有的份数相同,所以有些排列会重复。如果忽略这些重复,仅粗略地估计一下所有可能的情况的多少,可以用下面的方法进行估计。根据国家中医药管理局2007年3月12日印发的《医院中药饮片管理规范》第三十一条规定,中药饮片调配每剂重量误差应当在±5%以内。换句话说,一剂药重量误差 ±5% 可以认为效果一样,这样来看,一剂药重量最大相差为 10%。如果将药的总量分成 20 份,这样每份占比就是 5%,拆分数变动一次至少一味药少 5%,另一味药多 5%,这跟总量误差10%相比,可以看做是药方上的一个明显的调整。所以,在份20份的情况下,在忽略一些重复的排列的情况下,可能出现的情况随着药方药材味数的增长情况,如下表所示。

方中药材的味数 可能的配比情况(总量 20 等分,粗略估计) 读数 对应书籍
1 1 一般中药材的手册、词典、伤寒杂病论(白云阁藏本,16 首)
2 22 张锡纯对药、施今墨对药、伤寒杂病论(白云阁藏本,39 首)
3 261 张锡纯对药、施今墨对药、伤寒杂病论(白云阁藏本,45 首)
4 2452 施今墨对药、伤寒杂病论(白云阁藏本,79 首)
5 19945 1 万 9 千 伤寒杂病论(白云阁藏本,56 首)
6 152586 15 万 伤寒杂病论(白云阁藏本,37 首)
7 1139677 113 万 伤寒杂病论(白云阁藏本,33 首)
8 8626696 862 万 伤寒杂病论(白云阁藏本,9 首)
9 66799377 6679 万 伤寒杂病论(白云阁藏本,8 首)
10 541461790 5 亿 4146 万 伤寒杂病论(白云阁藏本,4 首)
11 4588976821 45 亿 8897 万
12 41071200732 410 亿 7120 万 伤寒杂病论(白云阁藏本,2 首)
13 385871967481 3858 亿 7196 万
14 3863390901202 3,8633 亿 9090 万
15 40352035350285 40,3520 亿 3535 万

从表格中可以看到,药方可能的配比情况,随着方中药材味数的增加而极具膨胀。这意味着,多味数大药方的不确定性也是极具膨胀的。所以,谨慎地使用大药方是确保药效的重要手段。从伤寒杂病论的药方味数统计来看,超过 7 味药的药方急剧减少。伤寒杂病论中的药方,经历代医家千年反复验证大多屡试不爽,这也在一定程度上说明,药方味数不宜过多。

这次是代码太多了,网页编辑卡得要命,见下次。

方法一与方法二各自的特点与关系

这次是代码太多了,网页编辑卡得要命,见下次。

方法一与方法二的局限性

  1. 计算量的局限性
  2. 主要功能也存在区别

你可能感兴趣的:(中药的量化研究,学习,健康医疗)