Added TableColumnAnalyzer

This commit is contained in:
Panupong Pasupat 2017-05-03 17:30:29 -07:00
parent f203345ffd
commit f041f1db03
3 changed files with 166 additions and 0 deletions

1
run
View File

@ -649,6 +649,7 @@ addMode('tables', 'QA on HTML tables', lambda { |e| l(
'alter' => l('edu.stanford.nlp.sempre.tables.alter.BatchTableAlterer', let(:parser, 'serialized')),
'alter-ex' => l('edu.stanford.nlp.sempre.tables.alter.AlteredTablesExecutor', let(:parser, 'serialized')),
'filter' => 'edu.stanford.nlp.sempre.tables.serialize.DumpFilterer',
'column' => 'edu.stanford.nlp.sempre.tables.test.TableColumnAnalyzer',
}),
# Fig parameters
selo(:cldir, 'execDir', '_OUTPATH_', '.'),

View File

@ -53,6 +53,7 @@ public final class StringNormalizationUtils {
// Cell normalization
// ============================================================
public static final Pattern STRICT_DASH = Pattern.compile("\\s*[-‐‑⁃‒–—―]\\s*");
public static final Pattern DASH = Pattern.compile("\\s*[-‐‑⁃‒–—―/,:;]\\s*");
public static final Pattern COMMA = Pattern.compile("\\s*(,\\s|\\n|/)\\s*");
public static final Pattern SPACE = Pattern.compile("\\s+");

View File

@ -0,0 +1,164 @@
package edu.stanford.nlp.sempre.tables.test;
import java.io.*;
import java.util.*;
import edu.stanford.nlp.sempre.*;
import edu.stanford.nlp.sempre.tables.*;
import fig.basic.*;
import fig.exec.Execution;
/**
* Analyze table columns and print out any hard-to-process column.
*
* @author ppasupat
*/
public class TableColumnAnalyzer implements Runnable {
public static class Options {
@Option(gloss = "Maximum number of tables to process (for debugging)")
public int maxNumTables = Integer.MAX_VALUE;
}
public static Options opts = new Options();
public static void main(String[] args) {
Execution.run(args, "TableColumnAnalyzerMain", new TableColumnAnalyzer(), Master.getOptionsParser());
}
PrintWriter out;
PrintWriter outCompact;
@Override
public void run() {
out = IOUtils.openOutHard(Execution.getFile("column-stats.tsv"));
outCompact = IOUtils.openOutHard(Execution.getFile("column-compact.tsv"));
Map<String, List<String>> tableIdToExIds = getTableIds();
int tablesProcessed = 0;
for (Map.Entry<String, List<String>> entry : tableIdToExIds.entrySet()) {
String tableId = entry.getKey(),
tableIdAbbrev = tableId.replaceAll("csv/(\\d+)-csv/(\\d+)\\.csv", "$1-$2");
LogInfo.begin_track("Processing %s ...", tableId);
TableKnowledgeGraph graph = TableKnowledgeGraph.fromFilename(tableId);
out.printf("%s\tIDS\t%s\n", tableIdAbbrev, String.join(" ", entry.getValue()));
out.printf("%s\tCOLUMNS\t%d\n", tableIdAbbrev, graph.numColumns());
for (int i = 0; i < graph.numColumns(); i++) {
analyzeColumn(graph, graph.columns.get(i), tableIdAbbrev + "\t" + i);
}
LogInfo.end_track();
if (tablesProcessed++ >= opts.maxNumTables) break;
}
out.close();
outCompact.close();
}
protected Map<String, List<String>> getTableIds() {
Map<String, List<String>> tableIdToExIds = new LinkedHashMap<>();
LogInfo.begin_track_printAll("Collect table IDs");
for (Pair<String, String> pathPair : Dataset.opts.inPaths) {
String group = pathPair.getFirst();
String path = pathPair.getSecond();
Execution.putOutput("group", group);
LogInfo.begin_track("Reading %s", path);
Iterator<LispTree> trees = LispTree.proto.parseFromFile(path);
while (trees.hasNext()) {
LispTree tree = trees.next();
if ("metadata".equals(tree.child(0).value)) continue;
String exId = null, tableId = null;
for (int i = 1; i < tree.children.size(); i++) {
LispTree arg = tree.child(i);
String label = arg.child(0).value;
if ("id".equals(label)) {
exId = arg.child(1).value;
} else if ("context".equals(label)) {
tableId = arg.child(1).child(2).value;
}
}
if (exId != null && tableId != null) {
List<String> exIdsForTable = tableIdToExIds.get(tableId);
if (exIdsForTable == null)
tableIdToExIds.put(tableId, exIdsForTable = new ArrayList<>());
exIdsForTable.add(exId);
}
}
LogInfo.end_track();
}
LogInfo.end_track();
LogInfo.logs("Got %d IDs", tableIdToExIds.size());
return tableIdToExIds;
}
protected void analyzeColumn(TableKnowledgeGraph graph, TableColumn column, String printPrefix) {
List<String> escapedCells = new ArrayList<>();
// Print the header
String h = column.originalString, escapedH = StringNormalizationUtils.escapeTSV(h);
out.printf("%s\t0\t%s\n", printPrefix, escapedH);
escapedCells.add(escapedH);
// Print the cells
Map<String, Integer> typeCounts = new HashMap<>();
for (int j = 0; j < column.children.size(); j++) {
TableCell cell = column.children.get(j);
String c = cell.properties.originalString, escapedC = StringNormalizationUtils.escapeTSV(c);
escapedCells.add(escapedC);
// Infer the type
List<String> types = analyzeCell(c);
for (String type : types)
MapUtils.incr(typeCounts, type);
out.printf("%s\t%d\t%s\t%s\n", printPrefix, j + 1, String.join("|", types), escapedC);
}
// Analyze the common types
List<String> commonTypes = new ArrayList<>();
for (Map.Entry<String, Integer> entry : typeCounts.entrySet()) {
if (entry.getValue() == column.children.size()) {
commonTypes.add(entry.getKey());
} else if (entry.getValue() == column.children.size() - 1) {
commonTypes.add("ALMOST-" + entry.getKey());
}
}
outCompact.printf("%s\t%s\t%s\n", String.join("|", commonTypes), printPrefix, String.join("\t", escapedCells));
}
// ============================================================
// Cell analysis
// ============================================================
protected List<String> analyzeCell(String c) {
List<String> types = new ArrayList<>();
LanguageInfo languageInfo = LanguageAnalyzer.getSingleton().analyze(c);
{
// Integer
NumberValue n = StringNormalizationUtils.parseNumberStrict(c);
if (n != null) {
// Number
types.add("num");
// Integer
double value = n.value;
if (Math.abs(value - Math.round(value)) < 1e-9) {
types.add("int");
if (c.matches("^[12]\\d\\d\\d$")) {
// Year?
types.add("year");
}
}
}
}
{
// Ordinal
}
{
// Integer-Integer
String[] splitted = StringNormalizationUtils.STRICT_DASH.split(c);
if (splitted.length == 2 && splitted[0].matches("^[0-9]+$") && splitted[1].matches("^[0-9]+$")) {
types.add("2ints");
}
}
{
// Date
DateValue date = StringNormalizationUtils.parseDateWithLanguageAnalyzer(languageInfo);
if (date != null) {
types.add("date");
}
}
return types;
}
}