mirror of
https://github.com/meteoinfo/MeteoInfo.git
synced 2025-12-08 20:36:05 +00:00
add jenks nature breaks module
This commit is contained in:
parent
7a3e2e606c
commit
87f4309869
@ -21,7 +21,7 @@ public class Popup extends JWindow {
|
||||
private final static int MAX_HEIGHT = 300;
|
||||
private final static int MIN_WIDTH = 200;
|
||||
private final static int MAX_WIDTH = 400;
|
||||
private final JTextComponent textCompnent;
|
||||
private final JTextComponent textComponent;
|
||||
private int dotPosition;
|
||||
private final JList list;
|
||||
private String[] originalData;
|
||||
@ -36,7 +36,7 @@ public class Popup extends JWindow {
|
||||
*/
|
||||
public Popup(JFrame frame, JTextComponent textComponent){
|
||||
super(frame);
|
||||
this.textCompnent = textComponent;
|
||||
this.textComponent = textComponent;
|
||||
this.setSize(200, 200);
|
||||
this.list = new JList();
|
||||
this.list.addKeyListener(new KeyAdapter(){
|
||||
@ -86,7 +86,7 @@ public class Popup extends JWindow {
|
||||
|
||||
// @Override
|
||||
// public void show(){
|
||||
// this.dotPosition = this.textCompnent.getCaretPosition();
|
||||
// this.dotPosition = this.textComponent.getCaretPosition();
|
||||
// this.setSize(this.getPreferredSize());
|
||||
// //super.show();
|
||||
// this.setVisible(true);
|
||||
@ -97,12 +97,12 @@ public class Popup extends JWindow {
|
||||
this.setLocation(displayPoint);
|
||||
this.setBounds(displayPoint.x, displayPoint.y, size.width, size.height);
|
||||
this.setMethods(list);
|
||||
if (this.textCompnent != null)
|
||||
this.dotPosition = this.textCompnent.getCaretPosition();
|
||||
if (this.textComponent != null)
|
||||
this.dotPosition = this.textComponent.getCaretPosition();
|
||||
//this.show();
|
||||
this.setVisible(true);
|
||||
this.list.setSelectedIndex(0);
|
||||
this.setAlwaysOnTop(true);
|
||||
//this.setAlwaysOnTop(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,11 +113,11 @@ public class Popup extends JWindow {
|
||||
Dimension size = this.getPreferredSize();
|
||||
this.setLocation(displayPoint);
|
||||
this.setBounds(displayPoint.x, displayPoint.y, size.width, size.height);
|
||||
if (this.textCompnent != null)
|
||||
this.dotPosition = this.textCompnent.getCaretPosition();
|
||||
if (this.textComponent != null)
|
||||
this.dotPosition = this.textComponent.getCaretPosition();
|
||||
this.setVisible(true);
|
||||
this.list.setSelectedIndex(0);
|
||||
this.setAlwaysOnTop(true);
|
||||
//this.setAlwaysOnTop(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,12 +201,12 @@ public class Popup extends JWindow {
|
||||
Object value = this.list.getSelectedValue();
|
||||
if (value != null){
|
||||
int startPosition = this.dotPosition;
|
||||
int caretPosition = this.textCompnent.getCaretPosition();
|
||||
this.textCompnent.select(startPosition, caretPosition) ;
|
||||
this.textCompnent.replaceSelection(value.toString());
|
||||
int caretPosition = this.textComponent.getCaretPosition();
|
||||
this.textComponent.select(startPosition, caretPosition) ;
|
||||
this.textComponent.replaceSelection(value.toString());
|
||||
caretPosition = startPosition + value.toString().length();
|
||||
try {
|
||||
this.textCompnent.setCaretPosition(caretPosition);
|
||||
this.textComponent.setCaretPosition(caretPosition);
|
||||
} catch (Exception e){
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public class Tip extends JWindow {
|
||||
this.textarea.setEditable(false);
|
||||
JScrollPane jscrollpane = new JScrollPane(this.textarea);
|
||||
this.getContentPane().add(jscrollpane);
|
||||
this.setAlwaysOnTop(true);
|
||||
//this.setAlwaysOnTop(true);
|
||||
}
|
||||
// </editor-fold>
|
||||
// <editor-fold desc="Get Set Methods">
|
||||
|
||||
@ -46,6 +46,7 @@ import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
private MITextEditorPane _textArea;
|
||||
private String _title;
|
||||
private File _file = null;
|
||||
private Font font;
|
||||
private JTabbedPane _parent;
|
||||
// </editor-fold>
|
||||
// <editor-fold desc="Constructor">
|
||||
@ -244,6 +245,26 @@ import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
* @param font The font to use.
|
||||
*/
|
||||
public void setTextFont(Font font) {
|
||||
if (font != null) {
|
||||
this.font = font;
|
||||
SyntaxScheme ss = _textArea.getSyntaxScheme();
|
||||
ss = (SyntaxScheme) ss.clone();
|
||||
for (int i = 0; i < ss.getStyleCount(); i++) {
|
||||
if (ss.getStyle(i) != null) {
|
||||
ss.getStyle(i).font = font;
|
||||
}
|
||||
}
|
||||
_textArea.setSyntaxScheme(ss);
|
||||
_textArea.setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the font for all token types.
|
||||
*
|
||||
* @param font The font to use.
|
||||
*/
|
||||
public void updateTextFont() {
|
||||
if (font != null) {
|
||||
SyntaxScheme ss = _textArea.getSyntaxScheme();
|
||||
ss = (SyntaxScheme) ss.clone();
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<MeteoInfo File="milconfig.xml" Type="configurefile">
|
||||
<Path OpenPath="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui">
|
||||
<RecentFolder Folder="D:\Run\emips"/>
|
||||
<RecentFolder Folder="D:\Run\emips\run_meic"/>
|
||||
<RecentFolder Folder="D:\Run\emips\test"/>
|
||||
<Path OpenPath="D:\Working\MIScript\Jython\mis\common_math\stats">
|
||||
<RecentFolder Folder="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\grads"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\annotate"/>
|
||||
@ -15,33 +11,32 @@
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\boxplot"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\funny"/>
|
||||
<RecentFolder Folder="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\emips"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\stats"/>
|
||||
</Path>
|
||||
<File>
|
||||
<OpenedFiles>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\main_gui.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\_reload.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\emission_panel.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\vertical_panel.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\temporal_panel.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\chemical_panel.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\spatial_panel.py"/>
|
||||
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\run_panel.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\common_math\stats\jenks_breaks.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\common_math\stats\jenks_breaks_2.py"/>
|
||||
</OpenedFiles>
|
||||
<RecentFiles>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\main_gui.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\_reload.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\emission_panel.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\vertical_panel.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\temporal_panel.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\chemical_panel.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\spatial_panel.py"/>
|
||||
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\run_panel.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\common_math\stats\jenks_breaks.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\common_math\stats\jenks_breaks_2.py"/>
|
||||
</RecentFiles>
|
||||
</File>
|
||||
<Font>
|
||||
<TextFont FontName="YaHei Consolas Hybrid" FontSize="14"/>
|
||||
</Font>
|
||||
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatLightLaf"/>
|
||||
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
|
||||
<Figure DoubleBuffering="true"/>
|
||||
<Startup MainFormLocation="-7,-7" MainFormSize="1293,685"/>
|
||||
</MeteoInfo>
|
||||
|
||||
Binary file not shown.
@ -2,8 +2,10 @@ from .stats import *
|
||||
from .distributions import *
|
||||
from ._multivariate import *
|
||||
from .kde import GaussianKDE
|
||||
from ._jenks import *
|
||||
|
||||
__all__ = []
|
||||
__all__ += stats.__all__
|
||||
__all__ += distributions.__all__
|
||||
__all__ += _multivariate.__all__
|
||||
__all__ += _multivariate.__all__
|
||||
__all__ += _jenks.__all__
|
||||
|
||||
133
meteoinfo-lab/pylib/mipylib/numeric/stats/_jenks.py
Normal file
133
meteoinfo-lab/pylib/mipylib/numeric/stats/_jenks.py
Normal file
@ -0,0 +1,133 @@
|
||||
from org.meteoinfo.math.stats import StatsUtil, Jenks
|
||||
|
||||
from ..core import numeric as np
|
||||
|
||||
__all__ = ["jenks_breaks", "JenksNaturalBreaks"]
|
||||
|
||||
|
||||
class JenksNaturalBreaks(object):
|
||||
"""
|
||||
A class that can be used to classify a sequence of numbers into groups (clusters) using Fisher-Jenks natural breaks.
|
||||
"""
|
||||
|
||||
def __init__(self, n_classes=6):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
n_classes : int
|
||||
The number of classes to be generated by the classifier.
|
||||
"""
|
||||
self.n_classes = n_classes
|
||||
|
||||
def __repr__(self):
|
||||
return "JenksNaturalBreaks(n_classes={})".format(self.n_classes)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def fit(self, x):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
x : array-like
|
||||
The sequence of numbers (integer/float) to be classified.
|
||||
"""
|
||||
x = np.asarray(x)
|
||||
|
||||
self._jenks = Jenks()
|
||||
self._jenks.addValues(x.asarray())
|
||||
self._breaks = self._jenks.computeBreaks(self.n_classes)
|
||||
self.breaks_ = np.array(self._breaks.getClassValues())
|
||||
self.inner_breaks_ = self.breaks_[1:-1] # because inner_breaks is more
|
||||
self.labels_ = self.predict(x)
|
||||
self.groups_ = self.group(x)
|
||||
|
||||
def predict(self, x):
|
||||
"""
|
||||
Predicts the class of each element in x.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : scalar or array-like
|
||||
|
||||
Returns
|
||||
-------
|
||||
array
|
||||
"""
|
||||
x = np.asarray(x)
|
||||
r = self._breaks.classOf(x.asarray())
|
||||
return np.array(r)
|
||||
|
||||
def group(self, x):
|
||||
"""
|
||||
Groups the elements in x into groups according to the classifier.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array-like
|
||||
The sequence of numbers (integer/float) to be classified.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list of numpy.array
|
||||
The list of groups that contains the values of x.
|
||||
"""
|
||||
arr = np.array(x)
|
||||
groups_ = [arr[arr <= self.inner_breaks_[0]]]
|
||||
for idx in range(len(self.inner_breaks_))[:-1]:
|
||||
groups_.append(arr[(arr > self.inner_breaks_[idx]) & (arr <= self.inner_breaks_[idx + 1])])
|
||||
groups_.append(arr[arr > self.inner_breaks_[-1]])
|
||||
return groups_
|
||||
|
||||
def goodness_of_variance_fit(self, x):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
x : array-like
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The goodness of variance fit.
|
||||
"""
|
||||
gvf = self._breaks.gvf()
|
||||
return gvf
|
||||
|
||||
def get_label_(self, val):
|
||||
"""
|
||||
Compute the group label of the given value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
val : float
|
||||
The value to be classified.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int : The label of the value.
|
||||
"""
|
||||
return self._breaks.classOf(val)
|
||||
|
||||
|
||||
def jenks_breaks(a, n_classes, gvf=False):
|
||||
"""
|
||||
Compute natural breaks (Fisher-Jenks algorithm) on a sequence of `values`,
|
||||
given `n_classes`, the number of desired class.
|
||||
|
||||
:param a: (*array*) Input data array.
|
||||
:param n_classes: (*int*) The number of desired class.
|
||||
:param gvf: (*float*) Whether return gvf (Goodness of Variance Fit) value. Default is `False`.
|
||||
|
||||
:return: (*array*) The computed break values, including minimum and maximum, in order
|
||||
to have all the bounds for building `n_classes` classes,
|
||||
so the returned list has a length of `n_classes` + 1.
|
||||
"""
|
||||
if isinstance(a, (list, tuple)):
|
||||
a = np.array(a)
|
||||
|
||||
if gvf:
|
||||
r = StatsUtil.jenksBreaksGvf(a._array, n_classes)
|
||||
return np.array(r[0]), r[1]
|
||||
else:
|
||||
r = StatsUtil.jenksBreaks(a._array, n_classes)
|
||||
return np.array(r)
|
||||
Binary file not shown.
@ -2,6 +2,7 @@ from ..core import numeric as np
|
||||
import stats
|
||||
from ..linalg import linalg
|
||||
|
||||
|
||||
class GaussianKDE(object):
|
||||
"""
|
||||
Representation of a kernel-density estimate using Gaussian kernels.
|
||||
|
||||
@ -336,8 +336,10 @@ public class FrmSetting extends javax.swing.JDialog {
|
||||
Theme theme = Theme.load(getClass().getResourceAsStream(
|
||||
"/org/fife/ui/rsyntaxtextarea/themes/" + themeName + ".xml"));
|
||||
this.parent.getEditorDock().setTheme(theme);
|
||||
for (TextEditor textEditor : this.parent.getEditorDock().getAllTextEditor())
|
||||
theme.apply(textEditor.getTextArea());
|
||||
for (TextEditor textEditor : this.parent.getEditorDock().getAllTextEditor()) {
|
||||
theme.apply(textEditor.getTextArea());
|
||||
textEditor.updateTextFont();
|
||||
}
|
||||
} catch (IOException ioe) { // Never happens
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
404
meteoinfo-math/src/main/java/org/meteoinfo/math/stats/Jenks.java
Normal file
404
meteoinfo-math/src/main/java/org/meteoinfo/math/stats/Jenks.java
Normal file
@ -0,0 +1,404 @@
|
||||
package org.meteoinfo.math.stats;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* ActivityInfo Server
|
||||
* %%
|
||||
* Copyright (C) 2009 - 2013 UNICEF
|
||||
* %%
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program. If not, see
|
||||
* <http://www.gnu.org/licenses/gpl-3.0.html>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.meteoinfo.ndarray.Array;
|
||||
import org.meteoinfo.ndarray.DataType;
|
||||
import org.meteoinfo.ndarray.IndexIterator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Jenks optimization method, also called the Jenks natural breaks
|
||||
* classification method, is a data classification method designed to determine
|
||||
* the best arrangement of values into different classes. This is done by
|
||||
* seeking to minimize each class’s average deviation from the class mean, while
|
||||
* maximizing each class’s deviation from the means of the other groups. In
|
||||
* other words, the method seeks to reduce the variance within classes and
|
||||
* maximize the variance between classes.
|
||||
*/
|
||||
public class Jenks {
|
||||
|
||||
private LinkedList<Double> list = Lists.newLinkedList();
|
||||
|
||||
public void addValue(double value) {
|
||||
list.add(value);
|
||||
}
|
||||
|
||||
public void addValues(double... values) {
|
||||
for (double value : values) {
|
||||
addValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values
|
||||
* @param values Values array
|
||||
*/
|
||||
public void addValues(Array values) {
|
||||
IndexIterator vIter = values.getIndexIterator();
|
||||
while (vIter.hasNext()) {
|
||||
addValue(vIter.getDoubleNext());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public Breaks computeBreaks() {
|
||||
double[] list = toSortedArray();
|
||||
|
||||
int uniqueValues = countUnique(list);
|
||||
if (uniqueValues <= 3) {
|
||||
return computeBreaks(list, uniqueValues);
|
||||
}
|
||||
|
||||
Breaks lastBreaks = computeBreaks(list, 2);
|
||||
double lastGvf = lastBreaks.gvf();
|
||||
double lastImprovement = lastGvf - computeBreaks(list, 1).gvf();
|
||||
|
||||
for (int i = 3; i <= Math.min(6, uniqueValues); ++i) {
|
||||
Breaks breaks = computeBreaks(list, 2);
|
||||
double gvf = breaks.gvf();
|
||||
double marginalImprovement = gvf - lastGvf;
|
||||
if (marginalImprovement < lastImprovement) {
|
||||
return lastBreaks;
|
||||
}
|
||||
lastBreaks = breaks;
|
||||
lastGvf = gvf;
|
||||
lastImprovement = marginalImprovement;
|
||||
}
|
||||
|
||||
return lastBreaks;
|
||||
}
|
||||
|
||||
private double[] toSortedArray() {
|
||||
double[] values = new double[this.list.size()];
|
||||
for (int i = 0; i != values.length; ++i) {
|
||||
values[i] = this.list.get(i);
|
||||
}
|
||||
Arrays.sort(values);
|
||||
return values;
|
||||
}
|
||||
|
||||
private int countUnique(double[] sortedList) {
|
||||
int count = 1;
|
||||
for (int i = 1; i < sortedList.length; ++i) {
|
||||
if (sortedList[i] != sortedList[i - 1]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list sorted list of values
|
||||
* @param numclass int number of classes
|
||||
* @return int[] breaks (upper indices of class)
|
||||
*/
|
||||
public Breaks computeBreaks(int numclass) {
|
||||
return computeBreaks(toSortedArray(), numclass, new Identity());
|
||||
}
|
||||
|
||||
private Breaks computeBreaks(double[] list, int numclass) {
|
||||
return computeBreaks(list, numclass, new Identity());
|
||||
}
|
||||
|
||||
private Breaks computeBreaks(double[] list, int numclass, DoubleFunction transform) {
|
||||
|
||||
int numdata = list.length;
|
||||
|
||||
if (numdata == 0) {
|
||||
return new Breaks(new double[0], new int[0]);
|
||||
}
|
||||
|
||||
double[][] mat1 = new double[numdata + 1][numclass + 1];
|
||||
double[][] mat2 = new double[numdata + 1][numclass + 1];
|
||||
|
||||
for (int i = 1; i <= numclass; i++) {
|
||||
mat1[1][i] = 1;
|
||||
mat2[1][i] = 0;
|
||||
for (int j = 2; j <= numdata; j++) {
|
||||
mat2[j][i] = Double.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
double v = 0;
|
||||
for (int l = 2; l <= numdata; l++) {
|
||||
double s1 = 0;
|
||||
double s2 = 0;
|
||||
double w = 0;
|
||||
for (int m = 1; m <= l; m++) {
|
||||
int i3 = l - m + 1;
|
||||
|
||||
double val = transform.apply(list[i3 - 1]);
|
||||
|
||||
s2 += val * val;
|
||||
s1 += val;
|
||||
|
||||
w++;
|
||||
v = s2 - (s1 * s1) / w;
|
||||
int i4 = i3 - 1;
|
||||
if (i4 != 0) {
|
||||
for (int j = 2; j <= numclass; j++) {
|
||||
if (mat2[l][j] >= (v + mat2[i4][j - 1])) {
|
||||
mat1[l][j] = i3;
|
||||
mat2[l][j] = v + mat2[i4][j - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mat1[l][1] = 1;
|
||||
mat2[l][1] = v;
|
||||
}
|
||||
int k = numdata;
|
||||
|
||||
int[] kclass = new int[numclass];
|
||||
|
||||
kclass[numclass - 1] = list.length - 1;
|
||||
|
||||
for (int j = numclass; j >= 2; j--) {
|
||||
int id = (int) (mat1[k][j]) - 2;
|
||||
|
||||
kclass[j - 2] = id;
|
||||
|
||||
k = (int) mat1[k][j] - 1;
|
||||
}
|
||||
return new Breaks(list, kclass);
|
||||
}
|
||||
|
||||
private interface DoubleFunction {
|
||||
double apply(double x);
|
||||
}
|
||||
|
||||
private static class Log10 implements DoubleFunction {
|
||||
|
||||
@Override
|
||||
public double apply(double x) {
|
||||
return Math.log10(x);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Identity implements DoubleFunction {
|
||||
|
||||
@Override
|
||||
public double apply(double x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Breaks {
|
||||
|
||||
private double[] sortedValues;
|
||||
private int[] breaks;
|
||||
|
||||
/**
|
||||
* @param sortedValues the complete array of sorted data values
|
||||
* @param breaks the indexes of the values within the sorted array that begin new classes
|
||||
*/
|
||||
private Breaks(double[] sortedValues, int[] breaks) {
|
||||
this.sortedValues = sortedValues;
|
||||
this.breaks = breaks;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Goodness of Variance Fit (GVF) is found by taking the difference
|
||||
* between the squared deviations from the array mean (SDAM) and the
|
||||
* squared deviations from the class means (SDCM), and dividing by the
|
||||
* SDAM
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public double gvf() {
|
||||
double sdam = sumOfSquareDeviations(sortedValues);
|
||||
double sdcm = 0.0;
|
||||
for (int i = 0; i != numClasses(); ++i) {
|
||||
sdcm += sumOfSquareDeviations(classList(i));
|
||||
}
|
||||
return (sdam - sdcm) / sdam;
|
||||
}
|
||||
|
||||
private double sumOfSquareDeviations(double[] values) {
|
||||
double mean = mean(values);
|
||||
double sum = 0.0;
|
||||
for (int i = 0; i != values.length; ++i) {
|
||||
double sqDev = Math.pow(values[i] - mean, 2);
|
||||
sum += sqDev;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public double[] getValues() {
|
||||
return sortedValues;
|
||||
}
|
||||
|
||||
private double[] classList(int i) {
|
||||
int classStart = (i == 0) ? 0 : breaks[i - 1] + 1;
|
||||
int classEnd = breaks[i];
|
||||
double list[] = new double[classEnd - classStart + 1];
|
||||
for (int j = classStart; j <= classEnd; ++j) {
|
||||
list[j - classStart] = sortedValues[j];
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value arrays for each group
|
||||
* @return Value arrays for each group
|
||||
*/
|
||||
public List<Array> getGroups() {
|
||||
List<Array> groups = new ArrayList<>();
|
||||
int n = numClasses();
|
||||
for (int i = 0; i < n; i++) {
|
||||
double[] values = classList(i);
|
||||
groups.add(Array.factory(DataType.DOUBLE, new int[]{values.length}, values));
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classIndex
|
||||
* @return the minimum value (inclusive) of the given class
|
||||
*/
|
||||
public double getClassMin(int classIndex) {
|
||||
if (classIndex == 0) {
|
||||
return sortedValues[0];
|
||||
} else {
|
||||
return sortedValues[breaks[classIndex - 1] + 1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classIndex
|
||||
* @return the maximum value (inclusive) of the given class
|
||||
*/
|
||||
public double getClassMax(int classIndex) {
|
||||
return sortedValues[breaks[classIndex]];
|
||||
}
|
||||
|
||||
public int getClassCount(int classIndex) {
|
||||
if (classIndex == 0) {
|
||||
return breaks[0] + 1;
|
||||
} else {
|
||||
return breaks[classIndex] - breaks[classIndex - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private double mean(double[] values) {
|
||||
double sum = 0;
|
||||
for (int i = 0; i != values.length; ++i) {
|
||||
sum += values[i];
|
||||
}
|
||||
return sum / values.length;
|
||||
}
|
||||
|
||||
public int numClasses() {
|
||||
return breaks.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get classes bound values
|
||||
* @return Classes bound values
|
||||
*/
|
||||
public Array getClassValues() {
|
||||
double[] classValues = new double[breaks.length + 1];
|
||||
classValues[0] = sortedValues[0];
|
||||
for (int i = 0; i < breaks.length; i++) {
|
||||
classValues[i + 1] = getClassMax(i);
|
||||
}
|
||||
|
||||
return Array.factory(DataType.DOUBLE, new int[]{classValues.length}, classValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i != numClasses(); ++i) {
|
||||
if (getClassMin(i) == getClassMax(i)) {
|
||||
sb.append(getClassMin(i));
|
||||
} else {
|
||||
sb.append(getClassMin(i)).append(" - ").append(getClassMax(i));
|
||||
}
|
||||
sb.append(" (" + getClassCount(i) + ")");
|
||||
sb.append(" = ").append(Arrays.toString(classList(i)));
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String printClusters() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i != numClasses(); ++i) {
|
||||
if (getClassMin(i) == getClassMax(i)) {
|
||||
sb.append(getClassMin(i));
|
||||
} else {
|
||||
sb.append(getClassMin(i)).append(" - ").append(getClassMax(i));
|
||||
}
|
||||
sb.append(" (" + getClassCount(i) + ");");
|
||||
// sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int classOf(double value) {
|
||||
for (int i = 0; i != numClasses(); ++i) {
|
||||
if (value <= getClassMax(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return numClasses() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class index of values
|
||||
* @param values The values array
|
||||
* @return Class index array
|
||||
*/
|
||||
public Array classOf(Array values) {
|
||||
Array r = Array.factory(DataType.INT, values.getShape());
|
||||
IndexIterator vIter = values.getIndexIterator();
|
||||
IndexIterator rIter = r.getIndexIterator();
|
||||
while (vIter.hasNext()) {
|
||||
rIter.setIntNext(classOf(vIter.getDoubleNext()));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Jenks jenks = new Jenks();
|
||||
jenks.addValue(1.0);
|
||||
jenks.addValue(2.0);
|
||||
jenks.addValue(2.0);
|
||||
jenks.addValue(2.0);
|
||||
jenks.addValue(3.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -16,14 +16,9 @@ import org.apache.commons.math4.legacy.stat.correlation.PearsonsCorrelation;
|
||||
import org.apache.commons.math4.legacy.stat.correlation.SpearmansCorrelation;
|
||||
import org.apache.commons.math4.legacy.stat.inference.InferenceTestUtils;
|
||||
import org.apache.commons.math4.legacy.stat.regression.OLSMultipleLinearRegression;
|
||||
import org.meteoinfo.ndarray.*;
|
||||
import org.meteoinfo.ndarray.math.ArrayMath;
|
||||
import org.meteoinfo.ndarray.math.ArrayUtil;
|
||||
import org.meteoinfo.ndarray.Array;
|
||||
import org.meteoinfo.ndarray.DataType;
|
||||
import org.meteoinfo.ndarray.Index;
|
||||
import org.meteoinfo.ndarray.InvalidRangeException;
|
||||
import org.meteoinfo.ndarray.MAMath;
|
||||
import org.meteoinfo.ndarray.Range;
|
||||
import smile.math.special.Erf;
|
||||
|
||||
/**
|
||||
@ -528,4 +523,42 @@ public class StatsUtil {
|
||||
|
||||
return new double[]{s, p};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Jenks breaks
|
||||
* @param a The input data array
|
||||
* @param nClass Number of classes
|
||||
* @return Jenks breaks value array
|
||||
*/
|
||||
public static Array jenksBreaks(Array a, int nClass) {
|
||||
Jenks jenks = new Jenks();
|
||||
IndexIterator iterA = a.getIndexIterator();
|
||||
while (iterA.hasNext()) {
|
||||
jenks.addValue(iterA.getDoubleNext());
|
||||
}
|
||||
|
||||
Jenks.Breaks breaks = jenks.computeBreaks(nClass);
|
||||
Array r = breaks.getClassValues();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Jenks breaks
|
||||
* @param a The input data array
|
||||
* @param nClass Number of classes
|
||||
* @return Jenks breaks value array and gvf value
|
||||
*/
|
||||
public static Object[] jenksBreaksGvf(Array a, int nClass) {
|
||||
Jenks jenks = new Jenks();
|
||||
IndexIterator iterA = a.getIndexIterator();
|
||||
while (iterA.hasNext()) {
|
||||
jenks.addValue(iterA.getDoubleNext());
|
||||
}
|
||||
|
||||
Jenks.Breaks breaks = jenks.computeBreaks(nClass);
|
||||
Array r = breaks.getClassValues();
|
||||
|
||||
return new Object[]{r, breaks.gvf()};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user