Skip to content

Commit 772f9ec

Browse files
committed
* Fixed bug #1727558
* Some more tests * ValueError changed to ClusteringError where appropriate git-svn-id: https://python-cluster.svn.sourceforge.net/svnroot/python-cluster/trunk@3 57eab859-f816-0410-af72-e61ffa1cc713
1 parent 5ccd132 commit 772f9ec

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

cluster.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
from types import TupleType
1919

20+
class ClusteringError(Exception):
21+
pass
22+
2023
def flatten(L):
2124
"""
2225
Flattens a list.
@@ -632,6 +635,8 @@ def __init__(self, data, distance=None):
632635
euclidian-distance algorithm on them.
633636
"""
634637
self.__data = data
638+
self.distance = distance
639+
self.__initial_length = len(data)
635640

636641
# test if each item is of same dimensions
637642
if len(data) > 1 and isinstance(data[0], TupleType):
@@ -654,14 +659,21 @@ def getclusters(self, n):
654659
n - The amount of clusters that should be generated.
655660
n must be greater than 1
656661
"""
662+
657663
# only proceed if we got sensible input
658664
if n <= 1:
659-
raise ValueError("When clustering, you need to ask for at least two clusters! You asked for %d" % n)
665+
raise ClusteringError("When clustering, you need to ask for at least two clusters! You asked for %d" % n)
660666

661667
# return the data straight away if there is nothing to cluster
662-
if self.__data == [] or len(self.__data) == 1:
668+
if self.__data == [] or len(self.__data) == 1 or n == self.__initial_length:
663669
return self.__data
664670

671+
# It makes no sense to ask for more clusters than data-items available
672+
if n > self.__initial_length:
673+
raise ClusteringError( """Unable to generate more clusters than items
674+
available. You supplied %d items, and asked for %d clusters.""" %
675+
(self.__initial_length, n) )
676+
665677
self.initialiseClusters(self.__data, n)
666678

667679
items_moved = True # tells us if any item moved between the clusters,

clusterTests.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,13 @@ class KCluster2DTestCase(unittest.TestCase):
130130
def testClusterCount(self):
131131
"Test that asking for less than 2 clusters raises an error"
132132
cl = KMeansClustering([876, 123, 344, 676], distance=lambda x,y: abs(x-y))
133-
self.assertRaises(ValueError, cl.getclusters, 0)
134-
self.assertRaises(ValueError, cl.getclusters, 1)
133+
self.assertRaises(ClusteringError, cl.getclusters, 0)
134+
self.assertRaises(ClusteringError, cl.getclusters, 1)
135+
136+
def testNonsenseCluster(self):
137+
"Test that asking for more clusters than data-items available raises an error"
138+
cl = KMeansClustering([876, 123], distance=lambda x,y: abs(x-y))
139+
self.assertRaises(ClusteringError, cl.getclusters, 5)
135140

136141
def testUniformLength(self):
137142
"Test if there is an item in the cluster that has a different cardinality"
@@ -161,12 +166,25 @@ def testClustering(self):
161166
[[(8, 2), (8, 1), (8, 3), (7, 3), (9, 2), (9, 3)],
162167
[(3, 5), (1, 5), (3, 4), (2, 6), (2, 5), (3, 6)]])
163168

169+
class KClusterSFBugs(unittest.TestCase):
170+
171+
def testLostFunctionReference(self):
172+
"test for bug #1727558"
173+
cl = KMeansClustering([(1,1), (20,40), (20,41)], lambda x,y:x+y)
174+
clusters = cl.getclusters(3)
175+
expected = [(1,1), (20,40), (20,41)]
176+
self.assertTrue( compare_list(
177+
clusters,
178+
expected ),
179+
"Elements differ!\n%s\n%s" % (clusters, expected))
180+
164181
unittest.TextTestRunner(verbosity=2).run(
165182
unittest.TestSuite((
166183
unittest.makeSuite(HClusterSmallListTestCase),
167184
unittest.makeSuite(HClusterIntegerTestCase),
168185
unittest.makeSuite(HClusterStringTestCase),
169186
unittest.makeSuite(KClusterSmallListTestCase),
170187
unittest.makeSuite(KCluster2DTestCase),
188+
unittest.makeSuite(KClusterSFBugs),
171189
))
172190
)

0 commit comments

Comments
 (0)