Completed
Push — 0.8.dev ( 244bc6...fbf64e )
by Andrei
01:01
created

ttsas.__append_to_cluster()   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
"""!
2
3
@brief Cluster analysis algorithm: TTSAS (Two-Threshold Sequential Algorithmic Scheme).
4
@details Implementation based on book:
5
         - Theodoridis, Koutroumbas, Konstantinos. Elsevier Academic Press - Pattern Recognition - 2nd Edition. 2003.
6
7
@authors Andrei Novikov ([email protected])
8
@date 2014-2018
9
@copyright GNU Public License
10
11
@cond GNU_PUBLIC_LICENSE
12
    PyClustering is free software: you can redistribute it and/or modify
13
    it under the terms of the GNU General Public License as published by
14
    the Free Software Foundation, either version 3 of the License, or
15
    (at your option) any later version.
16
17
    PyClustering is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
22
    You should have received a copy of the GNU General Public License
23
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
@endcond
25
26
"""
27
28
29
from pyclustering.cluster.bsas import bsas;
30
31
32
class ttsas(bsas):
33
    """!
34
    @brief Class represents TTSAS (Two-Threshold Sequential Algorithmic Scheme).
35
36
    @see pyclustering.cluster.bsas, pyclustering.cluster.mbsas
37
38
    """
39
40
    def __init__(self, data, threshold1, threshold2, ccore, **kwargs):
41
        """!
42
        @brief Creates TTSAS algorithm.
43
44
        @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple.
45
        @param[in] maximum_clusters: Maximum allowable number of clusters that can be allocated during processing.
46
        @param[in] threshold1: Dissimilarity level (distance) between point and its closest cluster, if the distance is
47
                    less than 'threshold1' value then point is assigned to the cluster.
48
        @param[in] threshold2: Dissimilarity level (distance) between point and its closest cluster, if the distance is
49
                    greater than 'threshold2' value then point is considered as a new cluster.
50
        @param[in] ccore (bool): If True than DLL CCORE (C++ solution) will be used for solving.
51
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric').
52
53
        Keyword Args:
54
            metric (distance_metric): Metric that is used for distance calculation between two points.
55
56
        """
57
58
        self._threshold2 = threshold2;
59
        self._amount_skipped_objects = len(data);
60
        self._skipped_objects = [ True ] * len(data);
61
62
        super().__init__(data, len(data), threshold1, ccore, **kwargs);
63
64
65
    def process(self):
66
        """!
67
        @brief Performs cluster analysis in line with rules of BSAS algorithm.
68
69
        @remark Results of clustering can be obtained using corresponding get methods.
70
71
        @see get_clusters()
72
        @see get_representatives()
73
74
        """
75
76
        changes = 0;
77
        while self._amount_skipped_objects != 0:
78
            previous_amount = self._amount_skipped_objects;
79
            self.__process_objects(changes);
80
81
            changes = previous_amount - self._amount_skipped_objects;
82
83
84
    def __process_objects(self, changes):
85
        index_point = self._skipped_objects.index(True);
86
87
        if changes == 0:
88
            self.__allocate_cluster(index_point, self._data[index_point]);
89
            index_point += 1;
90
91
        for i in range(index_point, len(self._data)):
92
            if self._skipped_objects[i] is True:
93
                self.__process_skipped_object(i);
94
95
96
    def __process_skipped_object(self, index_point):
97
        point = self._data[index_point];
98
99
        index_cluster, distance = self._find_nearest_cluster(point);
100
101
        if distance < self._threshold:
102
            self.__append_to_cluster(index_cluster, index_point, point);
103
        elif distance > self._threshold2:
104
            self.__allocate_cluster(index_point, point);
105
106
107
    def __append_to_cluster(self, index_cluster, index_point, point):
108
        self._clusters[index_cluster].append(index_point);
109
        self._update_representative(index_cluster, point);
110
111
        self._amount_skipped_objects -= 1;
112
        self._skipped_objects[index_point] = False;
113
114
115
    def __allocate_cluster(self, index_point, point):
116
        self._clusters.append( [index_point] );
117
        self._representatives.append(point);
118
119
        self._amount_skipped_objects -= 1;
120
        self._skipped_objects[index_point] = False;
121