Current section

Files

Jump to
penelope c_src deps crfsuite example crfutils.py
Raw

c_src/deps/crfsuite/example/crfutils.py

"""
A miscellaneous utility for sequential labeling.
Copyright 2010,2011 Naoaki Okazaki.
"""
import optparse
import sys
def apply_templates(X, templates):
"""
Generate features for an item sequence by applying feature templates.
A feature template consists of a tuple of (name, offset) pairs,
where name and offset specify a field name and offset from which
the template extracts a feature value. Generated features are stored
in the 'F' field of each item in the sequence.
@type X: list of mapping objects
@param X: The item sequence.
@type template: tuple of (str, int)
@param template: The feature template.
"""
for template in templates:
name = '|'.join(['%s[%d]' % (f, o) for f, o in template])
X_len = len(X)
for t in range(X_len):
values = []
for field, offset in template:
p = t + offset
if p < 0 or p >= X_len:
values = []
break
values.append(X[p][field])
if values:
X[t]['F'].append('%s=%s' % (name, '|'.join(values)))
def readiter(fi, names, sep=' '):
"""
Return an iterator for item sequences read from a file object.
This function reads a sequence from a file object L{fi}, and
yields the sequence as a list of mapping objects. Each line
(item) from the file object is split by the separator character
L{sep}. Separated values of the item are named by L{names},
and stored in a mapping object. Every item has a field 'F' that
is reserved for storing features.
@type fi: file
@param fi: The file object.
@type names: tuple
@param names: The list of field names.
@type sep: str
@param sep: The separator character.
@rtype list of mapping objects
@return An iterator for sequences.
"""
X = []
for line in fi:
line = line.strip('\n')
if not line:
yield X
X = []
else:
fields = line.split(sep)
if len(fields) < len(names):
raise ValueError(
'Too few fields (%d) for %r\n%s' % (len(fields), names, line))
item = {'F': []} # 'F' is reserved for features.
for i in range(len(names)):
item[names[i]] = fields[i]
X.append(item)
def escape(src):
"""
Escape colon characters from feature names.
@type src: str
@param src: A feature name
@rtype str
@return The feature name escaped.
"""
return src.replace(':', '__COLON__')
def output_features(fo, X, field=''):
"""
Output features (and reference labels) of a sequence in CRFSuite
format. For each item in the sequence, this function writes a
reference label (if L{field} is a non-empty string) and features.
@type fo: file
@param fo: The file object.
@type X: list of mapping objects
@param X: The sequence.
@type field: str
@param field: The field name of reference labels.
"""
for t in range(len(X)):
if field:
fo.write('%s' % X[t][field])
for a in X[t]['F']:
if isinstance(a, str):
fo.write('\t%s' % escape(a))
else:
fo.write('\t%s:%f' % (escape(a[0]), a[1]))
fo.write('\n')
fo.write('\n')
def to_crfsuite(X):
"""
Convert an item sequence into an object compatible with crfsuite
Python module.
@type X: list of mapping objects
@param X: The sequence.
@rtype crfsuite.ItemSequence
@return The same sequence in crfsuite.ItemSequence type.
"""
import crfsuite
xseq = crfsuite.ItemSequence()
for x in X:
item = crfsuite.Item()
for f in x['F']:
if isinstance(f, str):
item.append(crfsuite.Attribute(escape(f)))
else:
item.append(crfsuite.Attribute(escape(f[0]), f[1]))
xseq.append(item)
return xseq
def main(feature_extractor, fields='w pos y', sep=' '):
fi = sys.stdin
fo = sys.stdout
# Parse the command-line arguments.
parser = optparse.OptionParser(usage="""usage: %prog [options]
This utility reads a data set from STDIN, and outputs attributes to STDOUT.
Each line of a data set must consist of field values separated by SEPARATOR
characters. The names and order of field values can be specified by -f option.
The separator character can be specified with -s option. Instead of outputting
attributes, this utility tags the input data when a model file is specified by
-t option (CRFsuite Python module must be installed)."""
)
parser.add_option(
'-t', dest='model',
help='tag the input using the model (requires "crfsuite" module)'
)
parser.add_option(
'-f', dest='fields', default=fields,
help='specify field names of input data [default: "%default"]'
)
parser.add_option(
'-s', dest='separator', default=sep,
help='specify the separator of columns of input data [default: "%default"]'
)
(options, args) = parser.parse_args()
# The fields of input: ('w', 'pos', 'y) by default.
F = options.fields.split(' ')
if not options.model:
# The generator function readiter() reads a sequence from a
for X in readiter(fi, F, options.separator):
feature_extractor(X)
output_features(fo, X, 'y')
else:
# Create a tagger with an existing model.
import crfsuite
tagger = crfsuite.Tagger()
tagger.open(options.model)
# For each sequence from STDIN.
for X in readiter(fi, F, options.separator):
# Obtain features.
feature_extractor(X)
xseq = to_crfsuite(X)
yseq = tagger.tag(xseq)
for t in range(len(X)):
v = X[t]
fo.write('\t'.join([v[f] for f in F]))
fo.write('\t%s\n' % yseq[t])
fo.write('\n')