-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Classifier #1357
Classifier #1357
Changes from 23 commits
96e5b14
33cece3
c855b6b
ba60af9
b3c63ab
84395a1
280ed2a
95bc1f2
ca0541d
4c947fa
d4a163a
1ed0023
26eaf71
2bde111
e723c37
b6fe81c
52f6564
a751329
893a93c
56ff9dc
a47ebc5
ece1779
81baa02
da03532
87d5aa8
c2dc1d0
5ce0491
6e36dc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,62 @@ | ||
package ucar.nc2.filter; | ||
|
||
import java.io.IOException; | ||
import static ucar.ma2.MAMath.nearlyEquals; | ||
import ucar.ma2.Array; | ||
import ucar.ma2.DataType; | ||
import ucar.ma2.IndexIterator; | ||
import ucar.nc2.dataset.VariableDS; | ||
import ucar.nc2.Variable; | ||
import ucar.nc2.constants.CDM; | ||
import ucar.nc2.Attribute; | ||
import ucar.nc2.util.Misc; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
|
||
public class Classifier implements Enhancement { | ||
private Classifier classifier = null; | ||
private static Classifier emptyClassifier; | ||
private int classifiedVal; | ||
private int[] classifiedArray; | ||
|
||
public static Classifier createFromVariable(VariableDS var) { | ||
try { | ||
Array arr = var.read(); | ||
// DataType type = var.getDataType(); | ||
return emptyClassifier(); | ||
} catch (IOException e) { | ||
return emptyClassifier(); | ||
} | ||
private List<Attribute> AttCat; | ||
private List<int[]> rules = new ArrayList<>(); | ||
|
||
// Constructor with no arguments | ||
public Classifier() { | ||
this.AttCat = new ArrayList<>(); | ||
this.rules = new ArrayList<>(); | ||
} | ||
|
||
// Constructor with attributes | ||
public Classifier(List<Attribute> AttCat) { | ||
this.AttCat = AttCat; | ||
this.rules = loadClassificationRules(); | ||
} | ||
|
||
public static Classifier emptyClassifier() { | ||
emptyClassifier = new Classifier(); | ||
return emptyClassifier; | ||
// Factory method to create a Classifier from a Variable | ||
public static Classifier createFromVariable(Variable var) { | ||
|
||
List<Attribute> attributes = var.getAttributes(); | ||
|
||
if (var.attributes().hasAttribute(CDM.RANGE_CAT)) { | ||
return new Classifier(attributes); | ||
} else { | ||
return new Classifier(); | ||
} | ||
|
||
} | ||
|
||
/** Enough of a constructor */ | ||
public Classifier() {} | ||
|
||
public int[] classifyWithAttributes(Array arr) { | ||
int[] classifiedArray = new int[(int) arr.getSize()]; | ||
IndexIterator iterArr = arr.getIndexIterator(); | ||
int i = 0; | ||
while (iterArr.hasNext()) { | ||
Number value = (Number) iterArr.getObjectNext(); | ||
if (!Double.isNaN(value.doubleValue())) { | ||
classifiedArray[i] = classifyArrayAttribute(value.doubleValue()); | ||
} else { | ||
classifiedArray[i] = Integer.MIN_VALUE; | ||
} | ||
i++; | ||
} | ||
return classifiedArray; | ||
} | ||
|
||
/** Classify double array */ | ||
public int[] classifyDoubleArray(Array arr) { | ||
|
@@ -46,25 +74,64 @@ public int[] classifyDoubleArray(Array arr) { | |
return classifiedArray; | ||
} | ||
|
||
|
||
|
||
/** for a single double */ | ||
public int classifyArray(double val) { | ||
if (val >= 0) { | ||
classifiedVal = 1; | ||
} else { | ||
classifiedVal = 0; | ||
} | ||
|
||
return classifiedVal; | ||
} | ||
|
||
public int classifyArrayAttribute(double val) { | ||
for (int[] rule : rules) { | ||
if (val > rule[0] && val <= rule[1] + ucar.nc2.util.Misc.defaultMaxRelativeDiffFloat) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor style comment: I would add an import statement for
so that this can just be |
||
return rule[2]; // Return the matched rule's value | ||
} | ||
} | ||
// Return min possible int if no rule matches | ||
return Integer.MIN_VALUE; | ||
} | ||
|
||
// Method to load classification rules from the attributes | ||
private List<int[]> loadClassificationRules() { | ||
for (Attribute attribute : this.AttCat) { | ||
int[] rule = stringToIntArray(attribute.getStringValue()); | ||
this.rules.add(rule); | ||
} | ||
return rules; | ||
} | ||
|
||
@Override | ||
public double convert(double val) { | ||
return emptyClassifier.classifyArray(val); | ||
return classifyArray(val); | ||
} | ||
|
||
public static int[] stringToIntArray(String str) { | ||
String[] stringArray = str.split(" "); // Split the string by spaces | ||
int[] intArray = new int[stringArray.length]; // Create an array to hold the parsed integers | ||
|
||
for (int i = 0; i < stringArray.length; i++) { | ||
|
||
double value = Double.parseDouble(stringArray[i]); // Parse each string to a double | ||
|
||
if (Double.isNaN(value)) { | ||
// Check if the entry is NaN and assign Integer.MIN_VALUE or Integer.MAX_VALUE based on the index | ||
if (i == 0) { | ||
intArray[i] = Integer.MIN_VALUE; | ||
} else if (i == 1) { | ||
intArray[i] = Integer.MAX_VALUE; | ||
} else { | ||
intArray[i] = -99999; // Default value for other indices if needed | ||
} | ||
} else { | ||
intArray[i] = (int) value; // Convert the value to int if it is not NaN | ||
} | ||
|
||
} | ||
} | ||
|
||
return intArray; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
|
||
<!-- | ||
~ Copyright (c) 1998-2020 John Caron and University Corporation for Atmospheric Research/Unidata | ||
~ See LICENSE for license information. | ||
--> | ||
|
||
<netcdf xmlns="http://www.unidata.ucar.edu/namespaces/netcdf/ncml-2.2" enhance="all"> | ||
|
||
<variable name="class_specs" shape="17" type="double"> | ||
<attribute name="range_cat" type="string" value="NaN 0 0" /> | ||
<attribute name="range_cat1" type="string" value="0 10 10" /> | ||
<attribute name="range_cat2" type="string" value="10 100 100" /> | ||
<attribute name="range_cat3" type="string" value="100 NaN 1000" /> | ||
<values>-500000 NaN -10 0 1 2 3 11 25 29 NaN 100 150 121 102 199999 12211</values> | ||
</variable> | ||
|
||
|
||
</netcdf> |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,14 +2,17 @@ | |||||
|
||||||
import static com.google.common.truth.Truth.assertThat; | ||||||
import static ucar.ma2.MAMath.nearlyEquals; | ||||||
|
||||||
import java.io.IOException; | ||||||
import java.util.Arrays; | ||||||
import java.util.List; | ||||||
import org.junit.Test; | ||||||
import ucar.ma2.Array; | ||||||
import ucar.ma2.DataType; | ||||||
import ucar.nc2.Attribute; | ||||||
import ucar.nc2.NetcdfFile; | ||||||
import ucar.nc2.Variable; | ||||||
import ucar.nc2.dataset.NetcdfDatasets; | ||||||
import ucar.nc2.filter.Classifier; | ||||||
import ucar.unidata.util.test.TestDir; | ||||||
|
||||||
public class TestEnhanceClassifier { | ||||||
|
@@ -22,7 +25,9 @@ public class TestEnhanceClassifier { | |||||
public static final Array DATA_all_zeroes = Array.makeFromJavaArray(all_zeroes); | ||||||
public static final int[] mixNumbers = {1, 0, 1, 1, 0}; | ||||||
public static final Array DATA_mixNumbers = Array.makeFromJavaArray(mixNumbers); | ||||||
|
||||||
public static final int[] Classification_test = | ||||||
{0, -2147483648, 0, 0, 10, 10, 10, 100, 100, 100, -2147483648, 100, 1000, 1000, 1000, 1000, 1000}; | ||||||
public static final Array CLASSIFICATION_TEST = Array.makeFromJavaArray(Classification_test); | ||||||
|
||||||
/** test on doubles, all positives, all negatives and a mixed array */ | ||||||
@Test | ||||||
|
@@ -78,6 +83,7 @@ public void testEnhanceClassifier_floats() throws IOException { | |||||
assertThat(floatMix.getDataType()).isEqualTo(DataType.FLOAT); | ||||||
assertThat(floatMix.attributes().hasAttribute("classify")).isTrue(); | ||||||
Array datafloatsMix = floatMix.read(); | ||||||
// assertThat(datafloatsMix).isEqualTo(DATA_mixNumbers); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can probably go?
Suggested change
|
||||||
assertThat(nearlyEquals(datafloatsMix, DATA_mixNumbers)).isTrue(); | ||||||
|
||||||
} | ||||||
|
@@ -112,4 +118,27 @@ public void testEnhanceClassifier_integers() throws IOException { | |||||
} | ||||||
|
||||||
} | ||||||
|
||||||
@Test | ||||||
public void testEnhanceClassifier_classification() throws IOException { | ||||||
|
||||||
try (NetcdfFile ncfile = NetcdfDatasets.openDataset(dataDir + "testAddToClassifier.ncml", true, null)) { | ||||||
|
||||||
Variable Classify_Specsx = ncfile.findVariable("class_specs"); | ||||||
matakleo marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor style issue: would use lower camel case for the variable name, something like:
Suggested change
|
||||||
assertThat((Object) Classify_Specsx).isNotNull(); | ||||||
assertThat(!Classify_Specsx.attributes().isEmpty()).isTrue(); | ||||||
Array Data = Classify_Specsx.read(); | ||||||
Classifier classifier = Classifier.createFromVariable(Classify_Specsx); | ||||||
// List<Attribute> Whatever = Classify_Specsx.getAttributes(); | ||||||
// Classifier classifier = new Classifier(Whatever); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can probably go?
Suggested change
|
||||||
int[] ClassifiedArray = classifier.classifyWithAttributes(Data); | ||||||
assertThat(nearlyEquals(Array.makeFromJavaArray(ClassifiedArray), CLASSIFICATION_TEST)).isTrue(); | ||||||
|
||||||
|
||||||
} catch (IOException e) { | ||||||
throw new RuntimeException(e); | ||||||
} | ||||||
|
||||||
} | ||||||
|
||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this
classifyArray
still being used? maybe we can delete this function as it was the placeholder version and add the categories to the ncml intestClassifier.ncml
so your original tests keep working. It's possible that this is causing some of the test issues as the original tests may be using this code path and you only added the tolerance to the comparison below inclassifyArrayAttribute