numpy Perceptron算法的实现,但运行时效率不高

z9gpfhce  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(109)

当样本大小设置为10时,直到收敛的平均迭代次数应该在15左右。然而,当在我的代码中实现该算法时,它需要大约225(或更多!)迭代以达到收敛。这让我怀疑代码中的while循环可能有问题,但我无法识别它。

def gen_data(N=10):
    size = (N, 2)
    data = np.random.uniform(-1, 1, size)
    point1, point2 = data[np.random.choice(data.shape[0], 2, replace=False), :]
    m = (point2[1] - point1[1]) / (point2[0] - point1[0])
    c = point1[1] - m * point1[0]
    labels = np.array([+1 if y >= m * x + c else -1 for x, y in data])
    data = np.column_stack((data, labels))
    return data, point1, point2

class PLA:
    def __init__(self, data):
        m, n = data.shape
        self.X = np.hstack((np.ones((m, 1)), data[:, :2]))
        self.w = np.zeros(n)
        self.y = data[:, -1]
        self.count = 0

    def fit(self):
        while True:
            self.count += 1
            y_pred = self.predict(self.X)
            misclassified = np.where(y_pred != self.y)[0]
            if len(misclassified) == 0:
                break

            idx = np.random.choice(misclassified)
            self.update_weight(idx)

    def update_weight(self, idx):
        self.w +=  self.y[idx] * self.X[idx]

    def sign(self, z):
        return np.where(z > 0, 1, np.where(z < 0, -1, 0))

    def predict(self, x):
        z = np.dot(x, self.w)
        return self.sign(z)
0s0u357o

0s0u357o1#

问题不在于你的右循环,而在于你的数据生成函数。
N随机点中选择两个点来定义决策线:

point1, point2 = data[np.random.choice(data.shape[0], 2, replace=False), :]

然而,它们在数据集中停留在后面,因此它们被标记为1,并且正好在决策线上。
如果你随机选取两个不在你的数据集中的点,那么算法应该在10步内收敛,大约从我测试的开始(只需要采样N + 2点,然后选择前两个点来定义你的决策线,其他的用于你的数据集)。

  • 那么,为什么这个小差异会使收敛所需的步骤变慢?*

我会说,因为数据集中的两个点位于决策线上,所以学习零误差模型可能是最困难的,特别是如果其他点靠近它,因为一次模型更新可能会导致模型仍然不完美。
Easy case
Hard case

  • 是否需要定义决策线,使数据集中没有点在其上?*

我会说是的,因为域空间是连续的。

bsxbgnwa

bsxbgnwa2#

将随机生成器更改为:

import numpy as np
def gen_data(N=10):
    size = (N, 2)
    data = np.random.uniform(-1, 1, size)
    point1, point2 = np.random.uniform(-1, 1, (2,2))
    m = (point2[1] - point1[1]) / (point2[0] - point1[0])
    c = point1[1] - m * point1[0]
    labels = np.array([+1 if y >= m * x + c else -1 for x, y in data])
    data = np.column_stack((data, labels))
    return data, point1, point2

在我的模拟中:

total = 0
for i in range(1000):
  d,x,y = gen_data()
  w = PLA(d)
  w.fit()
  print(w.count)
  total+=w.count
total/1000

结果接近15,但使用前一个生成器,它可能会在分离选择靠近线的点时卡住。

相关问题