A convenience class for maintaining a dynamically growing table of values with access to the elements by named row and column identifiers.
git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@1988 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
parent
21c5f543fa
commit
2225d8176e
|
|
@ -0,0 +1,292 @@
|
|||
package org.broadinstitute.sting.playground.utils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* NamedTable is a utility class for maintaining a table and accessing rows and columns
|
||||
* with named identifiers, rather than indicies that must be remembered. It also grows
|
||||
* dynamically; you needn't specify the rows and columns before accessing them, so you can
|
||||
* continuously expand the table in situations where you don't necessarily know how many
|
||||
* rows or columns you'll have in the end.
|
||||
*/
|
||||
public class NamedTable {
|
||||
// If in the future, this class gets templatized, the counter variable should really become a CountedObject<T>.
|
||||
private HashMap<String, HashMap<String, Double>> table;
|
||||
private HashSet<String> rowNames;
|
||||
private HashSet<String> colNames;
|
||||
|
||||
public NamedTable() {
|
||||
table = new HashMap<String, HashMap<String, Double>>();
|
||||
rowNames = new HashSet<String>();
|
||||
colNames = new HashSet<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy another table into this new table
|
||||
* @param ct the table to copy
|
||||
*/
|
||||
public NamedTable(NamedTable ct) {
|
||||
table = new HashMap<String, HashMap<String, Double>>();
|
||||
rowNames = new HashSet<String>();
|
||||
colNames = new HashSet<String>();
|
||||
|
||||
for (String rowName : ct.getRowNames()) {
|
||||
for (String colName : ct.getColumnNames()) {
|
||||
this.set(rowName, colName, ct.get(rowName, colName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the entry we're trying to access doesn't exist, create it.
|
||||
*
|
||||
* @param rowName the name of the row
|
||||
* @param colName the name of the column
|
||||
*/
|
||||
private void verifyEntry(String rowName, String colName) {
|
||||
rowNames.add(rowName);
|
||||
colNames.add(colName);
|
||||
|
||||
if (!table.containsKey(rowName)) {
|
||||
table.put(rowName, new HashMap<String, Double>());
|
||||
}
|
||||
|
||||
if (!table.get(rowName).containsKey(colName)) {
|
||||
table.get(rowName).put(colName, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an entry in the table
|
||||
*
|
||||
* @param rowName the name of the row
|
||||
* @param colName the name of the column
|
||||
* @param value the value to set for the (row,column)-th entry
|
||||
*/
|
||||
public void set(String rowName, String colName, double value) {
|
||||
verifyEntry(rowName, colName);
|
||||
|
||||
table.get(rowName).put(colName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry in the table
|
||||
*
|
||||
* @param rowName the name of the row
|
||||
* @param colName the name of the column
|
||||
* @return the value of the (row,column)-th entry
|
||||
*/
|
||||
public double get(String rowName, String colName) {
|
||||
verifyEntry(rowName, colName);
|
||||
|
||||
return table.get(rowName).get(colName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For convenience, increment the (row,column)-th entry in the table so that the
|
||||
* user doesn't need to extract, increment, and then reassign the value. One day,
|
||||
* this should probably be rewritten to use Andrey's CountedObject class.
|
||||
*
|
||||
* @param rowName the name of the row
|
||||
* @param colName the name of the column
|
||||
*/
|
||||
public void increment(String rowName, String colName) {
|
||||
double value = get(rowName, colName);
|
||||
|
||||
table.get(rowName).put(colName, value + 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* For convenience, decrement the (row,column)-th entry in the table so that the
|
||||
* user doesn't need to extract, increment, and then reassign the value. One day,
|
||||
* this should probably be rewritten to use Andrey's CountedObject class.
|
||||
*
|
||||
* @param rowName the name of the row
|
||||
* @param colName the name of the column
|
||||
*/
|
||||
public void decrement(String rowName, String colName) {
|
||||
double value = get(rowName, colName);
|
||||
|
||||
table.get(rowName).put(colName, value - 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sorted list of all the rows in the table
|
||||
*
|
||||
* @return a sorted list of all the rows in the table
|
||||
*/
|
||||
public ArrayList<String> getRowNames() {
|
||||
ArrayList<String> rows = new ArrayList<String>();
|
||||
Iterator<String> rowit = rowNames.iterator();
|
||||
while (rowit.hasNext()) {
|
||||
rows.add(rowit.next());
|
||||
}
|
||||
Collections.sort(rows);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sorted list of all the columns in the table
|
||||
*
|
||||
* @return a sorted list of all the columns in the table
|
||||
*/
|
||||
public ArrayList<String> getColumnNames() {
|
||||
ArrayList<String> cols = new ArrayList<String>();
|
||||
Iterator<String> colit = colNames.iterator();
|
||||
while (colit.hasNext()) {
|
||||
cols.add(colit.next());
|
||||
}
|
||||
Collections.sort(cols);
|
||||
|
||||
return cols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new table representing a subset of the current table
|
||||
* @param rowNames a list of rows to extract
|
||||
* @param colNames a list of columns to extract
|
||||
* @return the subsetted table
|
||||
*/
|
||||
public NamedTable getSubset(ArrayList<String> rowNames, ArrayList<String> colNames) {
|
||||
NamedTable ct = new NamedTable();
|
||||
|
||||
for (String rowName : rowNames) {
|
||||
for (String colName : colNames) {
|
||||
ct.set(rowName, colName, get(rowName, colName));
|
||||
}
|
||||
}
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
/* This stuff doesn't belong in this class, but I don't want
|
||||
to delete the code until it's moved somewhere appropriate */
|
||||
/*
|
||||
public boolean twoTailedFisherExactTest(double pValueLimit) {
|
||||
return (twoTailedFisherExactTest() < pValueLimit);
|
||||
}
|
||||
|
||||
public double oneTailedFisherExactTestRight() {
|
||||
NamedTable ct = new NamedTable(this);
|
||||
|
||||
double pCutoff = pValue();
|
||||
double pValue = pCutoff;
|
||||
|
||||
while (ct.rotateRight()) {
|
||||
double pValuePiece = ct.pValue();
|
||||
|
||||
if (pValuePiece <= pCutoff) {
|
||||
pValue += pValuePiece;
|
||||
}
|
||||
}
|
||||
|
||||
return pValue;
|
||||
}
|
||||
|
||||
public double oneTailedFisherExactTestLeft() {
|
||||
NamedTable ct = new NamedTable(this);
|
||||
|
||||
double pCutoff = pValue();
|
||||
double pValue = pCutoff;
|
||||
|
||||
while (ct.rotateLeft()) {
|
||||
double pValuePiece = ct.pValue();
|
||||
|
||||
if (pValuePiece <= pCutoff) {
|
||||
pValue += pValuePiece;
|
||||
}
|
||||
}
|
||||
|
||||
return pValue;
|
||||
}
|
||||
|
||||
public double twoTailedFisherExactTest() {
|
||||
return oneTailedFisherExactTestLeft() + oneTailedFisherExactTestRight();
|
||||
}
|
||||
|
||||
public double pValue() {
|
||||
double p = 0.0;
|
||||
|
||||
if (rowNames.size() == 2 && colNames.size() == 2) {
|
||||
String[] rows = rowNames.toArray(new String[1]);
|
||||
String[] columns = colNames.toArray(new String[1]);
|
||||
|
||||
double a = get(rows[0], columns[0]);
|
||||
double b = get(rows[0], columns[1]);
|
||||
double c = get(rows[1], columns[0]);
|
||||
double d = get(rows[1], columns[1]);
|
||||
double n = a + b + c + d;
|
||||
|
||||
double p1 = Arithmetic.binomial(a + b, (long) a);
|
||||
double p2 = Arithmetic.binomial(c + d, (long) c);
|
||||
double pn = Arithmetic.binomial(n, (long) (a + c));
|
||||
|
||||
p = p1*p2/pn;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public boolean rotateRight() {
|
||||
String[] rows = rowNames.toArray(new String[1]);
|
||||
String[] columns = colNames.toArray(new String[1]);
|
||||
|
||||
decrement(rows[0], columns[0]);
|
||||
increment(rows[1], columns[0]);
|
||||
|
||||
increment(rows[0], columns[1]);
|
||||
decrement(rows[1], columns[1]);
|
||||
|
||||
return (get(rows[0], columns[0]) >= 0 && get(rows[1], columns[1]) >= 0);
|
||||
}
|
||||
|
||||
public boolean rotateLeft() {
|
||||
String[] rows = rowNames.toArray(new String[1]);
|
||||
String[] columns = colNames.toArray(new String[1]);
|
||||
|
||||
increment(rows[0], columns[0]);
|
||||
decrement(rows[1], columns[0]);
|
||||
|
||||
decrement(rows[0], columns[1]);
|
||||
increment(rows[1], columns[1]);
|
||||
|
||||
return (get(rows[0], columns[1]) >= 0 && get(rows[1], columns[0]) >= 0);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a nicely-formatted version of the contents of the table.
|
||||
*
|
||||
* @return a String representing the contents of the table
|
||||
*/
|
||||
public String toString() {
|
||||
String tableString = "";
|
||||
boolean headerPrinted = false;
|
||||
|
||||
ArrayList<String> rows = getRowNames();
|
||||
ArrayList<String> cols = getColumnNames();
|
||||
|
||||
for (String rowName : rows) {
|
||||
if (!headerPrinted) {
|
||||
tableString += "rowName ";
|
||||
for (String colName : cols) {
|
||||
tableString += "\t" + colName;
|
||||
}
|
||||
tableString += "\n";
|
||||
|
||||
headerPrinted = true;
|
||||
}
|
||||
|
||||
tableString += rowName;
|
||||
|
||||
for (String colName : cols) {
|
||||
tableString += String.format("\t%7.7f", get(rowName, colName));
|
||||
}
|
||||
|
||||
tableString += "\n";
|
||||
}
|
||||
|
||||
return tableString;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue