diff --git a/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java b/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java index f1a95e4f..9640c282 100644 --- a/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java +++ b/meteoinfo-common/src/main/java/org/meteoinfo/common/util/GlobalUtil.java @@ -43,6 +43,8 @@ import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; diff --git a/meteoinfo-console/src/main/java/org/meteoinfo/console/JConsole.java b/meteoinfo-console/src/main/java/org/meteoinfo/console/JConsole.java index 73616a08..ee5e39ae 100644 --- a/meteoinfo-console/src/main/java/org/meteoinfo/console/JConsole.java +++ b/meteoinfo-console/src/main/java/org/meteoinfo/console/JConsole.java @@ -652,6 +652,10 @@ public class JConsole extends JScrollPane } private void append(String string) { + if (string.length() > 10000) { + string = string.substring(0, 10000); + } + string = StringUtil.unicodeToString(string); int slen = textLength(); if (slen > this.maxLength) { text.setText(""); diff --git a/meteoinfo-console/src/main/java/org/meteoinfo/console/StringUtil.java b/meteoinfo-console/src/main/java/org/meteoinfo/console/StringUtil.java index a27d10aa..60db1fbf 100644 --- a/meteoinfo-console/src/main/java/org/meteoinfo/console/StringUtil.java +++ b/meteoinfo-console/src/main/java/org/meteoinfo/console/StringUtil.java @@ -29,6 +29,8 @@ package org.meteoinfo.console; import java.util.StringTokenizer; import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class StringUtil { @@ -91,6 +93,26 @@ public class StringUtil { return sb.toString(); } + /** + * Convert unicode string to character string + * + * @param unicodeString Unicode string + * @return Character string + */ + public static String unicodeToString(String unicodeString) { + Pattern pattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); + Matcher matcher = pattern.matcher(unicodeString); + StringBuffer builder = new StringBuffer(); + while (matcher.find()) { + String unicodeSequence = matcher.group(); + char unicode = (char) Integer.parseInt(unicodeSequence.substring(2), 16); + matcher.appendReplacement(builder, Character.toString(unicode)); + } + matcher.appendTail(builder); + + return builder.toString(); + } + /** * Split a filename into dirName, baseName * diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml index 69ac815d..9dec9803 100644 --- a/meteoinfo-lab/milconfig.xml +++ b/meteoinfo-lab/milconfig.xml @@ -1,11 +1,6 @@ - - - - - - + @@ -13,22 +8,23 @@ - - + + + + + + + - - - + - - - + @@ -36,5 +32,5 @@
- + diff --git a/meteoinfo-math/src/main/java/org/meteoinfo/math/stats/regression/StepwiseRegression.java b/meteoinfo-math/src/main/java/org/meteoinfo/math/stats/regression/StepwiseRegression.java new file mode 100644 index 00000000..e24e1dca --- /dev/null +++ b/meteoinfo-math/src/main/java/org/meteoinfo/math/stats/regression/StepwiseRegression.java @@ -0,0 +1,118 @@ +package org.meteoinfo.math.stats.regression; + +import org.apache.commons.math4.legacy.stat.regression.OLSMultipleLinearRegression; + +import java.util.ArrayList; +import java.util.List; + +public class StepwiseRegression { + private static final double F_THRESHOLD = 4.0; // F test threshold, can be adjusted as needed + + public static void main(String[] args) { + // sample data + double[][] xData = { + {1, 2, 3, 4}, + {2, 3, 4, 5}, + {3, 4, 5, 6}, + {4, 5, 6, 7}, + {5, 6, 7, 8} + }; + double[] yData = {1, 2, 3, 4, 5}; + + // stepwise regression + StepwiseRegression stepwiseRegression = new StepwiseRegression(); + List selectedVariables = stepwiseRegression.stepwise(xData, yData); + + System.out.println("Selected Variables: " + selectedVariables); + } + + public List stepwise(double[][] xData, double[] yData) { + List variables = new ArrayList<>(); + for (int i = 0; i < xData[0].length; i++) { + variables.add(i); + } + + List selectedVariables = new ArrayList<>(); + boolean changed; + + do { + changed = false; + + // forward selection + double bestFValue = Double.NEGATIVE_INFINITY; + int bestVariable = -1; + for (int var : variables) { + if (!selectedVariables.contains(var)) { + List tempVars = new ArrayList<>(selectedVariables); + tempVars.add(var); + double fValue = calculateFValue(xData, yData, tempVars); + if (fValue > bestFValue) { + bestFValue = fValue; + bestVariable = var; + } + } + } + + if (bestFValue > F_THRESHOLD) { + selectedVariables.add(bestVariable); + changed = true; + } + + // backward remove + bestFValue = Double.NEGATIVE_INFINITY; + bestVariable = -1; + for (int var : selectedVariables) { + List tempVars = new ArrayList<>(selectedVariables); + tempVars.remove(Integer.valueOf(var)); + double fValue = calculateFValue(xData, yData, tempVars); + if (fValue > bestFValue) { + bestFValue = fValue; + bestVariable = var; + } + } + + if (bestFValue > F_THRESHOLD && selectedVariables.size() > 1) { + selectedVariables.remove(Integer.valueOf(bestVariable)); + changed = true; + } + } while (changed); + + return selectedVariables; + } + + private double calculateFValue(double[][] xData, double[] yData, List variables) { + int n = xData.length; + int k = variables.size(); + + double[][] xMatrix = new double[n][k + 1]; + for (int i = 0; i < n; i++) { + xMatrix[i][0] = 1; // intercept + for (int j = 0; j < k; j++) { + xMatrix[i][j + 1] = xData[i][variables.get(j)]; + } + } + + OLSMultipleLinearRegression regression = new OLSMultipleLinearRegression(); + regression.newSampleData(yData, xMatrix); + + double sse = regression.calculateResidualSumOfSquares(); + double sst = calculateSST(yData); + + double fValue = ((sst - sse) / k) / (sse / (n - k - 1)); + return fValue; + } + + private double calculateSST(double[] yData) { + double mean = 0; + for (double y : yData) { + mean += y; + } + mean /= yData.length; + + double sst = 0; + for (double y : yData) { + sst += Math.pow(y - mean, 2); + } + return sst; + } +}