Map.get(key) returns null after inserting key

M

Mize-ze

Hello,
I am inserting a key and a object into a Map. later in the code I try
to retrieve the object by calling
Map.get(key) and I get a null.
I can't see where is my problem...

The application is a weka classifier.
the problem can be seen in isAcceptable(Instance) function.

First I populate a hashtable (calculateAprior method) where the key is
an instance and the value
is a double.
later I will try to fetch the double value by the key and get null (in
isAcceptable method).
I will eventually recieve a NullPointerException.
Thanks



CODE:
/*=============================buildIB3TrainingSet===========================*/

private Instances buildIB3TrainingSet(Instances instances) {

/** see implementation below <==**/
calculateAprior(instances);
double distance
=0,minDistance=Double.MAX_VALUE,classValue=Double.NaN;

/*** Sucess rate*/
successRate = new HashMap<Instance,int[]>();

Instances res = new Instances(instances,0,1);
this.addSuccessSuccessRate(res.firstInstance());
//Iterate on original
for(int i=0;i<instances.numInstances();i++)
{
Instance candidate = instances.instance(i);
Instance yInstance = null;
//Find nearest neighbor
for(int j=0;j<res.numInstances();j++)
{
Instance conceptDescription = res.instance(j);

/** see implementation below <== here is the
problem!!!!!!!!!!!**/
if(!isAcceptable(conceptDescription))
continue;
if (!conceptDescription.classIsMissing())
{
distance = distance(candidate, conceptDescription);
if (distance < minDistance)
{
minDistance = distance;
classValue = conceptDescription.classValue();
yInstance = conceptDescription;
}
}
}
if (yInstance!=null)
{
if(candidate.classValue()!=classValue&&classValue!=Double.NaN)
{
res.add(candidate);
addFailureSuccessRate(yInstance);
}
else
{
addSuccessSuccessRate(yInstance);
}
}

for(int j=0;j<res.numInstances();j++)
{
Instance conceptDescription = res.instance(j);
if(isRejected(conceptDescription))
{
res.delete(j);
successRate.remove(conceptDescription);
}
}
}
return res;
}

/*=======================calculateAprior===================================*/
/**
* calculateAprior
*
* @param instances
* @return double array of aPriory
*/
private void calculateAprior(Instances instances) {

this.aPriori = new
Hashtable<Instance,Double>(instances.numInstances());

/** count classes*/
Map<Double,Double> classCounter = new
HashMap<Double,Double>(m_Train.numClasses());
for(Enumeration enumeration =
instances.enumerateInstances();enumeration.hasMoreElements();)
{
Instance ins = (Instance)enumeration.nextElement();
if (classCounter.containsKey(ins.classValue()))
{
classCounter.put(ins.classValue(), new
Double(classCounter.get(ins.classValue())+ 1));
}
else
{
classCounter.put(ins.classValue(), new Double(1));
}
}

/** Update instances a priori*/
for(Enumeration enumeration =
instances.enumerateInstances();enumeration.hasMoreElements();)
{
Instance ins = (Instance)enumeration.nextElement();
aPriori.put(ins,
(double)classCounter.get(ins.classValue())
/instances.numInstances());
}
}



/*=========================isAcceptable==================================*/
/**
* is the Instance acceptable
* @param j
* @return
*/
private boolean isAcceptable(Instance instance) {
int [] inf = successRate.get(instance);
double rate = (double)inf[1]/inf[0];

/* here is the problem!!!!!!!!!!! aPriori.get(instance)
is null!!!!*/

return (rate-aPriori.get(instance)>ACCEPTENCE);
}
 
M

Mize-ze

Here is the full code just in case ....
--------------------------------------------------------
/*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
* IB1.java
* Copyright (C) 1999 Stuart Inglis,Len Trigg,Eibe Frank
*
*/

package weka.classifiers.lazy;

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.UpdateableClassifier;
import java.io.*;
import java.util.*;

import weka.core.*;


