mirror of https://github.com/percyliang/sempre
Added more features
This commit is contained in:
parent
c475bddba2
commit
8a987add98
12
run
12
run
|
|
@ -675,7 +675,7 @@ addMode('tables', 'QA on HTML tables', lambda { |e| l(
|
|||
}),
|
||||
# Parser
|
||||
letDefault(:parser, 'floatsize'),
|
||||
o('beamSize', 100),
|
||||
o('beamSize', 50),
|
||||
o('useSizeInsteadOfDepth'),
|
||||
sel(:parser, {
|
||||
'floatsize' => l(
|
||||
|
|
@ -728,8 +728,8 @@ addMode('tables', 'QA on HTML tables', lambda { |e| l(
|
|||
nil),
|
||||
'editdist-fuzzy' => l(
|
||||
o('FuzzyMatcher.fuzzyMatcher', 'tables.match.EditDistanceFuzzyMatcher'),
|
||||
o('fuzzyMatchSubstring'), o('fuzzyMatchMaxEditDistanceRatio', 0.3),
|
||||
o('alsoReturnUnion'), o('alsoMatchPart'),
|
||||
o('fuzzyMatchSubstring'), o('fuzzyMatchMaxEditDistanceRatio', 0.15),
|
||||
o('alsoMatchPart'),
|
||||
nil),
|
||||
}),
|
||||
letDefault(:normalize, 1),
|
||||
|
|
@ -814,10 +814,14 @@ addMode('tables', 'QA on HTML tables', lambda { |e| l(
|
|||
'some' => l( # Add your own features! (only set up the feature computers)
|
||||
o('FeatureExtractor.featureComputers', 'tables.features.PhrasePredicateFeatureComputer tables.features.PhraseDenotationFeatureComputer'.split),
|
||||
nil),
|
||||
'all' => l( # All features
|
||||
'all' => l( # All ACL 2015 features
|
||||
o('FeatureExtractor.featureDomains', 'custom-denotation phrase-predicate phrase-denotation headword-denotation missing-predicate'.split),
|
||||
o('FeatureExtractor.featureComputers', 'tables.features.PhrasePredicateFeatureComputer tables.features.PhraseDenotationFeatureComputer'.split),
|
||||
nil),
|
||||
'more' => l( # All ACL 2015 features + more experimental features
|
||||
o('FeatureExtractor.featureDomains', 'custom-denotation phrase-predicate phrase-denotation headword-denotation missing-predicate anchored-entity'.split),
|
||||
o('FeatureExtractor.featureComputers', 'tables.features.PhrasePredicateFeatureComputer tables.features.PhraseDenotationFeatureComputer tables.features.AnchorFeatureComputer'.split),
|
||||
nil),
|
||||
'baseline' => l( # For the baseline classifier
|
||||
o('FeatureExtractor.featureDomains', 'custom-denotation phrase-denotation headword-denotation table-baseline'.split),
|
||||
o('FeatureExtractor.featureComputers', 'tables.baseline.TableBaselineFeatureComputer tables.features.PhraseDenotationFeatureComputer'.split),
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ public class FuzzyMatchFn extends SemanticFn {
|
|||
}
|
||||
}
|
||||
|
||||
public FuzzyMatchFnMode getMode() { return mode; }
|
||||
public boolean getMatchAny() { return matchAny; }
|
||||
|
||||
@Override
|
||||
public DerivationStream call(Example ex, Callable c) {
|
||||
return new LazyFuzzyMatchFnDerivs(ex, c, mode, matchAny);
|
||||
|
|
|
|||
|
|
@ -660,6 +660,18 @@ public class TableKnowledgeGraph extends KnowledgeGraph implements FuzzyMatchabl
|
|||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the column with the specified ID. Return -1 if not found.
|
||||
*/
|
||||
public int getColumnIndex(String nameValueId) {
|
||||
if (nameValueId.startsWith("!"))
|
||||
nameValueId = nameValueId.substring(1);
|
||||
for (int j = 0; j < columns.size(); j++) {
|
||||
if (columns.get(j).relationNameValue.id.equals(nameValueId)) return j;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Test
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package edu.stanford.nlp.sempre.tables.features;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import edu.stanford.nlp.sempre.*;
|
||||
import edu.stanford.nlp.sempre.tables.StringNormalizationUtils;
|
||||
import edu.stanford.nlp.sempre.tables.TableKnowledgeGraph;
|
||||
import edu.stanford.nlp.sempre.tables.TableCell;
|
||||
import edu.stanford.nlp.sempre.tables.TableColumn;
|
||||
import fig.basic.LogInfo;
|
||||
|
||||
public class AnchorFeatureComputer implements FeatureComputer {
|
||||
|
||||
@Override
|
||||
public void extractLocal(Example ex, Derivation deriv) {
|
||||
if (!(FeatureExtractor.containsDomain("anchored-entity"))) return;
|
||||
if (!(deriv.rule.sem instanceof FuzzyMatchFn)) return;
|
||||
FuzzyMatchFn sem = (FuzzyMatchFn) deriv.rule.sem;
|
||||
if (sem.getMatchAny() || sem.getMode() != FuzzyMatchFn.FuzzyMatchFnMode.ENTITY) return;
|
||||
String phrase = ((StringValue) ((ValueFormula<?>) deriv.child(0).formula).value).value;
|
||||
NameValue predicate = (NameValue) ((ValueFormula<?>) deriv.formula).value;
|
||||
TableKnowledgeGraph graph = (TableKnowledgeGraph) ex.context.graph;
|
||||
extractMatchingFeatures(graph, deriv, phrase, predicate);
|
||||
}
|
||||
|
||||
private void extractMatchingFeatures(TableKnowledgeGraph graph,
|
||||
Derivation deriv, String phrase, NameValue predicate) {
|
||||
LogInfo.logs("%s -> %s", phrase, predicate);
|
||||
// Type of match
|
||||
String predicateString = graph.getOriginalString(predicate);
|
||||
predicateString = StringNormalizationUtils.simpleNormalize(predicateString).toLowerCase();
|
||||
if (predicateString.equals(phrase)) {
|
||||
deriv.addFeature("a-e", "exact");
|
||||
LogInfo.logs("%s %s exact", phrase, predicateString);
|
||||
} else if (predicateString.startsWith(phrase + " ")) {
|
||||
deriv.addFeature("a-e", "prefix");
|
||||
LogInfo.logs("%s %s prefix", phrase, predicateString);
|
||||
} else if (predicateString.endsWith(" " + phrase)) {
|
||||
deriv.addFeature("a-e", "suffix");
|
||||
LogInfo.logs("%s %s suffix", phrase, predicateString);
|
||||
} else if (predicateString.contains(" " + phrase + " ")){
|
||||
deriv.addFeature("a-e", "substring");
|
||||
LogInfo.logs("%s %s substring", phrase, predicateString);
|
||||
} else {
|
||||
deriv.addFeature("a-e", "other");
|
||||
LogInfo.logs("%s %s other", phrase, predicateString);
|
||||
}
|
||||
// Does the phrase match other cells?
|
||||
Set<String> matches = new HashSet<>();
|
||||
for (TableColumn column : graph.columns) {
|
||||
for (TableCell cell : column.children) {
|
||||
String s = StringNormalizationUtils.simpleNormalize(cell.properties.originalString).toLowerCase();
|
||||
if (s.contains(phrase) && !cell.properties.id.equals(predicate.id)) {
|
||||
matches.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
LogInfo.logs(">> %s", matches);
|
||||
if (matches.size() == 0) {
|
||||
deriv.addFeature("a-e", "unique");
|
||||
} else if (matches.size() < 3) {
|
||||
deriv.addFeature("a-e", "multiple;" + matches.size());
|
||||
} else {
|
||||
deriv.addFeature("a-e", "multiple;>=3");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package edu.stanford.nlp.sempre.tables.features;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import edu.stanford.nlp.sempre.Example;
|
||||
import edu.stanford.nlp.sempre.tables.TableKnowledgeGraph;
|
||||
import fig.basic.*;
|
||||
|
||||
public class ColumnCategoryInfo {
|
||||
public static class Options {
|
||||
@Option(gloss = "Read category information from this file")
|
||||
public String tableCategoryInfo = null;
|
||||
}
|
||||
public static Options opts = new Options();
|
||||
|
||||
// ============================================================
|
||||
// Singleton access
|
||||
// ============================================================
|
||||
|
||||
private static ColumnCategoryInfo singleton;
|
||||
|
||||
public static ColumnCategoryInfo getSingleton() {
|
||||
if (opts.tableCategoryInfo == null)
|
||||
return null;
|
||||
else if (singleton == null)
|
||||
singleton = new ColumnCategoryInfo();
|
||||
return singleton;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Read data from file
|
||||
// ============================================================
|
||||
|
||||
// tableId -> columnIndex -> list of (category, weight)
|
||||
protected static Map<String, List<List<Pair<String, Double>>>> allCategoryInfo = null;
|
||||
|
||||
private ColumnCategoryInfo() {
|
||||
LogInfo.begin_track("Loading category information from %s", opts.tableCategoryInfo);
|
||||
allCategoryInfo = new HashMap<>();
|
||||
try {
|
||||
BufferedReader reader = IOUtils.openIn(opts.tableCategoryInfo);
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] tokens = line.split("\t");
|
||||
String tableId = tokens[0];
|
||||
List<List<Pair<String, Double>>> categoryInfoForTable = allCategoryInfo.get(tableId);
|
||||
if (categoryInfoForTable == null)
|
||||
allCategoryInfo.put(tableId, categoryInfoForTable = new ArrayList<>());
|
||||
int columnIndex = Integer.parseInt(tokens[1]);
|
||||
// Assume that the columns are ordered
|
||||
assert categoryInfoForTable.size() == columnIndex;
|
||||
// Read the category-weight pairs
|
||||
List<Pair<String, Double>> categories = new ArrayList<>();
|
||||
for (int i = 2; i < tokens.length; i++) {
|
||||
String[] pair = tokens[i].split(":");
|
||||
categories.add(new Pair<>(pair[0], Double.parseDouble(pair[1])));
|
||||
}
|
||||
categoryInfoForTable.add(categories);
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
LogInfo.end_track();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Getters
|
||||
// ============================================================
|
||||
|
||||
public List<Pair<String, Double>> get(String tableId, int columnIndex) {
|
||||
return allCategoryInfo.get(tableId).get(columnIndex);
|
||||
}
|
||||
|
||||
public List<Pair<String, Double>> get(Example ex, String columnId) {
|
||||
TableKnowledgeGraph graph = (TableKnowledgeGraph) ex.context.graph;
|
||||
String tableId = graph.filename;
|
||||
int columnIndex = graph.getColumnIndex(columnId);
|
||||
if (columnIndex == -1) return null;
|
||||
return allCategoryInfo.get(tableId).get(columnIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -113,6 +113,7 @@ public class PhraseDenotationFeatureComputer implements FeatureComputer {
|
|||
LogInfo.logs("%s %s %s", deriv.value, deriv.type, denotationTypes);
|
||||
for (String denotationType : denotationTypes) {
|
||||
for (PhraseInfo phraseInfo : phraseInfos) {
|
||||
if (PhraseInfo.opts.forbidBorderStopWordInLexicalizedFeatures && phraseInfo.isBorderStopWord) continue;
|
||||
deriv.addFeature("p-d", phraseInfo.lemmaText + ";" + denotationType);
|
||||
}
|
||||
// Check original column text
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package edu.stanford.nlp.sempre.tables.features;
|
|||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.cache.*;
|
||||
|
||||
|
|
@ -23,6 +24,8 @@ public class PhraseInfo {
|
|||
public int maxPhraseLength = 3;
|
||||
@Option(gloss = "Fuzzy match predicates")
|
||||
public boolean computeFuzzyMatchPredicates = false;
|
||||
@Option(gloss = "Do not produce lexicalized features if the phrase begins or ends with a stop word")
|
||||
public boolean forbidBorderStopWordInLexicalizedFeatures = false;
|
||||
}
|
||||
public static Options opts = new Options();
|
||||
|
||||
|
|
@ -35,6 +38,7 @@ public class PhraseInfo {
|
|||
public final List<String> nerTags;
|
||||
public final String canonicalPosSeq;
|
||||
public final List<String> fuzzyMatchedPredicates;
|
||||
public final boolean isBorderStopWord; // true if the first or last word is a stop word
|
||||
|
||||
public PhraseInfo(Example ex, int start, int end) {
|
||||
this.start = start;
|
||||
|
|
@ -49,6 +53,7 @@ public class PhraseInfo {
|
|||
lemmaText = languageInfo.lemmaPhrase(start, end).toLowerCase();
|
||||
canonicalPosSeq = languageInfo.canonicalPosSeq(start, end);
|
||||
fuzzyMatchedPredicates = opts.computeFuzzyMatchPredicates ? getFuzzyMatchedPredicates(ex.context) : null;
|
||||
isBorderStopWord = isStopWord(languageInfo.lemmaTokens.get(start)) || isStopWord(languageInfo.lemmaTokens.get(end - 1));
|
||||
}
|
||||
|
||||
private List<String> getFuzzyMatchedPredicates(ContextValue context) {
|
||||
|
|
@ -71,6 +76,17 @@ public class PhraseInfo {
|
|||
return matchedPredicates;
|
||||
}
|
||||
|
||||
static final Pattern ALL_PUNCT = Pattern.compile("^[^A-Za-z0-9]*$");
|
||||
static final Set<String> STOP_WORDS = new HashSet<>(Arrays.asList(
|
||||
"a", "an", "the", "be", "of", "in", "on", "do"
|
||||
));
|
||||
|
||||
static boolean isStopWord(String x) {
|
||||
if (ALL_PUNCT.matcher(x).matches()) return true;
|
||||
if (STOP_WORDS.contains(x)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "\"" + text + "\"";
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ public class PhrasePredicateFeatureComputer implements FeatureComputer {
|
|||
public boolean lexicalizedPhrasePredicate = true;
|
||||
@Option(gloss = "Maximum ngram length for lexicalize all pair features")
|
||||
public int maxNforLexicalizeAllPairs = Integer.MAX_VALUE;
|
||||
@Option(gloss = "phrase-category: Weight threshold")
|
||||
public double phraseCategoryWeightThreshold = 0.8;
|
||||
@Option(gloss = "phrase-category: Use binary features instead of continuous ones")
|
||||
public boolean phraseCategoryBinary = true;
|
||||
|
||||
}
|
||||
public static Options opts = new Options();
|
||||
|
||||
|
|
@ -47,7 +52,8 @@ public class PhrasePredicateFeatureComputer implements FeatureComputer {
|
|||
@Override
|
||||
public void extractLocal(Example ex, Derivation deriv) {
|
||||
if (!(FeatureExtractor.containsDomain("phrase-predicate")
|
||||
|| FeatureExtractor.containsDomain("missing-predicate"))) return;
|
||||
|| FeatureExtractor.containsDomain("phrase-formula")
|
||||
|| FeatureExtractor.containsDomain("phrase-category"))) return;
|
||||
// Only compute features at the root, except when the partial option is set.
|
||||
if (!opts.defineOnPartialDerivs && !deriv.isRoot(ex.numTokens())) return;
|
||||
List<PhraseInfo> phraseInfos = PhraseInfo.getPhraseInfos(ex);
|
||||
|
|
@ -58,7 +64,8 @@ public class PhrasePredicateFeatureComputer implements FeatureComputer {
|
|||
LogInfo.logs("Derivation: %s", deriv);
|
||||
LogInfo.logs("Predicates: %s", predicateInfos);
|
||||
}
|
||||
if (FeatureExtractor.containsDomain("phrase-predicate")) {
|
||||
if (FeatureExtractor.containsDomain("phrase-predicate")
|
||||
|| FeatureExtractor.containsDomain("phrase-category")) {
|
||||
if (opts.defineOnPartialDerivs) {
|
||||
deriv.getTempState().put("p-p", new ArrayList<>(predicateInfos));
|
||||
// Subtract predicates from children
|
||||
|
|
@ -109,7 +116,7 @@ public class PhrasePredicateFeatureComputer implements FeatureComputer {
|
|||
private void extractMatch(Example ex, Derivation deriv,
|
||||
PhraseInfo phraseInfo, String phraseString, String phraseType,
|
||||
PredicateInfo predicateInfo, String predicateString, String predicateType, double factor) {
|
||||
if (opts.unlexicalizedPhrasePredicate) {
|
||||
if (FeatureExtractor.containsDomain("phrase-predicate") && opts.unlexicalizedPhrasePredicate) {
|
||||
if (phraseString.equals(predicateString)) {
|
||||
defineFeatures(ex, deriv, phraseInfo, predicateInfo, phraseType + "=" + predicateType,
|
||||
phraseString, predicateString, factor);
|
||||
|
|
@ -132,10 +139,27 @@ public class PhrasePredicateFeatureComputer implements FeatureComputer {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (opts.lexicalizedPhrasePredicate && phraseInfo.end - phraseInfo.start <= maxNforLexicalizeAllPairs) {
|
||||
if (FeatureExtractor.containsDomain("phrase-predicate") && opts.lexicalizedPhrasePredicate
|
||||
&& phraseInfo.end - phraseInfo.start <= maxNforLexicalizeAllPairs
|
||||
&& (!PhraseInfo.opts.forbidBorderStopWordInLexicalizedFeatures || !phraseInfo.isBorderStopWord)) {
|
||||
deriv.addFeature("p-p",
|
||||
phraseType + phraseString + ";" + predicateType + predicateString, factor);
|
||||
}
|
||||
if (FeatureExtractor.containsDomain("phrase-category") && predicateInfo.type == PredicateType.BINARY
|
||||
&& (!PhraseInfo.opts.forbidBorderStopWordInLexicalizedFeatures || !phraseInfo.isBorderStopWord)) {
|
||||
ColumnCategoryInfo catInfo = ColumnCategoryInfo.getSingleton();
|
||||
List<Pair<String, Double>> categories = catInfo.get(ex, predicateInfo.predicate);
|
||||
if (categories != null) {
|
||||
for (Pair<String, Double> pair : categories) {
|
||||
if (pair.getSecond() >= opts.phraseCategoryWeightThreshold) {
|
||||
if (opts.phraseCategoryBinary)
|
||||
deriv.addFeature("p-c", phraseType + phraseString + ";" + pair.getFirst());
|
||||
else
|
||||
deriv.addFeature("p-c", phraseType + phraseString + ";" + pair.getFirst(), pair.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void defineFeatures(Example ex, Derivation deriv, PhraseInfo phraseInfo, PredicateInfo predicateInfo,
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ public final class DenotationUtils {
|
|||
*/
|
||||
public static UnaryDenotation superlativeUnary(int rank, int count, List<Pair<Value, Value>> pairs,
|
||||
SuperlativeFormula.Mode mode, TypeProcessor processor) {
|
||||
if (rank <= 0 || count <= 0)
|
||||
if (rank <= 0 || count <= 0 || rank >= 1000000 || count >= 100000)
|
||||
LogInfo.fails("Invalid superlative (rank = %d, count = %d)", rank, count);
|
||||
if (pairs.isEmpty()) {
|
||||
if (LambdaDCSExecutor.opts.superlativesFailOnEmptyLists)
|
||||
|
|
@ -269,7 +269,7 @@ public final class DenotationUtils {
|
|||
default: throw new LambdaDCSException(Type.invalidFormula, "Unknown superlative mode: %s", mode);
|
||||
}
|
||||
int from = Math.min(rank - 1, indices.size()),
|
||||
to = Math.min(Math.max(from, from + count), indices.size());
|
||||
to = Math.min(from + count, indices.size());
|
||||
for (int index : indices.subList(from, to))
|
||||
answer.add(pairs.get(index).getSecond());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue