/* * @(#)ContingencyTableModel.java 0.0.3 99/08/06 * * Copyright (c) 1999 by Willie Wheeler. All rights reserved. */ package stats; import java.util.*; /** * @version 0.0.3 08/06/99 * @author Willie Wheeler */ public class ContingencyTableModel extends MVDTableModel { public static final String FREQUENCY = "Frequency"; public static final int FREQUENCY_OFFSET = 0; public static final String ESTIMATE = "Estimate"; public static final int ESTIMATE_OFFSET = 1; public ContingencyTableModel(Vector independents) { Vector dependents = new Vector(); dependents.add(new IntegralVariable(FREQUENCY)); dependents.add(new ContinuousVariable(ESTIMATE)); setVariables(independents, dependents); } public ContingencyTableModel(TextVariable[] independents) { this(convertToVector(independents)); } public int getFrequencyColumnIndex() { return getNumIndependents() + FREQUENCY_OFFSET; } public int getEstimateColumnIndex() { return getNumIndependents() + ESTIMATE_OFFSET; } // // Accessing frequencies. // public int getFrequency(int[] state) { int[] rowIndices = rowIndices(state); int colIndex = getFrequencyColumnIndex(); int sum = 0; for (int i = 0; i < rowIndices.length; i++) { int rowIndex = rowIndices[i]; sum += ((Integer)getValueAt(rowIndex, colIndex)).intValue(); } return sum; } public int getFrequency(int[] state, int[] conditioningState) { if (conditioningState == null) { return getFrequency(state); } int[] rowIndices = rowIndices(state); int colIndex = getFrequencyColumnIndex(); int sum = 0; for (int i = 0; i < rowIndices.length; i++) { int rowIndex = rowIndices[i]; if (substate(totalState(rowIndex), conditioningState)) { sum += ((Integer)getValueAt(rowIndex, colIndex)).intValue(); } } return sum; } public int[] getFrequencyDistribution(int[] variableIndices) { return getFrequencyDistribution(states(variableIndices)); } public int[] getFrequencyDistribution(int[][] states) { int[] dist = new int[states.length]; for (int i = 0; i < states.length; i++) { dist[i] = getFrequency(states[i]); } return dist; } public int[] getFrequencyDistribution(int[] variableIndices, int[] conditioningState) { return getFrequencyDistribution(states(variableIndices), conditioningState); } public int[] getFrequencyDistribution(int[][] states, int[] conditioningState) { if (conditioningState == null) { return getFrequencyDistribution(states); } int[] dist = new int[states.length]; for (int i = 0; i < states.length; i++) { dist[i] = getFrequency(states[i], conditioningState); } return dist; } public int[][] getFrequencyDistributions(int[] variableIndices, int[] conditioningVariableIndices) { return getFrequencyDistributions(states(variableIndices), states(conditioningVariableIndices)); } public int[][] getFrequencyDistributions(int[][] states, int[][] conditioningStates) { int numDists = conditioningStates.length; int[][] dists = new int[numDists][]; for (int i = 0; i < numDists; i++) { dists[i] = getFrequencyDistribution(states, conditioningStates[i]); } return dists; } // // Accessing estimates. // public double getEstimate(int[] state) { int[] rowIndices = rowIndices(state); int colIndex = getEstimateColumnIndex(); double sum = 0.0; for (int i = 0; i < rowIndices.length; i++) { int rowIndex = rowIndices[i]; sum += ((Double)getValueAt(rowIndex, colIndex)).doubleValue(); } return sum; } public double getEstimate(int[] state, int[] conditioningState) { if (conditioningState == null) { return getEstimate(state); } int[] rowIndices = rowIndices(conditioningState); int colIndex = getEstimateColumnIndex(); double stateSum = 0.0; double totalSum = 0.0; for (int i = 0; i < rowIndices.length; i++) { int rowIndex = rowIndices[i]; Object value = getValueAt(rowIndex, colIndex); double dblVal = ((Double)value).doubleValue(); totalSum += dblVal; if (substate(totalState(rowIndex), state)) { stateSum += dblVal; } } if (totalSum == 0.0) { totalSum += 1.0; } // Avoid div by 0. return stateSum / totalSum; } public double[] getEstimateDistribution(int[] variableIndices) { return getEstimateDistribution(states(variableIndices)); } public double[] getEstimateDistribution(int[][] states) { double[] dist = new double[states.length]; for (int i = 0; i < states.length; i++) { dist[i] = getEstimate(states[i]); } return dist; } public double[] getEstimateDistribution(int[] variableIndices, int[] conditioningState) { return getEstimateDistribution(states(variableIndices), conditioningState); } public double[] getEstimateDistribution(int[][] states, int[] conditioningState) { if (conditioningState == null) { return getEstimateDistribution(states); } double[] dist = new double[states.length]; for (int i = 0; i < states.length; i++) { dist[i] = getEstimate(states[i], conditioningState); } return dist; } public double[][] getEstimateDistributions(int[] variableIndices, int[] conditioningVariableIndices) { return getEstimateDistributions(states(variableIndices), states(conditioningVariableIndices)); } public double[][] getEstimateDistributions(int[][] states, int[][] conditioningStates) { int numDists = conditioningStates.length; double[][] dists = new double[numDists][]; for (int i = 0; i < numDists; i++) { dists[i] = getEstimateDistribution(states, conditioningStates[i]); } return dists; } // // Converting between variable indices, states, and row indices. // public int[][] states(int[] independentIndices) { // Build a boolean array indicating which independents are to have // specific values (true = has specific value). int totalNumIndependents = getNumIndependents(); boolean[] hasSpecifiedValues = new boolean[totalNumIndependents]; for (int i = 0; i < independentIndices.length; i++) { hasSpecifiedValues[independentIndices[i]] = true; } // Precompute the number of states that we will be returning. int numStates = 1; for (int i = 0; i < independentIndices.length; i++) { numStates *= getIndependent(independentIndices[i]).getNumValues(); } // Build the array. int[][] states = new int[numStates][totalNumIndependents]; int placeValue = 1; for (int j = totalNumIndependents-1; j >= 0; j--) { if (hasSpecifiedValues[j]) { int numValues = getIndependent(j).getNumValues(); for (int i = 0; i < numStates; i++) { states[i][j] = (i / placeValue) % numValues; } placeValue *= numValues; } else { // Unspecified values, so fill the column with -1's. for (int i = 0; i < numStates; i++) { states[i][j] = -1; } } } // Return the array of states. return states; } public int[] rowIndices(int[] state) { // This method attempts to optimize the process of building the array // of row indices. The naive way to do it is to iterate over the // table rows, testing the corresponding total states to see whether // they are substates of the given state. Instead what we do here is // precompute the number n of row indices, and then iterate over // the set { 0, ..., n-1 }. Since n is potentially much smaller // than the number of table rows, the algorithm here is generally // faster than the naive algorithm. // Compute the number of row indices, along with some other stuff // that we can do here as well. int totalNumIndependents = getNumIndependents(); int numStateIndependents = 0; int[] stateIndependents = new int[totalNumIndependents]; int numRowIndices = 1; int baseRowIndex = 0; for (int i = totalNumIndependents-1; i >= 0; i--) { if (state[i] == -1) { stateIndependents[numStateIndependents++] = i; numRowIndices *= getIndependent(i).getNumValues(); } else { baseRowIndex += state[i] * placeValues[i]; } } // Build an array of place values for the state independents. int[] statePlaceValues = new int[numStateIndependents]; if (numStateIndependents > 0) { statePlaceValues[0] = 1; for (int i = 1; i < numStateIndependents; i++) { statePlaceValues[i] = getIndependent(stateIndependents[i-1]).getNumValues() * statePlaceValues[i-1]; } } // Build the array of row indices. int[] rowIndices = new int[numRowIndices]; for (int i = 0; i < numRowIndices; i++) { rowIndices[i] = baseRowIndex; for (int j = 0; j < numStateIndependents; j++) { int value = (i / statePlaceValues[j]) % getIndependent(stateIndependents[j]).getNumValues(); rowIndices[i] += (value * placeValues[stateIndependents[j]]); } } // Return the array. return rowIndices; } // // Other useful methods. // public boolean substate(int[] state1, int[] state2) { if (state2 == null) { return true; } for (int i = 0; i < state2.length; i++) { if (state2[i] != -1 && state2[i] != state1[i]) { return false; } } return true; } public void updateEstimates() { int freqColIndex = getFrequencyColumnIndex(); int estColIndex = getEstimateColumnIndex(); // Compute the sum of the frequencies. int sum = 0; for (int i = 0; i < getRowCount(); i++) { sum += ((Integer)getValueAt(i, freqColIndex)).intValue(); } if (sum == 0) { sum++; } // Avoids division by 0. // Set the estimates. Vector tableData = getDataVector(); for (int i = 0; i < getRowCount(); i++) { Vector rowData = (Vector)tableData.get(i); double freq = ((Number)rowData.get(freqColIndex)).doubleValue(); double est = freq / (double)sum; rowData.set(estColIndex, new Double(est)); } // Fire a table model event. fireTableDataChanged(); } }