台大在线课程的Machine Learning Foundations,作业二的Question 4
如何解这道题目?我们可以写一支python解这道题目。如,求Original VC Bound的epsilon(error)的上限为多少,定义一个function:
def errorForOriginalVcBound (N, sigma):
然后将数学式子写成代码,放进去就好了。但这时候,遇到一个问题,如何用程序表达mH?还记得VC
Dimension吗?:
我们可以将mH(N)换成N^dvc,如此一来,式子就写成:
于是,我们的function,多了一个参数,叫dvc:
def errorForOriginalVcBound (dvc, N, sigma):
也可以用Python定义一个function叫mH,覆用之。def mH (N, dvc):
return math.pow (N, dvc)
Error for Original VC Bound的实作
def errorForOriginalVcBound (dvc, N, sigma):
value = 4 * mH (2*N, dvc) / sigma
value = 8 * np.log (value) / N
value = math.sqrt (value)
return value
接下来是 Error for Rademacher Penalty Bound的实作,
def errorForRademacherPenaltyBound (dvc, N, sigma):
value1 = 2 * N * mH (N, dvc)
value1 = 2 * np.log (value1) / N
value1 = math.sqrt (value1)
value2 = (2/N) * np.log (1/sigma)
value2 = math.sqrt (value2)
value3 = 1/N
return value1 + value2 + value3
再来是Error for Parrondo and Van den Broek的实作。但我们发现一个问题,就是公式的左右边,都有一个epsilon。有两种解法,第1种解法,是用一元二次求x解的公式,x就是epsilon:
ax^2 + bx + c = 0
这样,就可以推导出,只有左边有epsilon的式子出来。于是,我们就把式子的右边,写成代码即可。这是数学家的作法。
第2种解法,将epsilon当成一个参数。至于要给什么样的值,我们可以先观察其它的式子算出来的结果,再做决定。我选择第2种解法,于是,Error for Parrondo and Van den Broek的实作如下:
def errorForParrondoAndVanDenBroek (dvc, N, sigma, epsilon):
value = 6 * mH (2*N, dvc) / sigma
value = 2 * epsilon + np.log (value)
value = math.sqrt ((1/N) * value)
return value
对于Devroye而言,也是公式的左右两边,都有一个epsilon。实作的方法与刚才的Parrondo相同:
def errorForDevroye (dvc, N, sigma, epsilon):
value = np.log (4) + dvc * np.log (N * N) - np.log (epsilon)
value = 4 * epsilon * (1 + epsilon) + value
value = (1/(2*N)) * value
value = math.sqrt (value)
return value
这里有一个问题是,为何function的第一行要这么写?那是因为当N=10000时,直接计算,数字太大,计算机无法处理。我们可用以用对数运算,将式子拆解成计算机可以处理的单元,如下:
最后是Variant VC Bound的实作:
def errorVariantVcBound (dvc, N, sigma):
value = 2 * mH (N, dvc)
value = value / math.sqrt (sigma)
value = np.log (value)
value = (16.0 / N) * value
value = math.sqrt (value)
return value
所以,我们现在有5个functions,依据题目的顺序排列:errorForOriginalVcBound
errorForRademacherPenaltyBound
errorForParrondoAndVanDenBroek
errorForDevroye
errorVariantVcBound
其中,errorForParrondoAndVanDenBroek和errorForDevroye因为都需要epsilon参数,而我们不知道该给那一个值,所以暂不管它。先求其它3个:
dvc = 50
sigma = 0.05
N = 10000
value1 = errorForOriginalVcBound (dvc, N, sigma)
print ("Error for Original VC Bound = ", value1)
value2 = errorForRademacherPenaltyBound (dvc, N, sigma)
print ("Error for Rademacher Penalty Bound = ", value2)
value3 = errorVariantVcBound (dvc, N, sigma)
print ("Error for Variant VC Bound = ", value3)
执行结果
发现最小的值是0.3313。我们可以用这个最小的值,当作是epsilon的参数,用在errorForParrondoAndVanDenBroek和errorForDevroye
epsilon = min ([value1, value2, value3])
print ("epsilon = ", epsilon)
value4 = errorForParrondoAndVanDenBroek (dvc, N, sigma, epsilon)
print ("Error for Parrondo and Van den Broek = ", value4)
value5 = errorForDevroye (dvc, N, sigma, epsilon)
print ("Error for Devroye = ", value5)
执行结果所以,Devroye公式算出来的值,是最小的。
-Count