pygmi 2.2.7__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygmi-2.2.7/LICENSE.txt +623 -0
- pygmi-2.2.7/MANIFEST.in +7 -0
- pygmi-2.2.7/PKG-INFO +47 -0
- pygmi-2.2.7/README.md +55 -0
- pygmi-2.2.7/README.rst +20 -0
- pygmi-2.2.7/log.txt +242 -0
- pygmi-2.2.7/pygmi/__init__.py +22 -0
- pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
- pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
- pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
- pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
- pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
- pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
- pygmi-2.2.7/pygmi/clust/menu.py +139 -0
- pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
- pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
- pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
- pygmi-2.2.7/pygmi/images/Help.png +0 -0
- pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
- pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
- pygmi-2.2.7/pygmi/images/delete.png +0 -0
- pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
- pygmi-2.2.7/pygmi/images/logo256.png +0 -0
- pygmi-2.2.7/pygmi/images/pointer.png +0 -0
- pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
- pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
- pygmi-2.2.7/pygmi/main.py +1037 -0
- pygmi-2.2.7/pygmi/menu_default.py +327 -0
- pygmi-2.2.7/pygmi/misc.py +147 -0
- pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
- pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
- pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
- pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
- pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
- pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
- pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
- pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
- pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
- pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
- pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
- pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
- pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
- pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
- pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
- pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
- pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
- pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
- pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
- pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
- pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
- pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
- pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
- pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
- pygmi-2.2.7/pygmi/raster/menu.py +307 -0
- pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
- pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
- pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
- pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
- pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
- pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
- pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
- pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
- pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
- pygmi-2.2.7/pygmi/seis/menu.py +136 -0
- pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
- pygmi-2.2.7/pygmi/test/__init__.py +6 -0
- pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
- pygmi-2.2.7/pygmi/test/tests.py +39 -0
- pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
- pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
- pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
- pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
- pygmi-2.2.7/pygmi/vector/menu.py +127 -0
- pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
- pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
- pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
- pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
- pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
- pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
- pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
- pygmi-2.2.7/quickstart.py +35 -0
- pygmi-2.2.7/setup.cfg +8 -0
- pygmi-2.2.7/setup.py +80 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# Name: crisp_clust.py (part of PyGMI)
|
|
3
|
+
#
|
|
4
|
+
# Author: Patrick Cole
|
|
5
|
+
# E-Mail: pcole@geoscience.org.za
|
|
6
|
+
#
|
|
7
|
+
# Copyright: (c) 2013 Council for Geoscience
|
|
8
|
+
# Licence: GPL-3.0
|
|
9
|
+
#
|
|
10
|
+
# This file is part of PyGMI
|
|
11
|
+
#
|
|
12
|
+
# PyGMI 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
|
+
# PyGMI 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
|
+
# -----------------------------------------------------------------------------
|
|
25
|
+
""" This is the main Crisp Clustering set of routines """
|
|
26
|
+
|
|
27
|
+
from PyQt4 import QtGui, QtCore
|
|
28
|
+
import numpy as np
|
|
29
|
+
import copy
|
|
30
|
+
from pygmi.clust.datatypes import Clust
|
|
31
|
+
import pygmi.clust.var_ratio as vr
|
|
32
|
+
import os
|
|
33
|
+
import pdb
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class CrispClust(QtGui.QDialog):
|
|
37
|
+
"""
|
|
38
|
+
Crisp Cluster Class
|
|
39
|
+
|
|
40
|
+
Attributes
|
|
41
|
+
----------
|
|
42
|
+
parent : parent
|
|
43
|
+
reference to the parent routine
|
|
44
|
+
indata : dictionary
|
|
45
|
+
dictionary of input datasets
|
|
46
|
+
outdata : dictionary
|
|
47
|
+
dictionary of output datasets
|
|
48
|
+
"""
|
|
49
|
+
def __init__(self, parent=None):
|
|
50
|
+
QtGui.QDialog.__init__(self, parent)
|
|
51
|
+
|
|
52
|
+
self.indata = {}
|
|
53
|
+
self.outdata = {}
|
|
54
|
+
self.parent = parent
|
|
55
|
+
self.pbar = parent.pbar
|
|
56
|
+
|
|
57
|
+
self.spinbox_maxclusters = QtGui.QSpinBox()
|
|
58
|
+
self.combobox_alg = QtGui.QComboBox()
|
|
59
|
+
self.doublespinbox_maxerror = QtGui.QDoubleSpinBox()
|
|
60
|
+
self.spinbox_maxiterations = QtGui.QSpinBox()
|
|
61
|
+
self.spinbox_repeatedruns = QtGui.QSpinBox()
|
|
62
|
+
self.spinbox_minclusters = QtGui.QSpinBox()
|
|
63
|
+
self.checkbox_denorm = QtGui.QCheckBox()
|
|
64
|
+
self.groupbox = QtGui.QGroupBox()
|
|
65
|
+
self.label_7 = QtGui.QLabel()
|
|
66
|
+
self.doublespinbox_constraincluster = QtGui.QDoubleSpinBox()
|
|
67
|
+
self.radiobutton_random = QtGui.QRadioButton()
|
|
68
|
+
self.radiobutton_manual = QtGui.QRadioButton()
|
|
69
|
+
self.radiobutton_datadriven = QtGui.QRadioButton()
|
|
70
|
+
|
|
71
|
+
self.setupui()
|
|
72
|
+
|
|
73
|
+
self.name = "Crisp Clustering"
|
|
74
|
+
self.cltype = 'k-means'
|
|
75
|
+
self.min_cluster = 5
|
|
76
|
+
self.max_cluster = 5
|
|
77
|
+
self.max_iter = 100
|
|
78
|
+
self.term_thresh = 0.00001
|
|
79
|
+
self.runs = 1
|
|
80
|
+
self.constrain = 0.0
|
|
81
|
+
self.denorm = False
|
|
82
|
+
self.init_type = 'random'
|
|
83
|
+
self.type = 'crisp'
|
|
84
|
+
self.log = ''
|
|
85
|
+
|
|
86
|
+
self.combobox_alg.addItems(['k-means', 'advanced k-means', 'w-means'])
|
|
87
|
+
self.combobox_alg.currentIndexChanged.connect(self.combo)
|
|
88
|
+
self.combo()
|
|
89
|
+
|
|
90
|
+
self.reportback = self.parent.showprocesslog
|
|
91
|
+
|
|
92
|
+
def setupui(self):
|
|
93
|
+
""" setup UI """
|
|
94
|
+
gridlayout = QtGui.QGridLayout(self)
|
|
95
|
+
verticallayout = QtGui.QVBoxLayout(self.groupbox)
|
|
96
|
+
|
|
97
|
+
buttonbox = QtGui.QDialogButtonBox()
|
|
98
|
+
label = QtGui.QLabel()
|
|
99
|
+
label_2 = QtGui.QLabel()
|
|
100
|
+
label_3 = QtGui.QLabel()
|
|
101
|
+
label_4 = QtGui.QLabel()
|
|
102
|
+
label_5 = QtGui.QLabel()
|
|
103
|
+
label_6 = QtGui.QLabel()
|
|
104
|
+
|
|
105
|
+
self.spinbox_minclusters.setMinimum(1)
|
|
106
|
+
self.spinbox_minclusters.setProperty("value", 5)
|
|
107
|
+
self.spinbox_maxclusters.setMinimum(1)
|
|
108
|
+
self.spinbox_maxclusters.setProperty("value", 5)
|
|
109
|
+
self.spinbox_maxiterations.setMinimum(1)
|
|
110
|
+
self.spinbox_maxiterations.setMaximum(1000)
|
|
111
|
+
self.spinbox_maxiterations.setProperty("value", 100)
|
|
112
|
+
self.doublespinbox_maxerror.setDecimals(5)
|
|
113
|
+
self.doublespinbox_maxerror.setProperty("value", 1e-05)
|
|
114
|
+
self.spinbox_repeatedruns.setMinimum(1)
|
|
115
|
+
|
|
116
|
+
buttonbox.setOrientation(QtCore.Qt.Horizontal)
|
|
117
|
+
buttonbox.setStandardButtons(buttonbox.Cancel | buttonbox.Ok)
|
|
118
|
+
self.radiobutton_random.setChecked(True)
|
|
119
|
+
self.groupbox.hide()
|
|
120
|
+
|
|
121
|
+
self.setWindowTitle("Crisp Clustering")
|
|
122
|
+
label.setText("Cluster Algorithm:")
|
|
123
|
+
label_2.setText("Minimum Clusters:")
|
|
124
|
+
label_3.setText("Maximum Clusters")
|
|
125
|
+
label_4.setText("Maximum Iterations:")
|
|
126
|
+
label_5.setText("Terminate if relative change per iteration is less than:")
|
|
127
|
+
label_6.setText("Repeated Runs:")
|
|
128
|
+
self.label_7.setText("Constrain Cluster Shape (0: unconstrained, 1: spherical)")
|
|
129
|
+
self.checkbox_denorm.setText("De-normalise Results")
|
|
130
|
+
self.groupbox.setTitle("Initial Guess")
|
|
131
|
+
self.radiobutton_random.setText("Random")
|
|
132
|
+
self.radiobutton_manual.setText("Manual")
|
|
133
|
+
self.radiobutton_datadriven.setText("Data Driven")
|
|
134
|
+
|
|
135
|
+
gridlayout.addWidget(label, 0, 2, 1, 1)
|
|
136
|
+
gridlayout.addWidget(self.combobox_alg, 0, 4, 1, 1)
|
|
137
|
+
gridlayout.addWidget(label_2, 1, 2, 1, 1)
|
|
138
|
+
gridlayout.addWidget(self.spinbox_minclusters, 1, 4, 1, 1)
|
|
139
|
+
gridlayout.addWidget(label_3, 2, 2, 1, 1)
|
|
140
|
+
gridlayout.addWidget(self.spinbox_maxclusters, 2, 4, 1, 1)
|
|
141
|
+
gridlayout.addWidget(label_4, 3, 2, 1, 1)
|
|
142
|
+
gridlayout.addWidget(self.spinbox_maxiterations, 3, 4, 1, 1)
|
|
143
|
+
gridlayout.addWidget(label_5, 4, 2, 1, 1)
|
|
144
|
+
gridlayout.addWidget(self.doublespinbox_maxerror, 4, 4, 1, 1)
|
|
145
|
+
gridlayout.addWidget(label_6, 5, 2, 1, 1)
|
|
146
|
+
gridlayout.addWidget(self.spinbox_repeatedruns, 5, 4, 1, 1)
|
|
147
|
+
gridlayout.addWidget(self.label_7, 6, 2, 1, 1)
|
|
148
|
+
gridlayout.addWidget(self.doublespinbox_constraincluster, 6, 4, 1, 1)
|
|
149
|
+
gridlayout.addWidget(self.checkbox_denorm, 7, 2, 1, 1)
|
|
150
|
+
gridlayout.addWidget(self.groupbox, 8, 2, 1, 3)
|
|
151
|
+
gridlayout.addWidget(buttonbox, 9, 4, 1, 1)
|
|
152
|
+
|
|
153
|
+
verticallayout.addWidget(self.radiobutton_random)
|
|
154
|
+
verticallayout.addWidget(self.radiobutton_manual)
|
|
155
|
+
verticallayout.addWidget(self.radiobutton_datadriven)
|
|
156
|
+
|
|
157
|
+
buttonbox.accepted.connect(self.accept)
|
|
158
|
+
buttonbox.rejected.connect(self.reject)
|
|
159
|
+
|
|
160
|
+
def combo(self):
|
|
161
|
+
""" Combo box """
|
|
162
|
+
i = str(self.combobox_alg.currentText())
|
|
163
|
+
if i == 'w-means':
|
|
164
|
+
self.label_7.show()
|
|
165
|
+
self.doublespinbox_constraincluster.show()
|
|
166
|
+
else:
|
|
167
|
+
self.label_7.hide()
|
|
168
|
+
self.doublespinbox_constraincluster.hide()
|
|
169
|
+
|
|
170
|
+
def settings(self):
|
|
171
|
+
""" Settings """
|
|
172
|
+
tst = np.unique([i.data.shape for i in self.indata['Raster']])
|
|
173
|
+
if tst.size > 2:
|
|
174
|
+
pdb.set_trace()
|
|
175
|
+
self.reportback('Error: Your input datasets have different ' +
|
|
176
|
+
'sizes. Merge the data first')
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
self.update_vars()
|
|
180
|
+
temp = self.exec_()
|
|
181
|
+
if temp == 0:
|
|
182
|
+
return
|
|
183
|
+
|
|
184
|
+
self.parent.process_is_active()
|
|
185
|
+
self.run()
|
|
186
|
+
self.parent.process_is_active(False)
|
|
187
|
+
self.pbar.to_max()
|
|
188
|
+
return True
|
|
189
|
+
|
|
190
|
+
def update_vars(self):
|
|
191
|
+
""" Updates the variables """
|
|
192
|
+
self.cltype = str(self.combobox_alg.currentText())
|
|
193
|
+
self.min_cluster = self.spinbox_minclusters.value()
|
|
194
|
+
self.max_cluster = self.spinbox_maxclusters.value()
|
|
195
|
+
self.max_iter = self.spinbox_maxiterations.value()
|
|
196
|
+
self.term_thresh = self.doublespinbox_maxerror.value()
|
|
197
|
+
self.runs = self.spinbox_repeatedruns.value()
|
|
198
|
+
self.constrain = self.doublespinbox_constraincluster.value()
|
|
199
|
+
self.denorm = self.checkbox_denorm.isChecked()
|
|
200
|
+
|
|
201
|
+
def run(self):
|
|
202
|
+
""" Process data """
|
|
203
|
+
data = copy.copy(self.indata['Raster'])
|
|
204
|
+
self.update_vars()
|
|
205
|
+
# if datachecks.Datachecks(self).multdata(data) == False:
|
|
206
|
+
# return data
|
|
207
|
+
# if datachecks.Datachecks(self).isdata(data) == False:
|
|
208
|
+
# return data
|
|
209
|
+
# if datachecks.Datachecks(self).equalsize(data) == False:
|
|
210
|
+
# return data
|
|
211
|
+
# if datachecks.Datachecks(self).samecoords(data) == False:
|
|
212
|
+
# return data
|
|
213
|
+
# if datachecks.Datachecks(self).iscomplete(data) == False:
|
|
214
|
+
# return data
|
|
215
|
+
|
|
216
|
+
cltype = self.cltype
|
|
217
|
+
cov_constr = self.constrain
|
|
218
|
+
no_runs = self.runs
|
|
219
|
+
max_iter = self.max_iter
|
|
220
|
+
term_thresh = self.term_thresh
|
|
221
|
+
no_clust = np.array([self.min_cluster, self.max_cluster])
|
|
222
|
+
de_norm = self.denorm
|
|
223
|
+
|
|
224
|
+
self.reportback('Crisp Clustering started')
|
|
225
|
+
|
|
226
|
+
# #############################################################################
|
|
227
|
+
# Section to deal with different bands having different null values.
|
|
228
|
+
# Start with the first entry
|
|
229
|
+
masktmp = data[0].data.mask
|
|
230
|
+
# Add the all the masks to this. This promotes False values to True.
|
|
231
|
+
for i in data:
|
|
232
|
+
masktmp += i.data.mask
|
|
233
|
+
for i in range(len(data)): # Apply this to all the bands
|
|
234
|
+
data[i].data.mask = masktmp
|
|
235
|
+
# #############################################################################
|
|
236
|
+
|
|
237
|
+
# dat_in = np.array([i.data.flatten() for i in data]).T
|
|
238
|
+
dat_in = np.array([i.data.compressed() for i in data]).T
|
|
239
|
+
|
|
240
|
+
# dat_in = dat_in[dat_in != None]
|
|
241
|
+
|
|
242
|
+
# dat_in = np.array([[x for x in data[i].data.flatten() if x != None]
|
|
243
|
+
# for i in range(len(data))]).T
|
|
244
|
+
|
|
245
|
+
if self.radiobutton_manual.isChecked() is True:
|
|
246
|
+
ext = \
|
|
247
|
+
"ASCII matrix (*.txt);;" + \
|
|
248
|
+
"ASCII matrix (*.asc);;" + \
|
|
249
|
+
"ASCII matrix (*.dat)"
|
|
250
|
+
filename = QtGui.QFileDialog.getOpenFileName(
|
|
251
|
+
self.parent, 'Read Cluster Centers', '.', ext)
|
|
252
|
+
if filename == '':
|
|
253
|
+
return False
|
|
254
|
+
os.chdir(filename.rpartition('/')[0])
|
|
255
|
+
|
|
256
|
+
ifile = str(filename)
|
|
257
|
+
|
|
258
|
+
dummy_mod = np.ma.array(np.genfromtxt(ifile, unpack=True))
|
|
259
|
+
[ro0, co0] = np.shape(dummy_mod)
|
|
260
|
+
ro1 = np.sum(list(range(no_clust[0], no_clust[1] + 1)))
|
|
261
|
+
if dat_in.shape[1] != co0 or ro0 != ro1:
|
|
262
|
+
QtGui.QMessageBox.warning(self.parent, 'Warning',
|
|
263
|
+
' Incorrect matrix size!',
|
|
264
|
+
QtGui.QMessageBox.Ok,
|
|
265
|
+
QtGui.QMessageBox.Ok)
|
|
266
|
+
cnt = -1
|
|
267
|
+
for i in range(no_clust[0], no_clust[1] + 1):
|
|
268
|
+
smtmp = np.zeros(i)
|
|
269
|
+
for j in range(i):
|
|
270
|
+
cnt = cnt + 1
|
|
271
|
+
smtmp[j] = dummy_mod[cnt]
|
|
272
|
+
startmdat = {i: smtmp}
|
|
273
|
+
startmfix = {i: []}
|
|
274
|
+
|
|
275
|
+
filename = QtGui.QFileDialog.getOpenFileName(
|
|
276
|
+
self.parent, 'Read Cluster Center Constraints', '.', ext)
|
|
277
|
+
if filename == '':
|
|
278
|
+
QtGui.QMessageBox.warning(
|
|
279
|
+
self.parent, 'Warning',
|
|
280
|
+
'Running cluster analysis without constraints',
|
|
281
|
+
QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)
|
|
282
|
+
else:
|
|
283
|
+
os.chdir(filename.rpartition('/')[0])
|
|
284
|
+
ifile = str(filename)
|
|
285
|
+
dummy_mod = np.ma.array(np.genfromtxt(ifile, unpack=True))
|
|
286
|
+
[ro0, co0] = np.shape(dummy_mod)
|
|
287
|
+
ro1 = np.sum(list(range(no_clust[0], no_clust[1] + 1)))
|
|
288
|
+
if dat_in.shape[1] != co0 or ro0 != ro1:
|
|
289
|
+
QtGui.QMessageBox.warning(self.parent, 'Warning',
|
|
290
|
+
' Incorrect matrix size!',
|
|
291
|
+
QtGui.QMessageBox.Ok,
|
|
292
|
+
QtGui.QMessageBox.Ok)
|
|
293
|
+
cnt = -1
|
|
294
|
+
for i in range(no_clust[0], no_clust[1] + 1):
|
|
295
|
+
smtmp = np.zeros(i)
|
|
296
|
+
for j in range(i):
|
|
297
|
+
cnt = cnt + 1
|
|
298
|
+
smtmp = dummy_mod[cnt]
|
|
299
|
+
startmfix = {i: smtmp}
|
|
300
|
+
|
|
301
|
+
cnt = -1
|
|
302
|
+
dat_out = [Clust() for i in range(no_clust[0], no_clust[1]+1)]
|
|
303
|
+
|
|
304
|
+
for i in range(no_clust[0], no_clust[1]+1):
|
|
305
|
+
self.reportback('Number of Clusters:'+str(i))
|
|
306
|
+
cnt = cnt + 1
|
|
307
|
+
if self.radiobutton_datadriven.isChecked() is True:
|
|
308
|
+
self.reportback('Initial guess: data driven')
|
|
309
|
+
no_samp = dat_in.shape[0]
|
|
310
|
+
dno_samp = no_samp/i
|
|
311
|
+
# idx=1
|
|
312
|
+
# idx=[[idx,(j-1)*dno_samp] for j in range(2,i+1)]
|
|
313
|
+
idx = np.arange(0, no_samp+dno_samp, dno_samp)
|
|
314
|
+
idx[0] = 1
|
|
315
|
+
# idx=np.array([idx,no_samp])
|
|
316
|
+
startmdat = {i: np.zeros([i, dat_in.shape[1]])}
|
|
317
|
+
dat_in1 = dat_in
|
|
318
|
+
smtmp = np.zeros([i, dat_in.shape[1]])
|
|
319
|
+
for k in range(dat_in.shape[1]):
|
|
320
|
+
for j in range(i):
|
|
321
|
+
smtmp[j, k] = np.median(dat_in1[idx[j]:idx[j+1], k])
|
|
322
|
+
startmdat = {i: smtmp}
|
|
323
|
+
startmfix = {i: []}
|
|
324
|
+
del dat_in1
|
|
325
|
+
|
|
326
|
+
clidx, clcent, clobj_fcn, clvrc = self.crisp_means(
|
|
327
|
+
dat_in, i, startmdat[i], startmfix[i], max_iter,
|
|
328
|
+
term_thresh, cltype, cov_constr)
|
|
329
|
+
|
|
330
|
+
elif self.radiobutton_manual.isChecked() is True:
|
|
331
|
+
|
|
332
|
+
self.reportback('Initial guess: manual')
|
|
333
|
+
|
|
334
|
+
clidx, clcent, clobj_fcn, clvrc = self.crisp_means(
|
|
335
|
+
dat_in, i, startmdat[i], startmfix[i], max_iter,
|
|
336
|
+
term_thresh, cltype, cov_constr)
|
|
337
|
+
|
|
338
|
+
elif self.radiobutton_random.isChecked() is True:
|
|
339
|
+
self.reportback('Initial guess: random')
|
|
340
|
+
|
|
341
|
+
clobj_fcn = np.array([np.inf])
|
|
342
|
+
for j in range(no_runs):
|
|
343
|
+
self.reportback('Run '+str(j)+' of'+str(no_runs))
|
|
344
|
+
|
|
345
|
+
xmins = np.minimum(dat_in, 1)
|
|
346
|
+
xmaxs = np.maximum(dat_in, 1)
|
|
347
|
+
startm1dat = {i: np.random.uniform(
|
|
348
|
+
xmins[np.zeros(i, int), :],
|
|
349
|
+
xmaxs[np.zeros(i, int), :])}
|
|
350
|
+
startmfix = {i: np.array([])}
|
|
351
|
+
clidx1, clcent1, clobj_fcn1, clvrc1 = self.crisp_means(
|
|
352
|
+
dat_in, i, startm1dat[i], startmfix[i], max_iter,
|
|
353
|
+
term_thresh, cltype, cov_constr)
|
|
354
|
+
|
|
355
|
+
if clobj_fcn1[-1] < clobj_fcn[-1]:
|
|
356
|
+
clidx = clidx1
|
|
357
|
+
clcent = clcent1
|
|
358
|
+
clobj_fcn = clobj_fcn1
|
|
359
|
+
clvrc = clvrc1
|
|
360
|
+
startmdat = {i: startm1dat[i]}
|
|
361
|
+
|
|
362
|
+
# zonal = np.zeros(data[0].data.shape)-9999.0
|
|
363
|
+
zonal = np.ma.masked_all(data[0].data.shape)
|
|
364
|
+
|
|
365
|
+
alpha = (data[0].data.mask == 0)
|
|
366
|
+
zonal[alpha == 1] = clidx
|
|
367
|
+
|
|
368
|
+
cent_std = np.array([np.std(dat_in[clidx == k], 0)
|
|
369
|
+
for k in range(i)])
|
|
370
|
+
|
|
371
|
+
den_cent = clcent
|
|
372
|
+
den_cent_std = np.array(cent_std, copy=True)
|
|
373
|
+
den_cent_std1 = np.array(cent_std, copy=True)
|
|
374
|
+
if de_norm is True:
|
|
375
|
+
for k in range(len(data)):
|
|
376
|
+
if np.size(data[k].norm) > 0:
|
|
377
|
+
nnorm = len(data[k].norm)
|
|
378
|
+
for j in range(nnorm, 0, -1):
|
|
379
|
+
if data[k].norm[j-1]['type'] == 'minmax':
|
|
380
|
+
den_cent[:, k] = (
|
|
381
|
+
den_cent[:, k] *
|
|
382
|
+
(data[k].norm[j-1]['transform'][1, 1] -
|
|
383
|
+
data[k].norm[j-1]['transform'][0, 1]) +
|
|
384
|
+
data[k].norm[j-1]['transform'][0, 1])
|
|
385
|
+
den_cent_std[:, k] = (
|
|
386
|
+
den_cent_std[:, k] *
|
|
387
|
+
(data[k].norm[j-1]['transform'][1, 1] -
|
|
388
|
+
data[k].norm[j-1]['transform'][0, 1]) +
|
|
389
|
+
data[k].norm[j-1]['transform'][0, 1])
|
|
390
|
+
den_cent_std1[:, k] = (
|
|
391
|
+
den_cent_std1[:, k] *
|
|
392
|
+
(data[k].norm[j-1]['transform'][1, 1] -
|
|
393
|
+
data[k].norm[j-1]['transform'][0, 1]) +
|
|
394
|
+
data[k].norm[j-1]['transform'][0, 1])
|
|
395
|
+
elif (data[k].norm[j-1]['type'] == 'meanstd' or
|
|
396
|
+
data[k].norm[j-1]['type'] == 'medmad'):
|
|
397
|
+
den_cent[:, k] = (
|
|
398
|
+
den_cent[:, k] *
|
|
399
|
+
data[k].norm[j-1]['transform'][1, 1] +
|
|
400
|
+
data[k].norm[j-1]['transform'][0, 1])
|
|
401
|
+
den_cent_std[:, k] = (
|
|
402
|
+
den_cent_std[:, k] *
|
|
403
|
+
data[k].norm[j-1]['transform'][1, 1] +
|
|
404
|
+
data[k].norm[j-1]['transform'][0, 1])
|
|
405
|
+
den_cent_std1[:, k] = (
|
|
406
|
+
den_cent_std1[:, k] *
|
|
407
|
+
data[k].norm[j-1]['transform'][1, 1] +
|
|
408
|
+
data[k].norm[j-1]['transform'][0, 1])
|
|
409
|
+
elif data[k].norm[j-1]['type'] == 'histeq':
|
|
410
|
+
den_cent[:, k] = np.interp(
|
|
411
|
+
den_cent[:, k],
|
|
412
|
+
data[k].norm[j-1]['transform'][:, 0],
|
|
413
|
+
data[k].norm[j-1]['transform'][:, 1])
|
|
414
|
+
den_cent_std[:, k] = np.interp(
|
|
415
|
+
(den_cent[:, k] + den_cent_std[:, k]),
|
|
416
|
+
data[k].norm[j-1]['transform'][:, 0],
|
|
417
|
+
data[k].norm[j-1]['transform'][:, 1])
|
|
418
|
+
den_cent_std1[:, k] = np.interp(
|
|
419
|
+
(den_cent[:, k] - den_cent_std1[:, k]),
|
|
420
|
+
data[k].norm[j-1]['transform'][:, 0],
|
|
421
|
+
data[k].norm[j-1]['transform'][:, 1])
|
|
422
|
+
else:
|
|
423
|
+
den_cent = np.array([])
|
|
424
|
+
den_cent_std = np.array([])
|
|
425
|
+
den_cent_std1 = np.array([])
|
|
426
|
+
|
|
427
|
+
for k in data:
|
|
428
|
+
dat_out[cnt].input_type.append(k.dataid)
|
|
429
|
+
# dat_out[cnt].proc_history.append(k.proc)
|
|
430
|
+
|
|
431
|
+
dat_out[cnt].data = zonal
|
|
432
|
+
# dat_out[cnt].data.mask = masktmp
|
|
433
|
+
dat_out[cnt].nullvalue = zonal.fill_value
|
|
434
|
+
dat_out[cnt].no_clusters = i
|
|
435
|
+
dat_out[cnt].center = clcent # These are arrays
|
|
436
|
+
dat_out[cnt].center_std = cent_std # These are arrays
|
|
437
|
+
dat_out[cnt].obj_fcn = clobj_fcn
|
|
438
|
+
dat_out[cnt].vrc = clvrc
|
|
439
|
+
|
|
440
|
+
# dat_out[cnt].type = self.type
|
|
441
|
+
# dat_out[cnt].algorithm = cltype
|
|
442
|
+
# dat_out[cnt].initialization = init_type
|
|
443
|
+
# dat_out[cnt].init_mod = startmdat[i]
|
|
444
|
+
# dat_out[cnt].init_constrains = startmfix[i]
|
|
445
|
+
# dat_out[cnt].runs = no_runs
|
|
446
|
+
# dat_out[cnt].max_iterations = max_iter
|
|
447
|
+
# dat_out[cnt].denormalize = de_norm
|
|
448
|
+
# dat_out[cnt].term_threshold = term_thresh
|
|
449
|
+
# dat_out[cnt].shape_constrain = cov_constr
|
|
450
|
+
# dat_out[cnt].zonal = zonal
|
|
451
|
+
# dat_out[cnt].alpha = alpha
|
|
452
|
+
# dat_out[cnt].xxx = data[0].xxx
|
|
453
|
+
# dat_out[cnt].yyy = data[0].yyy
|
|
454
|
+
# dat_out[cnt].denorm_center = den_cent
|
|
455
|
+
# dat_out[cnt].denorm_center_stdup = den_cent_std
|
|
456
|
+
# dat_out[cnt].denorm_center_stdlow = den_cent_std1
|
|
457
|
+
# dat_out[cnt].iterations = clobj_fcn.size
|
|
458
|
+
|
|
459
|
+
self.log = ("Crisp Cluster complete" + ' (' + self.cltype + ' ' +
|
|
460
|
+
self.init_type+')')
|
|
461
|
+
|
|
462
|
+
for i in dat_out:
|
|
463
|
+
i.tlx = data[0].tlx
|
|
464
|
+
i.tly = data[0].tly
|
|
465
|
+
i.xdim = data[0].xdim
|
|
466
|
+
i.ydim = data[0].ydim
|
|
467
|
+
i.nrofbands = 1
|
|
468
|
+
i.dataid = 'Crisp Cluster: '+str(i.no_clusters)
|
|
469
|
+
i.rows = data[0].rows
|
|
470
|
+
i.cols = data[0].cols
|
|
471
|
+
i.nullvalue = data[0].nullvalue
|
|
472
|
+
|
|
473
|
+
self.reportback("Crisp Cluster complete" + ' ('+self.cltype + ' ' +
|
|
474
|
+
self.init_type+')')
|
|
475
|
+
|
|
476
|
+
self.outdata['Cluster'] = dat_out
|
|
477
|
+
return True
|
|
478
|
+
|
|
479
|
+
def crisp_means(self, data, no_clust, cent, centfix, maxit, term_thresh,
|
|
480
|
+
cltype, cov_constr):
|
|
481
|
+
""" Crisp Means """
|
|
482
|
+
|
|
483
|
+
# [idx, cent, obj_fcn] = crisp_means(data, no_clust, cent, maxit, term_thresh,
|
|
484
|
+
# cltype, cov_constr)
|
|
485
|
+
|
|
486
|
+
# script enables the crisp clustering of COMPLETE multi-variate datasets.
|
|
487
|
+
# (no attributes missing!!!!!!!!!)
|
|
488
|
+
|
|
489
|
+
# NOTE: All input arguments must be provided, even if they are empty!!!!
|
|
490
|
+
# DATA: NxP matrix containing the data to be clustered, N is number of
|
|
491
|
+
# samples, P is number of different attributes availabe for each sample
|
|
492
|
+
# NO_CLUST: number of clusters to be used
|
|
493
|
+
# CENT: cluster centre positions, either empty [] --> randomly
|
|
494
|
+
# guess center positions will be used for initialisation or NO_CLUSTxP
|
|
495
|
+
# matrix
|
|
496
|
+
# CENTFIX: Constrains the position of cluster centers, if centfix is empty,
|
|
497
|
+
# cluster centers can freely vary during cluster analysis, otherwise
|
|
498
|
+
# CENTFIX is of equal size to CENT and gives an absolut deviation from
|
|
499
|
+
# initial center positions that should not be exceeded during clustering.
|
|
500
|
+
# Note, CETNFIX applies only if center values are provided by the user
|
|
501
|
+
# MAXIT: number of maximal allowed iterations
|
|
502
|
+
# TERM_THRESH: Termination threshold, either empty [] --> go for the maximum
|
|
503
|
+
# number of iterations MAXIT or
|
|
504
|
+
# a scalar giving the minimum reduction of the size of the objective function
|
|
505
|
+
# for two consecutive iterations in Percent
|
|
506
|
+
# CLTYPE: either 'kmeans' --> kmeans cluster analysis (spherically shaped
|
|
507
|
+
# cluster), 'det' --> uses the determinant criterion of Spath, H.,
|
|
508
|
+
# "Cluster-Formation and Analyse, chapter3" (ellipsoidal clusters, all
|
|
509
|
+
# cluster use the same ellipsoid), or 'vardet' --> Spath, H., chapter 4
|
|
510
|
+
# (each cluster uses its individual ellipsoid) Note: the latter is the
|
|
511
|
+
# crisp version of the Gustafson-Kessel algorithm
|
|
512
|
+
# COV_CONSTR: scalar between [0 1], values >0 trimm the covariance matrix
|
|
513
|
+
# to avoid needle-like ellpsoids for the clusters, applies only for
|
|
514
|
+
# CLTYPE='vardet', but must always be provided
|
|
515
|
+
|
|
516
|
+
# IDX: cluster index number for each sample after the last iteration, column
|
|
517
|
+
# vector
|
|
518
|
+
# CENT: matrix with cluster centre positions after last iteration, one cluster
|
|
519
|
+
# centre per row
|
|
520
|
+
# OBJ_FCN: Vector, size of the objective function after each iteration
|
|
521
|
+
# VRC: Variance Ratio Criterion
|
|
522
|
+
self.reportback(' ')
|
|
523
|
+
|
|
524
|
+
no_samples = data.shape[0]
|
|
525
|
+
if cent.size == 0: # if no center values are provided
|
|
526
|
+
xmins = np.minimum(data, 1)
|
|
527
|
+
xmaxs = np.maximum(data, 1)
|
|
528
|
+
cent = np.random.uniform(xmins[np.zeros(no_clust, int), :],
|
|
529
|
+
xmaxs[np.zeros(no_clust, int), :])
|
|
530
|
+
centfix = np.array([])
|
|
531
|
+
|
|
532
|
+
cent_orig = cent
|
|
533
|
+
centfix = np.abs(centfix)
|
|
534
|
+
|
|
535
|
+
# calculate euclidian distance for initial classification
|
|
536
|
+
onetmp = np.ones([no_samples, 1], int) # trying this for speed?
|
|
537
|
+
edist = np.array([np.sqrt(np.sum(((data-onetmp*cent[j])**2), 1))
|
|
538
|
+
for j in range(no_clust)]) # initial distance -->
|
|
539
|
+
# Euclidian
|
|
540
|
+
|
|
541
|
+
mindist = edist.min(0) # 0 means row wize minimum
|
|
542
|
+
idx = edist.argmin(0)
|
|
543
|
+
|
|
544
|
+
# initial size of objective function
|
|
545
|
+
obj_fcn_initial = np.sum(mindist**2)
|
|
546
|
+
obj_fcn_prev = obj_fcn_initial
|
|
547
|
+
obj_fcn = np.zeros(maxit) # This is new - we must initialize this.
|
|
548
|
+
|
|
549
|
+
for i in self.pbar.iter(range(maxit)): # =1:maxit. loop over all iterations
|
|
550
|
+
cent_prev = cent # store result of last iteration
|
|
551
|
+
idx_prev = idx
|
|
552
|
+
dist_prev = edist
|
|
553
|
+
# calc new cluster centre positions
|
|
554
|
+
cent, idx = self.gcentroids(data, idx, no_clust, mindist)
|
|
555
|
+
# constrain the cluster center positions to keep it in the given interval
|
|
556
|
+
if centfix.size > 0:
|
|
557
|
+
# constrain the center positions within the given limits
|
|
558
|
+
cent_idx = cent > (cent_orig+centfix)
|
|
559
|
+
cent[cent_idx == 1] = (cent_orig(cent_idx == 1) +
|
|
560
|
+
centfix(cent_idx == 1))
|
|
561
|
+
cent_idx = cent < (cent_orig-centfix)
|
|
562
|
+
cent[cent_idx == 1] = (cent_orig(cent_idx == 1) -
|
|
563
|
+
centfix(cent_idx == 1))
|
|
564
|
+
|
|
565
|
+
# calc new cluster centre distances
|
|
566
|
+
edist = self.gdist(data, cent, idx, no_clust, cltype, cov_constr)
|
|
567
|
+
# get new index values for each data point and the distance from each
|
|
568
|
+
# sample to its cluster center
|
|
569
|
+
mindist = edist.min(0)
|
|
570
|
+
idx = edist.argmin(0)
|
|
571
|
+
|
|
572
|
+
# calc new objective function size
|
|
573
|
+
obj_fcn[i] = np.sum(mindist**2)
|
|
574
|
+
|
|
575
|
+
self.reportback('Iteration: ' + str(i) + ' Threshold: ' +
|
|
576
|
+
str(term_thresh) + ' Current: ' +
|
|
577
|
+
'{:.2e}'.format(100 *
|
|
578
|
+
((obj_fcn_prev-obj_fcn[i]) /
|
|
579
|
+
obj_fcn[i])), True)
|
|
580
|
+
# if no termination threshold provided, ignore this and do all iterations
|
|
581
|
+
if term_thresh > 0:
|
|
582
|
+
# if the improvement between the last two iterations was less
|
|
583
|
+
# than a defined threshold in percent
|
|
584
|
+
if (100*((obj_fcn_prev-obj_fcn[i])/obj_fcn[i]) < term_thresh
|
|
585
|
+
or obj_fcn[i] > obj_fcn_prev):
|
|
586
|
+
# go back to the results of the previous iteration
|
|
587
|
+
idx = idx_prev
|
|
588
|
+
cent = cent_prev
|
|
589
|
+
edist = dist_prev
|
|
590
|
+
if i == 0:
|
|
591
|
+
obj_fcn = obj_fcn_prev
|
|
592
|
+
else:
|
|
593
|
+
# changed from i-1 to i for w-means
|
|
594
|
+
obj_fcn = np.delete(obj_fcn, np.s_[i::])
|
|
595
|
+
# vrc=vr.var_ratio(data, idx, cent, edist)
|
|
596
|
+
break # and stop the clustering right now
|
|
597
|
+
obj_fcn_prev = obj_fcn[i]
|
|
598
|
+
vrc = vr.var_ratio(data, idx, cent, edist)
|
|
599
|
+
return idx, cent, obj_fcn, vrc
|
|
600
|
+
|
|
601
|
+
# -----------------------------------------------------------------------------
|
|
602
|
+
def gdist(self, data, center, index, no_clust, cltype, cov_constr):
|
|
603
|
+
""" Gdist routine """
|
|
604
|
+
no_samples = data.shape[0]
|
|
605
|
+
no_datasets = data.shape[1]
|
|
606
|
+
bigd = np.zeros([no_clust, no_samples])
|
|
607
|
+
ddd = []
|
|
608
|
+
if cltype == 'k-means':
|
|
609
|
+
onetmp = np.ones([no_samples, 1]) # trying this for speed?
|
|
610
|
+
for j in range(no_clust):
|
|
611
|
+
# Euclidian
|
|
612
|
+
bigd[j] = np.sqrt(np.sum(((data-onetmp*center[j])**2), 1))
|
|
613
|
+
# determinant criterion see Spath, Helmuth,
|
|
614
|
+
# "Cluster-Formation and Analyse", chapter 3
|
|
615
|
+
elif cltype == 'advanced k-means':
|
|
616
|
+
for j in range(no_clust):
|
|
617
|
+
# difference between each sample attribute to the corresponding
|
|
618
|
+
# attribute of the j-th cluster
|
|
619
|
+
dcent = data-np.ones([no_samples, 1])*center[j]
|
|
620
|
+
# grab the data belonging to cluster j
|
|
621
|
+
mod_idx = (index == j)*1
|
|
622
|
+
# should I use different transpose?
|
|
623
|
+
# Streuungsmatrix/ covariance of the j-th cluster
|
|
624
|
+
mat_a = np.dot(np.ones([no_datasets, 1])*mod_idx*dcent.T,
|
|
625
|
+
dcent/np.sum(mod_idx))
|
|
626
|
+
# constrain covariance matrix if badly conditioned
|
|
627
|
+
if np.linalg.cond(mat_a) > 1e10:
|
|
628
|
+
# warning([' Badly conditionend covariance matrix \
|
|
629
|
+
# (cond. number > 1e10) of cluster ',num2unicode(j)]);
|
|
630
|
+
ed1, ev1 = np.linalg.eig(mat_a)
|
|
631
|
+
edmax = np.max(ed1)
|
|
632
|
+
ed1[1e10*ed1 < edmax] = edmax/1e10
|
|
633
|
+
mat_a = np.dot(np.dot(ev1, (ed1*np.eye(no_datasets))),
|
|
634
|
+
np.linalg.inv(ev1))
|
|
635
|
+
if j == 0: # sum all covariance matrices for all clusters
|
|
636
|
+
mat_a0 = mat_a
|
|
637
|
+
else:
|
|
638
|
+
mat_a0 = mat_a0 + mat_a
|
|
639
|
+
# calc new distances using the same covariance matrix for all clusters -->
|
|
640
|
+
# ellisoidal clusters, all clusters use equal ellipsoids
|
|
641
|
+
for j in range(no_clust):
|
|
642
|
+
# difference between each sample attribute to the corresponding
|
|
643
|
+
# attribute of the j-th cluster
|
|
644
|
+
dcent = data-np.ones([no_samples, 1])*center[j]
|
|
645
|
+
# does this need to be in this loop?
|
|
646
|
+
mbig = (np.linalg.det(mat_a0)**(1.0/no_datasets) *
|
|
647
|
+
np.linalg.pinv(mat_a0))
|
|
648
|
+
ddd.append(np.sum((np.dot(dcent, mbig)*dcent), 1).T)
|
|
649
|
+
bigd = np.sqrt(ddd)
|
|
650
|
+
# cluster adapted determinant criterion see Spath, Helmuth,
|
|
651
|
+
# "Cluster-Formation and Analyse", chapter 4 --> equivalent to crisp GK
|
|
652
|
+
# algorithm
|
|
653
|
+
elif cltype == 'w-means':
|
|
654
|
+
for j in range(no_clust):
|
|
655
|
+
# difference between each sample attribute to the corresponding
|
|
656
|
+
# attribute of the j-th cluster
|
|
657
|
+
dcent = data-np.ones([no_samples, 1])*center[j]
|
|
658
|
+
mod_idx = (index == j)*1 # grab data belonging to cluster j
|
|
659
|
+
# '*dcent/sum(mod_idx); % Streuungsmatrix/ covariance of the j-th cluster
|
|
660
|
+
mat_a = np.dot(np.ones([no_datasets, 1])*mod_idx*dcent.T,
|
|
661
|
+
dcent/np.sum(mod_idx))
|
|
662
|
+
mat_a0 = np.eye(mat_a.shape[0])
|
|
663
|
+
# if cov_constr>0, this enforces not to elongated ellipsoids -->
|
|
664
|
+
# avoid the needle-like cluster
|
|
665
|
+
mat_a = (1-cov_constr)*mat_a+cov_constr*(mat_a0/no_samples)
|
|
666
|
+
# constrain covariance matrix if badly conditioned and cluster contains
|
|
667
|
+
# more than 1 sample
|
|
668
|
+
if np.linalg.cond(mat_a) > 1e10 and np.sum(mod_idx) > 1:
|
|
669
|
+
# warning([' Badly conditionend covariance matrix '+
|
|
670
|
+
# '(cond. number > 1e10) of cluster ',num2unicode(j)])
|
|
671
|
+
ed1, ev1 = np.linalg.eig(mat_a)
|
|
672
|
+
edmax = np.max(ed1)
|
|
673
|
+
ed1[1e10*ed1 < edmax] = edmax/1e10
|
|
674
|
+
mat_a = np.dot(np.dot(ev1, (ed1*np.eye(no_datasets))),
|
|
675
|
+
np.linalg.inv(ev1))
|
|
676
|
+
# assume spherical shape of clusters with only one sample
|
|
677
|
+
elif np.sum(mod_idx) == 1:
|
|
678
|
+
mat_a = mat_a0
|
|
679
|
+
mbig = (np.linalg.det(mat_a)**(1.0/no_datasets) *
|
|
680
|
+
np.linalg.pinv(mat_a))
|
|
681
|
+
# calc cluster to sample distances using mahalanobis distance for each
|
|
682
|
+
# cluster, ellipsoidal clusters, each cluster has its own individually
|
|
683
|
+
# oriented and shaped ellipsoid
|
|
684
|
+
ddd.append(np.sum((np.dot(dcent, mbig)*dcent), 1).T)
|
|
685
|
+
bigd = np.sqrt(ddd)
|
|
686
|
+
# end
|
|
687
|
+
return bigd
|
|
688
|
+
|
|
689
|
+
# -----------------------------------------------------------------------------
|
|
690
|
+
def gcentroids(self, data, index, no_clust, mindist):
|
|
691
|
+
"""Gcentroids"""
|
|
692
|
+
# no_samples=data.shape[0]
|
|
693
|
+
no_datatypes = data.shape[1]
|
|
694
|
+
centroids = np.tile(np.nan, (no_clust, no_datatypes))
|
|
695
|
+
for j in range(no_clust):
|
|
696
|
+
# find all members of the j-th cluster
|
|
697
|
+
members = (index == j).nonzero()[0]
|
|
698
|
+
# if j is an empty cluster, put one sample into this cluster
|
|
699
|
+
if members.size == 0:
|
|
700
|
+
# take the sample that has the greatest distance to its current
|
|
701
|
+
# cluster and make this the center of the j-th cluster
|
|
702
|
+
idx1 = mindist.argmax(0)
|
|
703
|
+
centroids[j] = data[idx1]
|
|
704
|
+
index[idx1] = j
|
|
705
|
+
mindist[idx1] = 0
|
|
706
|
+
else:
|
|
707
|
+
centroids[j] = data[members].mean(0)
|
|
708
|
+
return centroids, index
|