/**
* IB3-type classifier.
*
* @author Zahy
*/
public class IB3 extends Classifier implements UpdateableClassifier {

/** The training instances used for classification. */
private Instances m_Train;

/** The minimum values for numeric attributes. */
private double [] m_MinArray;

/** The A Priori Statistics according to which to use the Training
set*/
private Map<Instance,Double> aPriori;

private static final double ACCEPTENCE = 0.05;
private static final double REJECTION = 0.12;

Map<Instance,int[]> successRate;

/** The maximum values for numeric attributes. */
private double [] m_MaxArray;

/**
* Returns a string describing classifier
* @return a description suitable for
* displaying in the explorer/experimenter gui
*/
public String globalInfo() {


return "Nearest-neighbour classifier. IB3";
}

/**
* Generates the classifier.
*
* @param instances set of instances serving as training data
* @exception Exception if the classifier has not been generated
successfully
*/
public void buildClassifier(Instances instances) throws Exception {

if (instances.classAttribute().isNumeric()) {
throw new Exception("IB3: Class is numeric!");
}
if (instances.checkForStringAttributes()) {
throw new UnsupportedAttributeTypeException("IB3: Cannot handle
string attributes!");
}
// Throw away training instances with missing class
instances.deleteWithMissingClass();
m_Train = new Instances(instances, 0,1);
m_Train = buildIB3TrainingSet(instances);
m_Train.deleteWithMissingClass();



m_MinArray = new double [m_Train.numAttributes()];
m_MaxArray = new double [m_Train.numAttributes()];
for (int i = 0; i < m_Train.numAttributes(); i++) {
m_MinArray = m_MaxArray = Double.NaN;
}
Enumeration enu = m_Train.enumerateInstances();
while (enu.hasMoreElements()) {
updateMinMax((Instance) enu.nextElement());
}
}

private Instances buildIB3TrainingSet(Instances instances) {

calculateAprior(instances);
double distance
=0,minDistance=Double.MAX_VALUE,classValue=Double.NaN;

/*** Sucess rate*/
successRate = new HashMap<Instance,int[]>();

Instances res = new Instances(instances,0,1);
this.addSuccessSuccessRate(res.firstInstance());
//Iterate on original
for(int i=0;i<instances.numInstances();i++)
{
Instance candidate = instances.instance(i);
Instance yInstance = null;
//Find nearest neighbor
for(int j=0;j<res.numInstances();j++)
{
Instance conceptDescription = res.instance(j);
if(!isAcceptable(conceptDescription))
continue;
if (!conceptDescription.classIsMissing())
{
distance = distance(candidate, conceptDescription);
if (distance < minDistance)
{
minDistance = distance;
classValue = conceptDescription.classValue();
yInstance = conceptDescription;
}
}
}
if (yInstance!=null)
{
if(candidate.classValue()!=classValue&&classValue!=Double.NaN)
{
res.add(candidate);
addFailureSuccessRate(yInstance);
}
else
{
addSuccessSuccessRate(yInstance);
}
}

for(int j=0;j<res.numInstances();j++)
{
Instance conceptDescription = res.instance(j);
if(isRejected(conceptDescription))
{
res.delete(j);
successRate.remove(conceptDescription);
}
}
}
return res;
}

private void addSuccessSuccessRate(Instance instance) {
if(!successRate.containsKey(instance))
{
successRate.put(instance, new int[]{1,1});
}
else
{
successRate.put(instance, new int[]
{successRate.get(instance)[0]+1,
successRate.get(instance)[1]+1});
}
}

private void addFailureSuccessRate(Instance instance) {
if(!successRate.containsKey(instance))
{
successRate.put(instance, new int[]{1,0});
}
else
{
successRate.put(instance, new int[]
{successRate.get(instance)[0]+1,
successRate.get(instance)[1]});
}
}

/**
* Is the instance rejected
* @param instanceIndex
* @return
*/
private boolean isRejected(Instance instance) {
int [] inf = successRate.get(instance);
double rate = (double)inf[1]/inf[0];
return (aPriori.get(instance)-rate<REJECTION);
}

/**
* is the Instance acceptable
* @param j
* @return
*/
private boolean isAcceptable(Instance instance) {
int [] inf = successRate.get(instance);
double rate = (double)inf[1]/inf[0];
return (rate-aPriori.get(instance)>ACCEPTENCE);
}

/**
*
* @param instances
* @return double array of aPriory
*/
private void calculateAprior(Instances instances) {

this.aPriori = new
Hashtable<Instance,Double>(instances.numInstances());

/** count classes*/
Map<Double,Double> classCounter = new
HashMap<Double,Double>(m_Train.numClasses());
for(Enumeration enumeration =
instances.enumerateInstances();enumeration.hasMoreElements();)
{
Instance ins = (Instance)enumeration.nextElement();
if (classCounter.containsKey(ins.classValue()))
{
classCounter.put(ins.classValue(), new
Double(classCounter.get(ins.classValue())+ 1));
}
else
{
classCounter.put(ins.classValue(), new Double(1));
}
}

/** Update instances a priori*/
for(Enumeration enumeration =
instances.enumerateInstances();enumeration.hasMoreElements();)
{
Instance ins = (Instance)enumeration.nextElement();
aPriori.put(ins,
(double)classCounter.get(ins.classValue())
/instances.numInstances());
}
}

/**
* Updates the classifier.
*
* @param instance the instance to be put into the classifier
* @exception Exception if the instance could not be included
successfully
*/
public void updateClassifier(Instance instance) throws Exception {

if (m_Train.equalHeaders(instance.dataset()) == false) {
throw new Exception("Incompatible instance types");
}
if (instance.classIsMissing()) {
return;
}
m_Train.add(instance);
updateMinMax(instance);
}

/**
* Classifies the given test instance.
*
* @param instance the instance to be classified
* @return the predicted class for the instance
* @exception Exception if the instance can't be classified
*/
public double classifyInstance(Instance instance) throws Exception {

if (m_Train.numInstances() == 0) {
throw new Exception("No training instances!");
}
double distance, minDistance = Double.MAX_VALUE, classValue = 0;
updateMinMax(instance);
Enumeration enu = m_Train.enumerateInstances();
while (enu.hasMoreElements())
{
Instance trainInstance = (Instance) enu.nextElement();
if (!trainInstance.classIsMissing())
{
distance = distance(instance, trainInstance);
if (distance < minDistance)
{
minDistance = distance;
classValue = trainInstance.classValue();
}
}
}
return classValue;
}

/**
* Returns a description of this classifier.
*
* @return a description of this classifier as a string.
*/
public String toString() {

return ("IB3 classifier");
}

/**
* Calculates the distance between two instances
*
* @param first the first instance
* @param second the second instance
* @return the distance between the two given instances
*/
private double distance(Instance first, Instance second) {

double diff, distance = 0;

for(int i = 0; i < m_Train.numAttributes(); i++) {
if (i == m_Train.classIndex()) {
continue;
}
if (m_Train.attribute(i).isNominal()) {

// If attribute is nominal
if (first.isMissing(i) || second.isMissing(i) ||
((int)first.value(i) != (int)second.value(i))) {
distance += 1;
}
} else {

// If attribute is numeric
if (first.isMissing(i) || second.isMissing(i)){
if (first.isMissing(i) && second.isMissing(i)) {
diff = 1;
} else {
if (second.isMissing(i)) {
diff = norm(first.value(i), i);
} else {
diff = norm(second.value(i), i);
}
if (diff < 0.5) {
diff = 1.0 - diff;
}
}
} else {
diff = norm(first.value(i), i) - norm(second.value(i), i);
}
distance += diff * diff;
}
}

return distance;
}

/**
* Normalizes a given value of a numeric attribute.
*
* @param x the value to be normalized
* @param i the attribute's index
*/
private double norm(double x,int i) {

if (Double.isNaN(m_MinArray)
|| Utils.eq(m_MaxArray, m_MinArray)) {
return 0;
} else {
return (x - m_MinArray) / (m_MaxArray - m_MinArray);
}
}

/**
* Updates the minimum and maximum values for all the attributes
* based on a new instance.
*
* @param instance the new instance
*/
private void updateMinMax(Instance instance) {

for (int j = 0;j < m_Train.numAttributes(); j++) {
if ((m_Train.attribute(j).isNumeric()) &&
(!instance.isMissing(j))) {
if (Double.isNaN(m_MinArray[j])) {
m_MinArray[j] = instance.value(j);
m_MaxArray[j] = instance.value(j);
} else {
if (instance.value(j) < m_MinArray[j]) {
m_MinArray[j] = instance.value(j);
} else {
if (instance.value(j) > m_MaxArray[j]) {
m_MaxArray[j] = instance.value(j);
}
}
}
}
}
}

/**
* Main method for testing this class.
*
* @param argv should contain command line arguments for evaluation
* (see Evaluation).
*/
public static void main(String [] argv) {

try {
System.out.println(Evaluation.evaluateModel(new IB3(), argv));
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
 
D

Daniel Pitts

Mize-ze said:
Here is the full code just in case ....
That is way too much for me to read through and parse.

Try writing an sscce <http://physci.org/codes/sscce/>, and then perhaps
we can help you...

Without looking at your source code. If you wrote the class that
defines the Key of the map, make sure that equals and hashCode are both
implemented and consistent. Basically, if a.equals(b) == true, then
a.hashCode() == b.hashCode() must be true.

Hope this helps.
Daniel.
 
P

Paul Tomblin

In a previous article said:
Hello,
I am inserting a key and a object into a Map. later in the code I try
to retrieve the object by calling
Map.get(key) and I get a null.
I can't see where is my problem...

I only had to read this far to guess what the problem is - you haven't
implemented hashCode on your key class, or if you have, you haven't
implemented it properly, and you're using HashMap.

I know this, because I made the same mistake (AGAIN) a few weeks ago. I
changed something from TreeSet to HashSet and things weren't working the
way I expected.
 
R

Robert Klemme

That is way too much for me to read through and parse.

Try writing an sscce <http://physci.org/codes/sscce/>, and then perhaps
we can help you...

Without looking at your source code. If you wrote the class that
defines the Key of the map, make sure that equals and hashCode are both
implemented and consistent. Basically, if a.equals(b) == true, then
a.hashCode() == b.hashCode() must be true.

Also, if the Map is a TreeMap compareTo() must be implemented according
to the contract or you must use a proper Comparator.

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top