在实现中,我将使用Wellford方法 我不喜欢使用“标准”公式进行计算。 此外,我不会使用numpy和其他任何库来证明python语言的基本构造知识足以获得解决方案。
因此,我们需要能够递增地计算偏差的平均值和总和。 为此,我们描述了两个类:
class MeanCalculator: def __init__(self): self.Count = 0. self.Mean = 0. def Add(self, value, weight = 1.): self.Count += weight self.Mean += weight * (value - self.Mean) / self.Count def Remove(self, value, weight = 1.): self.Add(value, -weight) class SumSquaredErrorsCalculator: def __init__(self): self.MeanCalculator = MeanCalculator() self.SSE = 0. def Add(self, value, weight = 1.): curDiff = value - self.MeanCalculator.Mean self.MeanCalculator.Add(value, weight) self.SSE += weight * curDiff * (value - self.MeanCalculator.Mean) def Remove(self, value, weight = 1.): self.Add(value, -weight)
现在我们需要一个类来存储和处理训练集。 首先,我们描述它的字段和输入法:
class Instances: def __init__(self): self.Items = [] self.OverAllSSE = SumSquaredErrorsCalculator() def Read(self): fin = open('stump.in') for line in fin.readlines()[1:]: x, y = map(float, line.strip().split()) self.Items.append([x, y]) self.OverAllSSE.Add(y) self.Items.sort()
与数据输入同时,我们立即为所选内容中的所有对象形成SumSquaredErrorsCalculator结构。 加载整个样本后,我们按不减属性值对其进行排序。
现在最有趣的是:查找最佳参数值的方法。
让我们从初始化开始。 在初始状态下,所有对象都在正确的子样本中。 然后参数 可以等于任何东西,参数 等于整个样本的平均响应,参数 这样所选内容中的所有对象都在其右侧。
另外,我们初始化right
变量-它们将分别存储左右子样本的统计信息。
left = SumSquaredErrorsCalculator() right = self.OverAllSSE bestA = 0 bestB = right.MeanCalculator.Mean bestC = self.Items[0][0] bestQ = right.SSE
现在让我们继续进行增量算法。 我们将一次处理一个选择元素。 每个元素都转移到左子集。 然后,您需要验证相应分区是否确实存在-也就是说,特征值与下一个对象的特征值不同。
for i in range(len(self.Items) - 1): item = self.Items[i] nextItem = self.Items[i + 1] left.Add(item[1]) right.Remove(item[1]) if item[0] == nextItem[0]: continue a = left.MeanCalculator.Mean b = right.MeanCalculator.Mean c = (item[0] + nextItem[0]) / 2 q = left.SSE + right.SSE if q < bestQ: bestA = a bestB = b bestC = c bestQ = q
现在仅需编写代码即可获得解决方案:
instances = Instances() instances.Read() a, b, c = instances.BestSplit() print >> open('stump.out', 'w'), a, b, c
我注意到,以python提出的解决方案确实已为系统所接受,但它涉及到解决方案时间的上限:最大的测试大约需要800毫秒才能执行。 当然,使用其他库可以实现更出色的性能。
因此,我也用C ++实现了所提出的算法 。 在最坏的情况下,此解决方案在其中一项测试上花费了60毫秒。