找到平均值时出现 ZeroDivisionError
ZeroDivisionError when finding average
过去几天我一直在尝试编写自己的 k-mean 算法,但遇到了障碍。当我试图找到簇中点的平均位置以移动质心时,我得到一个零除法错误(注意:当 k = 2 时不会发生这种情况,只有当 k = 3 时才会发生,但总是当 k >= 4 时发生)。我试图通过确保每个质心从数据集中的一个点开始来解决这个问题,这样它在它的集群中总是至少有一个点,但它没有奏效。我也重新安排了计数器等,但同样,它没有用。我有 运行 的想法,我不确定为什么这个错误仍然发生。我很确定问题出在这些函数之一(编辑:添加了所有代码和完整的错误消息):
import random
import math
import matplotlib.pyplot as plt
class Kmeans:
def __init__(self, K, dataset, centroids, sorting):
self.K = K
self.dataset = dataset
self.centroids = centroids
self.sorting = sorting
def initializeCentroids(self):
usedPoints = [random.choice(data_set)]
self.centroids = []
for q in range(self.K):
pointSelected = False
while not pointSelected:
m = random.choice(data_set)
print(m)
print(usedPoints)
distance = math.sqrt(abs(((m[0] - usedPoints[len(usedPoints) - 1][0]) ** 2) + (m[1] - usedPoints[len(usedPoints) - 1][1]) ** 2))
if usedPoints.count(m) == 0 and distance > 50:
self.centroids.append(list(m))
usedPoints.append(m)
pointSelected = True
return self.centroids
def calcDistance(self):
self.sorting = []
for w in self.dataset:
distances = []
counter = -1
for centr in self.centroids:
counter += 1
distances.append(math.sqrt(abs((((w[0] - centr[0]) ** 2) + (w[1] - centr[1]) ** 2))))
for x in range(len(distances)):
if len(distances) > 1:
print(distances)
if distances[0] > distances[1]:
distances.pop(0)
else:
distances.pop(1)
counter -= 1
print(counter)
self.sorting.insert(0, [w, counter, distances[0]])
return self.sorting
# not done
def find_ME(self):
counter2 = 0
for r in self.centroids:
for t in self.sorting:
nums = []
if t[1] == counter2:
nums.append(t[2])
population = len(nums)
error = sum(nums) / population
def reassignCentroids(self):
counter3 = 0
for r in self.centroids:
positionsX = []
positionsY = []
for t in self.sorting:
if t[1] == counter3:
positionsX.append(t[0][0])
positionsY.append(t[0][1])
population = len(positionsY)
print(population)
print(self.sorting)
r[0] = sum(positionsX) / population
r[1] = sum(positionsY) / population
counter3 += 1
return self.centroids
def checkSimilar(self, prevList):
list1 = []
list2 = []
for u in prevList:
list1.append(u[1])
for i in self.sorting:
list2.append(i[1])
print(i)
if list2 == list1:
return True
else:
return False
k = 3
data_set = [(1, 1), (1, 2), (1, 3), (2, 3), (50, 52), (48, 50), (47, 60), (112, 90), (120, 100), (108, 130), (102, 121), (43, 51), (0, 1)]
attempt = Kmeans(k, data_set, [], [])
attempt.initializeCentroids()
xvals = []
yvals = []
sortCompare = []
maxIterations = 100000
# plots
for p in data_set:
xvals.append(p[0])
yvals.append(p[1])
running = True
zeroError = True
while running:
attempt.calcDistance()
sortCompare = attempt.sorting
print(sortCompare, "thisss")
attempt.reassignCentroids()
attempt.calcDistance()
attempt.reassignCentroids()
boolVal = attempt.checkSimilar(sortCompare)
if boolVal or maxIterations <= 0:
xs = []
ys = []
for y in attempt.centroids:
xs.append(y[0])
ys.append(y[1])
plt.scatter(xs, ys)
running = False
else:
sortCompare = []
maxIterations -= 1
print(attempt.sorting)
print(attempt.centroids)
plt.scatter(xvals, yvals)
plt.show()
完整错误:回溯(最后一次调用):
文件“C:/Users/Jack Cramer/PycharmProjects/kmeans/main.py”,第 117 行,位于
attempt.reassignCentroids()
文件“C:/Users/Jack Cramer/PycharmProjects/kmeans/main.py”,第 73 行,在 reassignCentroids 中
r[0] = sum(positionsX) / population
ZeroDivisionError:除以零
如果你知道为什么会这样,请告诉我,谢谢你的建议。
正如@thierry-lathuille 指出的那样,当您除以 population
时,错误发生在 reassignCentroids
中,即零。 population
设置为positionsY
的长度,所以我们需要看看哪些场景导致positionsY
没有元素
positionsY
将其值附加到值 t in self.sorting
的循环内。仅当 counter3
(范围从 0 到 K-1)匹配 t[1]
时才附加值。因此,如果 counter3
的值与 t[1]
值中的 none 相等,我们将得到错误。为了帮助调试,我在循环中添加了一些打印语句
print(f"{counter3=}")
for t in self.sorting:
print(f"{t[1]=}")
if t[1] == counter3:
positionsX.append(t[0][0])
positionsY.append(t[0][1])
运行 多次使用 k=2
,我看到 t[1]
是 0 或 1,如您所见,它不会崩溃。然而,上升到 k=3
,有时我得到 t[1]
等于 0、1 或 2,但其他时候它只等于 0 或 1。这意味着没有匹配,你会除以零。上升到 k=4
,我们应该得到 t[1]
等于 0、1、2 或 3,但在多次重新启动后我没有看到任何 3。
根据上下文,我猜测 t[1]
代表给定数据点最接近的集群。根据您的输入,肉眼看来存在三组点
所以你的代码自然会有三个预测的集群趋向于它们应该在的位置,所以如果你试图预测 4 个集群,你总是会崩溃。如果您只想预测 3 个集群,您可能会倒霉,并且您预测的集群之一不是最接近任何点的。即使 k=2
对某些初始化出错,我也不会感到惊讶,但在实践中一定很少见。
我想你需要先问问自己,当 k
高于实际簇数时,你希望看到什么行为。其次,您需要确定当 none 个数据点最接近集群时如何更新集群的位置。如果 population == 0
,一个快速的解决方法是什么都不做,尽管这可能不会产生您想要的行为。
过去几天我一直在尝试编写自己的 k-mean 算法,但遇到了障碍。当我试图找到簇中点的平均位置以移动质心时,我得到一个零除法错误(注意:当 k = 2 时不会发生这种情况,只有当 k = 3 时才会发生,但总是当 k >= 4 时发生)。我试图通过确保每个质心从数据集中的一个点开始来解决这个问题,这样它在它的集群中总是至少有一个点,但它没有奏效。我也重新安排了计数器等,但同样,它没有用。我有 运行 的想法,我不确定为什么这个错误仍然发生。我很确定问题出在这些函数之一(编辑:添加了所有代码和完整的错误消息):
import random
import math
import matplotlib.pyplot as plt
class Kmeans:
def __init__(self, K, dataset, centroids, sorting):
self.K = K
self.dataset = dataset
self.centroids = centroids
self.sorting = sorting
def initializeCentroids(self):
usedPoints = [random.choice(data_set)]
self.centroids = []
for q in range(self.K):
pointSelected = False
while not pointSelected:
m = random.choice(data_set)
print(m)
print(usedPoints)
distance = math.sqrt(abs(((m[0] - usedPoints[len(usedPoints) - 1][0]) ** 2) + (m[1] - usedPoints[len(usedPoints) - 1][1]) ** 2))
if usedPoints.count(m) == 0 and distance > 50:
self.centroids.append(list(m))
usedPoints.append(m)
pointSelected = True
return self.centroids
def calcDistance(self):
self.sorting = []
for w in self.dataset:
distances = []
counter = -1
for centr in self.centroids:
counter += 1
distances.append(math.sqrt(abs((((w[0] - centr[0]) ** 2) + (w[1] - centr[1]) ** 2))))
for x in range(len(distances)):
if len(distances) > 1:
print(distances)
if distances[0] > distances[1]:
distances.pop(0)
else:
distances.pop(1)
counter -= 1
print(counter)
self.sorting.insert(0, [w, counter, distances[0]])
return self.sorting
# not done
def find_ME(self):
counter2 = 0
for r in self.centroids:
for t in self.sorting:
nums = []
if t[1] == counter2:
nums.append(t[2])
population = len(nums)
error = sum(nums) / population
def reassignCentroids(self):
counter3 = 0
for r in self.centroids:
positionsX = []
positionsY = []
for t in self.sorting:
if t[1] == counter3:
positionsX.append(t[0][0])
positionsY.append(t[0][1])
population = len(positionsY)
print(population)
print(self.sorting)
r[0] = sum(positionsX) / population
r[1] = sum(positionsY) / population
counter3 += 1
return self.centroids
def checkSimilar(self, prevList):
list1 = []
list2 = []
for u in prevList:
list1.append(u[1])
for i in self.sorting:
list2.append(i[1])
print(i)
if list2 == list1:
return True
else:
return False
k = 3
data_set = [(1, 1), (1, 2), (1, 3), (2, 3), (50, 52), (48, 50), (47, 60), (112, 90), (120, 100), (108, 130), (102, 121), (43, 51), (0, 1)]
attempt = Kmeans(k, data_set, [], [])
attempt.initializeCentroids()
xvals = []
yvals = []
sortCompare = []
maxIterations = 100000
# plots
for p in data_set:
xvals.append(p[0])
yvals.append(p[1])
running = True
zeroError = True
while running:
attempt.calcDistance()
sortCompare = attempt.sorting
print(sortCompare, "thisss")
attempt.reassignCentroids()
attempt.calcDistance()
attempt.reassignCentroids()
boolVal = attempt.checkSimilar(sortCompare)
if boolVal or maxIterations <= 0:
xs = []
ys = []
for y in attempt.centroids:
xs.append(y[0])
ys.append(y[1])
plt.scatter(xs, ys)
running = False
else:
sortCompare = []
maxIterations -= 1
print(attempt.sorting)
print(attempt.centroids)
plt.scatter(xvals, yvals)
plt.show()
完整错误:回溯(最后一次调用): 文件“C:/Users/Jack Cramer/PycharmProjects/kmeans/main.py”,第 117 行,位于 attempt.reassignCentroids() 文件“C:/Users/Jack Cramer/PycharmProjects/kmeans/main.py”,第 73 行,在 reassignCentroids 中 r[0] = sum(positionsX) / population ZeroDivisionError:除以零
如果你知道为什么会这样,请告诉我,谢谢你的建议。
正如@thierry-lathuille 指出的那样,当您除以 population
时,错误发生在 reassignCentroids
中,即零。 population
设置为positionsY
的长度,所以我们需要看看哪些场景导致positionsY
没有元素
positionsY
将其值附加到值 t in self.sorting
的循环内。仅当 counter3
(范围从 0 到 K-1)匹配 t[1]
时才附加值。因此,如果 counter3
的值与 t[1]
值中的 none 相等,我们将得到错误。为了帮助调试,我在循环中添加了一些打印语句
print(f"{counter3=}")
for t in self.sorting:
print(f"{t[1]=}")
if t[1] == counter3:
positionsX.append(t[0][0])
positionsY.append(t[0][1])
运行 多次使用 k=2
,我看到 t[1]
是 0 或 1,如您所见,它不会崩溃。然而,上升到 k=3
,有时我得到 t[1]
等于 0、1 或 2,但其他时候它只等于 0 或 1。这意味着没有匹配,你会除以零。上升到 k=4
,我们应该得到 t[1]
等于 0、1、2 或 3,但在多次重新启动后我没有看到任何 3。
根据上下文,我猜测 t[1]
代表给定数据点最接近的集群。根据您的输入,肉眼看来存在三组点
k=2
对某些初始化出错,我也不会感到惊讶,但在实践中一定很少见。
我想你需要先问问自己,当 k
高于实际簇数时,你希望看到什么行为。其次,您需要确定当 none 个数据点最接近集群时如何更新集群的位置。如果 population == 0
,一个快速的解决方法是什么都不做,尽管这可能不会产生您想要的行为。