nltk 3.2__zip → 3.3__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nltk-3.2 → nltk-3.3}/INSTALL.txt +6 -6
- {nltk-3.2 → nltk-3.3}/LICENSE.txt +13 -13
- {nltk-3.2 → nltk-3.3}/MANIFEST.in +6 -6
- {nltk-3.2/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
- nltk-3.2/README.txt → nltk-3.3/README.md +49 -48
- nltk-3.3/nltk/VERSION +1 -0
- {nltk-3.2 → nltk-3.3}/nltk/__init__.py +185 -185
- {nltk-3.2 → nltk-3.3}/nltk/app/__init__.py +52 -53
- {nltk-3.2 → nltk-3.3}/nltk/app/chartparser_app.py +2276 -2276
- {nltk-3.2 → nltk-3.3}/nltk/app/chunkparser_app.py +1262 -1264
- {nltk-3.2 → nltk-3.3}/nltk/app/collocations_app.py +347 -350
- {nltk-3.2 → nltk-3.3}/nltk/app/concordance_app.py +568 -570
- {nltk-3.2 → nltk-3.3}/nltk/app/nemo_app.py +156 -155
- {nltk-3.2 → nltk-3.3}/nltk/app/rdparser_app.py +892 -894
- {nltk-3.2 → nltk-3.3}/nltk/app/srparser_app.py +809 -809
- {nltk-3.2 → nltk-3.3}/nltk/app/wordfreq_app.py +32 -32
- {nltk-3.2 → nltk-3.3}/nltk/app/wordnet_app.py +968 -968
- {nltk-3.2 → nltk-3.3}/nltk/book.py +91 -90
- {nltk-3.2 → nltk-3.3}/nltk/ccg/__init__.py +22 -22
- {nltk-3.2 → nltk-3.3}/nltk/ccg/api.py +359 -335
- {nltk-3.2 → nltk-3.3}/nltk/ccg/chart.py +394 -361
- {nltk-3.2 → nltk-3.3}/nltk/ccg/combinator.py +343 -312
- {nltk-3.2 → nltk-3.3}/nltk/ccg/lexicon.py +328 -290
- nltk-3.3/nltk/ccg/logic.py +46 -0
- {nltk-3.2 → nltk-3.3}/nltk/chat/__init__.py +49 -49
- {nltk-3.2 → nltk-3.3}/nltk/chat/eliza.py +244 -244
- {nltk-3.2 → nltk-3.3}/nltk/chat/iesha.py +140 -140
- {nltk-3.2 → nltk-3.3}/nltk/chat/rude.py +92 -92
- {nltk-3.2 → nltk-3.3}/nltk/chat/suntsu.py +117 -117
- {nltk-3.2 → nltk-3.3}/nltk/chat/util.py +122 -120
- {nltk-3.2 → nltk-3.3}/nltk/chat/zen.py +282 -282
- {nltk-3.2 → nltk-3.3}/nltk/chunk/__init__.py +190 -190
- {nltk-3.2 → nltk-3.3}/nltk/chunk/api.py +51 -51
- {nltk-3.2 → nltk-3.3}/nltk/chunk/named_entity.py +331 -331
- {nltk-3.2 → nltk-3.3}/nltk/chunk/regexp.py +1390 -1384
- {nltk-3.2 → nltk-3.3}/nltk/chunk/util.py +600 -600
- {nltk-3.2 → nltk-3.3}/nltk/classify/__init__.py +98 -98
- {nltk-3.2 → nltk-3.3}/nltk/classify/api.py +193 -193
- {nltk-3.2 → nltk-3.3}/nltk/classify/decisiontree.py +295 -295
- {nltk-3.2 → nltk-3.3}/nltk/classify/maxent.py +1510 -1492
- {nltk-3.2 → nltk-3.3}/nltk/classify/megam.py +179 -178
- {nltk-3.2 → nltk-3.3}/nltk/classify/naivebayes.py +245 -242
- {nltk-3.2 → nltk-3.3}/nltk/classify/positivenaivebayes.py +170 -170
- {nltk-3.2 → nltk-3.3}/nltk/classify/rte_classify.py +160 -191
- {nltk-3.2 → nltk-3.3}/nltk/classify/scikitlearn.py +153 -151
- {nltk-3.2 → nltk-3.3}/nltk/classify/senna.py +183 -181
- {nltk-3.2 → nltk-3.3}/nltk/classify/svm.py +15 -15
- {nltk-3.2 → nltk-3.3}/nltk/classify/tadm.py +113 -112
- {nltk-3.2 → nltk-3.3}/nltk/classify/textcat.py +193 -193
- {nltk-3.2 → nltk-3.3}/nltk/classify/util.py +324 -312
- {nltk-3.2 → nltk-3.3}/nltk/classify/weka.py +346 -345
- {nltk-3.2 → nltk-3.3}/nltk/cluster/__init__.py +86 -86
- {nltk-3.2 → nltk-3.3}/nltk/cluster/api.py +74 -70
- {nltk-3.2 → nltk-3.3}/nltk/cluster/em.py +247 -247
- {nltk-3.2 → nltk-3.3}/nltk/cluster/gaac.py +168 -168
- {nltk-3.2 → nltk-3.3}/nltk/cluster/kmeans.py +221 -221
- {nltk-3.2 → nltk-3.3}/nltk/cluster/util.py +304 -289
- nltk-3.3/nltk/collections.py +640 -0
- {nltk-3.2 → nltk-3.3}/nltk/collocations.py +388 -388
- nltk-3.3/nltk/compat.py +365 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/__init__.py +341 -320
- {nltk-3.2 → nltk-3.3}/nltk/corpus/europarl_raw.py +44 -44
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/__init__.py +147 -145
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/aligned.py +115 -114
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/api.py +448 -446
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bnc.py +252 -252
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +227 -227
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +179 -178
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chasen.py +140 -139
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/childes.py +522 -494
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chunked.py +212 -212
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/cmudict.py +97 -95
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +280 -278
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/conll.py +528 -521
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/crubadan.py +116 -116
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/dependency.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/framenet.py +3059 -2093
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ieer.py +112 -111
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/indian.py +85 -86
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ipipan.py +332 -331
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/knbc.py +187 -187
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/lin.py +156 -156
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/mte.py +311 -310
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nkjp.py +429 -428
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nombank.py +421 -421
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +73 -73
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +115 -115
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +165 -165
- nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/plaintext.py +232 -233
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ppattach.py +96 -95
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/propbank.py +479 -481
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +128 -126
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/reviews.py +330 -328
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/rte.py +144 -146
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/semcor.py +256 -256
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/senseval.py +203 -201
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +137 -137
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +75 -75
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/string_category.py +60 -59
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/switchboard.py +119 -119
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/tagged.py +295 -294
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/timit.py +452 -450
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/toolbox.py +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/twitter.py +155 -157
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/udhr.py +80 -80
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/util.py +804 -800
- nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
- nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/wordnet.py +2108 -2036
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +392 -387
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ycoe.py +243 -242
- {nltk-3.2 → nltk-3.3}/nltk/corpus/util.py +144 -127
- {nltk-3.2 → nltk-3.3}/nltk/data.py +1487 -1451
- {nltk-3.2 → nltk-3.3}/nltk/decorators.py +219 -215
- {nltk-3.2 → nltk-3.3}/nltk/downloader.py +2278 -2274
- {nltk-3.2 → nltk-3.3}/nltk/draw/__init__.py +27 -27
- {nltk-3.2 → nltk-3.3}/nltk/draw/cfg.py +774 -777
- {nltk-3.2 → nltk-3.3}/nltk/draw/dispersion.py +58 -58
- {nltk-3.2 → nltk-3.3}/nltk/draw/table.py +1098 -1098
- {nltk-3.2 → nltk-3.3}/nltk/draw/tree.py +963 -966
- {nltk-3.2 → nltk-3.3}/nltk/draw/util.py +2356 -2356
- {nltk-3.2 → nltk-3.3}/nltk/featstruct.py +2617 -2500
- {nltk-3.2 → nltk-3.3}/nltk/grammar.py +1559 -1516
- {nltk-3.2 → nltk-3.3}/nltk/help.py +56 -56
- {nltk-3.2 → nltk-3.3}/nltk/inference/__init__.py +20 -20
- {nltk-3.2 → nltk-3.3}/nltk/inference/api.py +597 -589
- {nltk-3.2 → nltk-3.3}/nltk/inference/discourse.py +612 -608
- {nltk-3.2 → nltk-3.3}/nltk/inference/mace.py +311 -311
- {nltk-3.2 → nltk-3.3}/nltk/inference/nonmonotonic.py +509 -509
- {nltk-3.2 → nltk-3.3}/nltk/inference/prover9.py +431 -431
- {nltk-3.2 → nltk-3.3}/nltk/inference/resolution.py +687 -687
- {nltk-3.2 → nltk-3.3}/nltk/inference/tableau.py +607 -607
- {nltk-3.2 → nltk-3.3}/nltk/internals.py +982 -982
- {nltk-3.2 → nltk-3.3}/nltk/jsontags.py +63 -63
- {nltk-3.2 → nltk-3.3}/nltk/lazyimport.py +142 -142
- {nltk-3.2 → nltk-3.3}/nltk/metrics/__init__.py +30 -29
- {nltk-3.2 → nltk-3.3}/nltk/metrics/agreement.py +421 -401
- nltk-3.3/nltk/metrics/aline.py +607 -0
- {nltk-3.2 → nltk-3.3}/nltk/metrics/association.py +414 -410
- {nltk-3.2 → nltk-3.3}/nltk/metrics/confusionmatrix.py +206 -206
- {nltk-3.2 → nltk-3.3}/nltk/metrics/distance.py +207 -202
- {nltk-3.2 → nltk-3.3}/nltk/metrics/paice.py +381 -381
- {nltk-3.2 → nltk-3.3}/nltk/metrics/scores.py +228 -228
- {nltk-3.2 → nltk-3.3}/nltk/metrics/segmentation.py +231 -232
- {nltk-3.2 → nltk-3.3}/nltk/metrics/spearman.py +69 -69
- {nltk-3.2 → nltk-3.3}/nltk/misc/__init__.py +11 -11
- {nltk-3.2 → nltk-3.3}/nltk/misc/babelfish.py +10 -10
- {nltk-3.2 → nltk-3.3}/nltk/misc/chomsky.py +135 -133
- {nltk-3.2 → nltk-3.3}/nltk/misc/minimalset.py +83 -83
- {nltk-3.2 → nltk-3.3}/nltk/misc/sort.py +157 -157
- {nltk-3.2 → nltk-3.3}/nltk/misc/wordfinder.py +129 -129
- {nltk-3.2 → nltk-3.3}/nltk/parse/__init__.py +81 -80
- {nltk-3.2 → nltk-3.3}/nltk/parse/api.py +66 -66
- {nltk-3.2 → nltk-3.3}/nltk/parse/bllip.py +282 -282
- {nltk-3.2 → nltk-3.3}/nltk/parse/chart.py +1682 -1681
- nltk-3.3/nltk/parse/corenlp.py +780 -0
- {nltk-3.2 → nltk-3.3}/nltk/parse/dependencygraph.py +760 -758
- {nltk-3.2 → nltk-3.3}/nltk/parse/earleychart.py +452 -451
- {nltk-3.2 → nltk-3.3}/nltk/parse/evaluate.py +129 -129
- {nltk-3.2 → nltk-3.3}/nltk/parse/featurechart.py +580 -578
- {nltk-3.2 → nltk-3.3}/nltk/parse/generate.py +87 -76
- {nltk-3.2 → nltk-3.3}/nltk/parse/malt.py +356 -356
- {nltk-3.2 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +783 -783
- {nltk-3.2 → nltk-3.3}/nltk/parse/pchart.py +522 -522
- {nltk-3.2 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +579 -578
- {nltk-3.2 → nltk-3.3}/nltk/parse/recursivedescent.py +655 -656
- {nltk-3.2 → nltk-3.3}/nltk/parse/shiftreduce.py +458 -459
- {nltk-3.2 → nltk-3.3}/nltk/parse/stanford.py +431 -406
- {nltk-3.2 → nltk-3.3}/nltk/parse/transitionparser.py +774 -772
- {nltk-3.2 → nltk-3.3}/nltk/parse/util.py +231 -231
- {nltk-3.2 → nltk-3.3}/nltk/parse/viterbi.py +401 -401
- {nltk-3.2 → nltk-3.3}/nltk/probability.py +2410 -2355
- {nltk-3.2 → nltk-3.3}/nltk/sem/__init__.py +61 -61
- {nltk-3.2 → nltk-3.3}/nltk/sem/boxer.py +1261 -1261
- {nltk-3.2 → nltk-3.3}/nltk/sem/chat80.py +782 -782
- {nltk-3.2 → nltk-3.3}/nltk/sem/cooper_storage.py +118 -118
- {nltk-3.2 → nltk-3.3}/nltk/sem/drt.py +1258 -1257
- {nltk-3.2 → nltk-3.3}/nltk/sem/drt_glue_demo.py +485 -489
- {nltk-3.2 → nltk-3.3}/nltk/sem/evaluate.py +790 -784
- {nltk-3.2 → nltk-3.3}/nltk/sem/glue.py +696 -694
- {nltk-3.2 → nltk-3.3}/nltk/sem/hole.py +386 -384
- {nltk-3.2 → nltk-3.3}/nltk/sem/lfg.py +210 -208
- {nltk-3.2 → nltk-3.3}/nltk/sem/linearlogic.py +451 -449
- {nltk-3.2 → nltk-3.3}/nltk/sem/logic.py +1910 -1910
- {nltk-3.2 → nltk-3.3}/nltk/sem/relextract.py +476 -483
- {nltk-3.2 → nltk-3.3}/nltk/sem/skolemize.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/sem/util.py +249 -249
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/__init__.py +14 -14
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +229 -229
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/util.py +762 -752
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/vader.py +443 -445
- {nltk-3.2 → nltk-3.3}/nltk/stem/__init__.py +31 -33
- {nltk-3.2 → nltk-3.3}/nltk/stem/api.py +28 -25
- nltk-3.3/nltk/stem/arlstem.py +369 -0
- {nltk-3.2 → nltk-3.3}/nltk/stem/isri.py +345 -345
- {nltk-3.2 → nltk-3.3}/nltk/stem/lancaster.py +337 -310
- nltk-3.3/nltk/stem/porter.py +710 -0
- {nltk-3.2 → nltk-3.3}/nltk/stem/regexp.py +61 -61
- {nltk-3.2 → nltk-3.3}/nltk/stem/rslp.py +142 -142
- {nltk-3.2 → nltk-3.3}/nltk/stem/snowball.py +4236 -3712
- {nltk-3.2 → nltk-3.3}/nltk/stem/util.py +22 -12
- {nltk-3.2 → nltk-3.3}/nltk/stem/wordnet.py +51 -51
- {nltk-3.2 → nltk-3.3}/nltk/tag/__init__.py +152 -127
- {nltk-3.2 → nltk-3.3}/nltk/tag/api.py +86 -81
- {nltk-3.2 → nltk-3.3}/nltk/tag/brill.py +424 -426
- {nltk-3.2 → nltk-3.3}/nltk/tag/brill_trainer.py +608 -608
- {nltk-3.2 → nltk-3.3}/nltk/tag/crf.py +204 -200
- {nltk-3.2 → nltk-3.3}/nltk/tag/hmm.py +1277 -1277
- {nltk-3.2 → nltk-3.3}/nltk/tag/hunpos.py +132 -132
- {nltk-3.2 → nltk-3.3}/nltk/tag/mapping.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/tag/perceptron.py +329 -314
- {nltk-3.2 → nltk-3.3}/nltk/tag/senna.py +147 -145
- {nltk-3.2 → nltk-3.3}/nltk/tag/sequential.py +740 -736
- {nltk-3.2 → nltk-3.3}/nltk/tag/stanford.py +219 -196
- {nltk-3.2 → nltk-3.3}/nltk/tag/tnt.py +595 -604
- {nltk-3.2 → nltk-3.3}/nltk/tag/util.py +72 -72
- {nltk-3.2 → nltk-3.3}/nltk/tbl/__init__.py +28 -28
- {nltk-3.2 → nltk-3.3}/nltk/tbl/api.py +1 -1
- {nltk-3.2 → nltk-3.3}/nltk/tbl/demo.py +366 -366
- {nltk-3.2 → nltk-3.3}/nltk/tbl/erroranalysis.py +39 -39
- {nltk-3.2 → nltk-3.3}/nltk/tbl/feature.py +259 -261
- {nltk-3.2 → nltk-3.3}/nltk/tbl/rule.py +321 -321
- {nltk-3.2 → nltk-3.3}/nltk/tbl/template.py +303 -308
- {nltk-3.2 → nltk-3.3}/nltk/test/__init__.py +18 -18
- {nltk-3.2 → nltk-3.3}/nltk/test/all.py +24 -23
- {nltk-3.2 → nltk-3.3}/nltk/test/bleu.doctest +14 -14
- {nltk-3.2 → nltk-3.3}/nltk/test/bnc.doctest +60 -60
- {nltk-3.2 → nltk-3.3}/nltk/test/ccg.doctest +376 -395
- nltk-3.3/nltk/test/ccg_semantics.doctest +553 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/chat80.doctest +234 -234
- {nltk-3.2 → nltk-3.3}/nltk/test/childes.doctest +184 -184
- {nltk-3.2 → nltk-3.3}/nltk/test/childes_fixt.py +14 -13
- {nltk-3.2 → nltk-3.3}/nltk/test/chunk.doctest +373 -373
- {nltk-3.2 → nltk-3.3}/nltk/test/classify.doctest +185 -185
- {nltk-3.2 → nltk-3.3}/nltk/test/classify_fixt.py +11 -10
- nltk-3.3/nltk/test/collections.doctest +20 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/collocations.doctest +276 -276
- {nltk-3.2 → nltk-3.3}/nltk/test/compat.doctest +134 -138
- {nltk-3.2 → nltk-3.3}/nltk/test/compat_fixt.py +9 -8
- nltk-3.3/nltk/test/concordance.doctest +55 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/corpus.doctest +2200 -2212
- {nltk-3.2 → nltk-3.3}/nltk/test/corpus_fixt.py +3 -3
- {nltk-3.2 → nltk-3.3}/nltk/test/crubadan.doctest +65 -65
- {nltk-3.2 → nltk-3.3}/nltk/test/data.doctest +379 -379
- {nltk-3.2 → nltk-3.3}/nltk/test/dependency.doctest +241 -241
- {nltk-3.2 → nltk-3.3}/nltk/test/discourse.doctest +546 -546
- {nltk-3.2 → nltk-3.3}/nltk/test/discourse_fixt.py +14 -13
- {nltk-3.2 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +159 -156
- {nltk-3.2 → nltk-3.3}/nltk/test/drt.doctest +517 -517
- {nltk-3.2 → nltk-3.3}/nltk/test/featgram.doctest +607 -607
- {nltk-3.2 → nltk-3.3}/nltk/test/featstruct.doctest +1229 -1230
- {nltk-3.2 → nltk-3.3}/nltk/test/framenet.doctest +288 -239
- {nltk-3.2 → nltk-3.3}/nltk/test/generate.doctest +67 -67
- {nltk-3.2 → nltk-3.3}/nltk/test/gensim.doctest +140 -141
- {nltk-3.2 → nltk-3.3}/nltk/test/gensim_fixt.py +10 -9
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics.doctest +384 -386
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/grammar.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/grammartestsuites.doctest +109 -109
- {nltk-3.2 → nltk-3.3}/nltk/test/index.doctest +100 -100
- {nltk-3.2 → nltk-3.3}/nltk/test/inference.doctest +534 -534
- {nltk-3.2 → nltk-3.3}/nltk/test/inference_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/internals.doctest +140 -140
- {nltk-3.2 → nltk-3.3}/nltk/test/japanese.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/logic.doctest +1098 -1098
- {nltk-3.2 → nltk-3.3}/nltk/test/metrics.doctest +270 -270
- {nltk-3.2 → nltk-3.3}/nltk/test/misc.doctest +118 -118
- {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic.doctest +286 -286
- {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/paice.doctest +35 -35
- {nltk-3.2 → nltk-3.3}/nltk/test/parse.doctest +884 -884
- {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en.doctest +565 -565
- {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +16 -16
- {nltk-3.2 → nltk-3.3}/nltk/test/probability.doctest +304 -304
- {nltk-3.2 → nltk-3.3}/nltk/test/probability_fixt.py +13 -12
- {nltk-3.2 → nltk-3.3}/nltk/test/propbank.doctest +176 -176
- {nltk-3.2 → nltk-3.3}/nltk/test/relextract.doctest +263 -263
- {nltk-3.2 → nltk-3.3}/nltk/test/resolution.doctest +221 -221
- {nltk-3.2 → nltk-3.3}/nltk/test/runtests.py +86 -64
- {nltk-3.2 → nltk-3.3}/nltk/test/segmentation_fixt.py +10 -10
- {nltk-3.2 → nltk-3.3}/nltk/test/semantics.doctest +665 -665
- {nltk-3.2 → nltk-3.3}/nltk/test/semantics_fixt.py +7 -7
- {nltk-3.2 → nltk-3.3}/nltk/test/sentiment.doctest +233 -233
- {nltk-3.2 → nltk-3.3}/nltk/test/sentiwordnet.doctest +41 -41
- {nltk-3.2 → nltk-3.3}/nltk/test/simple.doctest +85 -85
- {nltk-3.2 → nltk-3.3}/nltk/test/stem.doctest +78 -78
- {nltk-3.2 → nltk-3.3}/nltk/test/tag.doctest +33 -33
- {nltk-3.2 → nltk-3.3}/nltk/test/tokenize.doctest +273 -166
- {nltk-3.2 → nltk-3.3}/nltk/test/toolbox.doctest +307 -307
- {nltk-3.2 → nltk-3.3}/nltk/test/translate.doctest +242 -242
- {nltk-3.2 → nltk-3.3}/nltk/test/translate_fixt.py +3 -3
- {nltk-3.2 → nltk-3.3}/nltk/test/tree.doctest +1101 -1101
- {nltk-3.2 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +127 -127
- {nltk-3.2 → nltk-3.3}/nltk/test/treetransforms.doctest +156 -156
- nltk-3.3/nltk/test/unit/test_2x_compat.py +63 -0
- nltk-3.3/nltk/test/unit/test_aline.py +52 -0
- nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_classify.py +55 -53
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_collocations.py +88 -79
- nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
- nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpora.py +200 -183
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +45 -45
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_hmm.py +88 -88
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +188 -187
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +26 -26
- nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +124 -124
- nltk-3.3/nltk/test/unit/test_senna.py +74 -0
- nltk-3.3/nltk/test/unit/test_stem.py +121 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tag.py +20 -20
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tgrep.py +628 -626
- nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +185 -185
- nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
- nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
- nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +75 -75
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +87 -87
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +105 -105
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +126 -126
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +166 -166
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +270 -270
- nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +300 -300
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/utils.py +41 -41
- {nltk-3.2 → nltk-3.3}/nltk/test/util.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet.doctest +595 -581
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_fixt.py +7 -6
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_lch.doctest +53 -53
- {nltk-3.2 → nltk-3.3}/nltk/test/wsd.doctest +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/text.py +663 -610
- {nltk-3.2 → nltk-3.3}/nltk/tgrep.py +938 -937
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/__init__.py +130 -107
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/api.py +77 -78
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/casual.py +343 -342
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/mwe.py +120 -120
- nltk-3.3/nltk/tokenize/nist.py +173 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/punkt.py +1620 -1601
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/regexp.py +208 -202
- nltk-3.3/nltk/tokenize/repp.py +151 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/sexpr.py +140 -142
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/simple.py +138 -136
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/stanford.py +117 -113
- nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/texttiling.py +458 -460
- nltk-3.3/nltk/tokenize/toktok.py +155 -0
- nltk-3.3/nltk/tokenize/treebank.py +363 -0
- nltk-3.3/nltk/tokenize/util.py +261 -0
- {nltk-3.2 → nltk-3.3}/nltk/toolbox.py +499 -497
- {nltk-3.2 → nltk-3.3}/nltk/translate/__init__.py +24 -24
- {nltk-3.2 → nltk-3.3}/nltk/translate/api.py +331 -321
- {nltk-3.2 → nltk-3.3}/nltk/translate/bleu_score.py +615 -556
- nltk-3.3/nltk/translate/chrf_score.py +137 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/gale_church.py +248 -235
- {nltk-3.2 → nltk-3.3}/nltk/translate/gdfa.py +135 -131
- nltk-3.3/nltk/translate/gleu_score.py +193 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm1.py +250 -241
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm2.py +308 -308
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm3.py +337 -337
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm4.py +467 -467
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm5.py +639 -639
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm_model.py +536 -533
- {nltk-3.2 → nltk-3.3}/nltk/translate/metrics.py +40 -40
- nltk-3.3/nltk/translate/nist_score.py +178 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/phrase_based.py +175 -175
- {nltk-3.2 → nltk-3.3}/nltk/translate/ribes_score.py +325 -325
- {nltk-3.2 → nltk-3.3}/nltk/translate/stack_decoder.py +499 -495
- {nltk-3.2 → nltk-3.3}/nltk/tree.py +1605 -1603
- {nltk-3.2 → nltk-3.3}/nltk/treeprettyprinter.py +564 -564
- {nltk-3.2 → nltk-3.3}/nltk/treetransforms.py +309 -309
- {nltk-3.2 → nltk-3.3}/nltk/twitter/__init__.py +28 -28
- {nltk-3.2 → nltk-3.3}/nltk/twitter/api.py +141 -136
- {nltk-3.2 → nltk-3.3}/nltk/twitter/common.py +264 -258
- {nltk-3.2 → nltk-3.3}/nltk/twitter/twitter_demo.py +288 -288
- {nltk-3.2 → nltk-3.3}/nltk/twitter/twitterclient.py +530 -530
- {nltk-3.2 → nltk-3.3}/nltk/twitter/util.py +147 -146
- nltk-3.3/nltk/util.py +751 -0
- {nltk-3.2 → nltk-3.3}/nltk/wsd.py +53 -53
- {nltk-3.2 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/SOURCES.txt +26 -3
- nltk-3.3/nltk.egg-info/requires.txt +31 -0
- {nltk-3.2 → nltk-3.3}/setup.cfg +0 -1
- {nltk-3.2 → nltk-3.3}/setup.py +102 -75
- nltk-3.2/nltk/VERSION +0 -1
- nltk-3.2/nltk/compat.py +0 -680
- nltk-3.2/nltk/corpus/reader/pl196x.py +0 -278
- nltk-3.2/nltk/corpus/reader/verbnet.py +0 -408
- nltk-3.2/nltk/corpus/reader/wordlist.py +0 -37
- nltk-3.2/nltk/sentiment/vader_lexicon.txt +0 -7517
- nltk-3.2/nltk/six.py +0 -868
- nltk-3.2/nltk/stem/porter.py +0 -692
- nltk-3.2/nltk/test/unit/test_2x_compat.py +0 -26
- nltk-3.2/nltk/test/unit/test_stem.py +0 -36
- nltk-3.2/nltk/test/unit/test_tokenize.py +0 -23
- nltk-3.2/nltk/test/unit/translate/test_bleu.py +0 -84
- nltk-3.2/nltk/tokenize/treebank.py +0 -124
- nltk-3.2/nltk/tokenize/util.py +0 -90
- nltk-3.2/nltk/util.py +0 -1364
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
|
@@ -1,600 +1,600 @@
|
|
|
1
|
-
# Natural Language Toolkit: Chunk format conversions
|
|
2
|
-
#
|
|
3
|
-
# Copyright (C) 2001-
|
|
4
|
-
# Author: Edward Loper <edloper@gmail.com>
|
|
5
|
-
# Steven Bird <stevenbird1@gmail.com> (minor additions)
|
|
6
|
-
# URL: <http://nltk.org/>
|
|
7
|
-
# For license information, see LICENSE.TXT
|
|
8
|
-
from __future__ import print_function, unicode_literals, division
|
|
9
|
-
|
|
10
|
-
import re
|
|
11
|
-
|
|
12
|
-
from nltk.tree import Tree
|
|
13
|
-
from nltk.tag.mapping import map_tag
|
|
14
|
-
from nltk.tag.util import str2tuple
|
|
15
|
-
from nltk.compat import python_2_unicode_compatible
|
|
16
|
-
|
|
17
|
-
##//////////////////////////////////////////////////////
|
|
18
|
-
## EVALUATION
|
|
19
|
-
##//////////////////////////////////////////////////////
|
|
20
|
-
|
|
21
|
-
from nltk.metrics import accuracy as _accuracy
|
|
22
|
-
def accuracy(chunker, gold):
|
|
23
|
-
"""
|
|
24
|
-
Score the accuracy of the chunker against the gold standard.
|
|
25
|
-
Strip the chunk information from the gold standard and rechunk it using
|
|
26
|
-
the chunker, then compute the accuracy score.
|
|
27
|
-
|
|
28
|
-
:type chunker: ChunkParserI
|
|
29
|
-
:param chunker: The chunker being evaluated.
|
|
30
|
-
:type gold: tree
|
|
31
|
-
:param gold: The chunk structures to score the chunker on.
|
|
32
|
-
:rtype: float
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
gold_tags = []
|
|
36
|
-
test_tags = []
|
|
37
|
-
for gold_tree in gold:
|
|
38
|
-
test_tree = chunker.parse(gold_tree.flatten())
|
|
39
|
-
gold_tags += tree2conlltags(gold_tree)
|
|
40
|
-
test_tags += tree2conlltags(test_tree)
|
|
41
|
-
|
|
42
|
-
# print 'GOLD:', gold_tags[:50]
|
|
43
|
-
# print 'TEST:', test_tags[:50]
|
|
44
|
-
return _accuracy(gold_tags, test_tags)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# Patched for increased performance by Yoav Goldberg <yoavg@cs.bgu.ac.il>, 2006-01-13
|
|
48
|
-
# -- statistics are evaluated only on demand, instead of at every sentence evaluation
|
|
49
|
-
#
|
|
50
|
-
# SB: use nltk.metrics for precision/recall scoring?
|
|
51
|
-
#
|
|
52
|
-
class ChunkScore(object):
|
|
53
|
-
"""
|
|
54
|
-
A utility class for scoring chunk parsers. ``ChunkScore`` can
|
|
55
|
-
evaluate a chunk parser's output, based on a number of statistics
|
|
56
|
-
(precision, recall, f-measure, misssed chunks, incorrect chunks).
|
|
57
|
-
It can also combine the scores from the parsing of multiple texts;
|
|
58
|
-
this makes it significantly easier to evaluate a chunk parser that
|
|
59
|
-
operates one sentence at a time.
|
|
60
|
-
|
|
61
|
-
Texts are evaluated with the ``score`` method. The results of
|
|
62
|
-
evaluation can be accessed via a number of accessor methods, such
|
|
63
|
-
as ``precision`` and ``f_measure``. A typical use of the
|
|
64
|
-
``ChunkScore`` class is::
|
|
65
|
-
|
|
66
|
-
>>> chunkscore = ChunkScore() # doctest: +SKIP
|
|
67
|
-
>>> for correct in correct_sentences: # doctest: +SKIP
|
|
68
|
-
... guess = chunkparser.parse(correct.leaves()) # doctest: +SKIP
|
|
69
|
-
... chunkscore.score(correct, guess) # doctest: +SKIP
|
|
70
|
-
>>> print('F Measure:', chunkscore.f_measure()) # doctest: +SKIP
|
|
71
|
-
F Measure: 0.823
|
|
72
|
-
|
|
73
|
-
:ivar kwargs: Keyword arguments:
|
|
74
|
-
|
|
75
|
-
- max_tp_examples: The maximum number actual examples of true
|
|
76
|
-
positives to record. This affects the ``correct`` member
|
|
77
|
-
function: ``correct`` will not return more than this number
|
|
78
|
-
of true positive examples. This does *not* affect any of
|
|
79
|
-
the numerical metrics (precision, recall, or f-measure)
|
|
80
|
-
|
|
81
|
-
- max_fp_examples: The maximum number actual examples of false
|
|
82
|
-
positives to record. This affects the ``incorrect`` member
|
|
83
|
-
function and the ``guessed`` member function: ``incorrect``
|
|
84
|
-
will not return more than this number of examples, and
|
|
85
|
-
``guessed`` will not return more than this number of true
|
|
86
|
-
positive examples. This does *not* affect any of the
|
|
87
|
-
numerical metrics (precision, recall, or f-measure)
|
|
88
|
-
|
|
89
|
-
- max_fn_examples: The maximum number actual examples of false
|
|
90
|
-
negatives to record. This affects the ``missed`` member
|
|
91
|
-
function and the ``correct`` member function: ``missed``
|
|
92
|
-
will not return more than this number of examples, and
|
|
93
|
-
``correct`` will not return more than this number of true
|
|
94
|
-
negative examples. This does *not* affect any of the
|
|
95
|
-
numerical metrics (precision, recall, or f-measure)
|
|
96
|
-
|
|
97
|
-
- chunk_label: A regular expression indicating which chunks
|
|
98
|
-
should be compared. Defaults to ``'.*'`` (i.e., all chunks).
|
|
99
|
-
|
|
100
|
-
:type _tp: list(Token)
|
|
101
|
-
:ivar _tp: List of true positives
|
|
102
|
-
:type _fp: list(Token)
|
|
103
|
-
:ivar _fp: List of false positives
|
|
104
|
-
:type _fn: list(Token)
|
|
105
|
-
:ivar _fn: List of false negatives
|
|
106
|
-
|
|
107
|
-
:type _tp_num: int
|
|
108
|
-
:ivar _tp_num: Number of true positives
|
|
109
|
-
:type _fp_num: int
|
|
110
|
-
:ivar _fp_num: Number of false positives
|
|
111
|
-
:type _fn_num: int
|
|
112
|
-
:ivar _fn_num: Number of false negatives.
|
|
113
|
-
"""
|
|
114
|
-
def __init__(self, **kwargs):
|
|
115
|
-
self._correct = set()
|
|
116
|
-
self._guessed = set()
|
|
117
|
-
self._tp = set()
|
|
118
|
-
self._fp = set()
|
|
119
|
-
self._fn = set()
|
|
120
|
-
self._max_tp = kwargs.get('max_tp_examples', 100)
|
|
121
|
-
self._max_fp = kwargs.get('max_fp_examples', 100)
|
|
122
|
-
self._max_fn = kwargs.get('max_fn_examples', 100)
|
|
123
|
-
self._chunk_label = kwargs.get('chunk_label', '.*')
|
|
124
|
-
self._tp_num = 0
|
|
125
|
-
self._fp_num = 0
|
|
126
|
-
self._fn_num = 0
|
|
127
|
-
self._count = 0
|
|
128
|
-
self._tags_correct = 0.0
|
|
129
|
-
self._tags_total = 0.0
|
|
130
|
-
|
|
131
|
-
self._measuresNeedUpdate = False
|
|
132
|
-
|
|
133
|
-
def _updateMeasures(self):
|
|
134
|
-
if (self._measuresNeedUpdate):
|
|
135
|
-
self._tp = self._guessed & self._correct
|
|
136
|
-
self._fn = self._correct - self._guessed
|
|
137
|
-
self._fp = self._guessed - self._correct
|
|
138
|
-
self._tp_num = len(self._tp)
|
|
139
|
-
self._fp_num = len(self._fp)
|
|
140
|
-
self._fn_num = len(self._fn)
|
|
141
|
-
self._measuresNeedUpdate = False
|
|
142
|
-
|
|
143
|
-
def score(self, correct, guessed):
|
|
144
|
-
"""
|
|
145
|
-
Given a correctly chunked sentence, score another chunked
|
|
146
|
-
version of the same sentence.
|
|
147
|
-
|
|
148
|
-
:type correct: chunk structure
|
|
149
|
-
:param correct: The known-correct ("gold standard") chunked
|
|
150
|
-
sentence.
|
|
151
|
-
:type guessed: chunk structure
|
|
152
|
-
:param guessed: The chunked sentence to be scored.
|
|
153
|
-
"""
|
|
154
|
-
self._correct |= _chunksets(correct, self._count, self._chunk_label)
|
|
155
|
-
self._guessed |= _chunksets(guessed, self._count, self._chunk_label)
|
|
156
|
-
self._count += 1
|
|
157
|
-
self._measuresNeedUpdate = True
|
|
158
|
-
# Keep track of per-tag accuracy (if possible)
|
|
159
|
-
try:
|
|
160
|
-
correct_tags = tree2conlltags(correct)
|
|
161
|
-
guessed_tags = tree2conlltags(guessed)
|
|
162
|
-
except ValueError:
|
|
163
|
-
# This exception case is for nested chunk structures,
|
|
164
|
-
# where tree2conlltags will fail with a ValueError: "Tree
|
|
165
|
-
# is too deeply nested to be printed in CoNLL format."
|
|
166
|
-
correct_tags = guessed_tags = ()
|
|
167
|
-
self._tags_total += len(correct_tags)
|
|
168
|
-
self._tags_correct += sum(1 for (t,g) in zip(guessed_tags,
|
|
169
|
-
correct_tags)
|
|
170
|
-
if t==g)
|
|
171
|
-
|
|
172
|
-
def accuracy(self):
|
|
173
|
-
"""
|
|
174
|
-
Return the overall tag-based accuracy for all text that have
|
|
175
|
-
been scored by this ``ChunkScore``, using the IOB (conll2000)
|
|
176
|
-
tag encoding.
|
|
177
|
-
|
|
178
|
-
:rtype: float
|
|
179
|
-
"""
|
|
180
|
-
if self._tags_total == 0: return 1
|
|
181
|
-
return self._tags_correct/self._tags_total
|
|
182
|
-
|
|
183
|
-
def precision(self):
|
|
184
|
-
"""
|
|
185
|
-
Return the overall precision for all texts that have been
|
|
186
|
-
scored by this ``ChunkScore``.
|
|
187
|
-
|
|
188
|
-
:rtype: float
|
|
189
|
-
"""
|
|
190
|
-
self._updateMeasures()
|
|
191
|
-
div = self._tp_num + self._fp_num
|
|
192
|
-
if div == 0: return 0
|
|
193
|
-
else: return self._tp_num / div
|
|
194
|
-
|
|
195
|
-
def recall(self):
|
|
196
|
-
"""
|
|
197
|
-
Return the overall recall for all texts that have been
|
|
198
|
-
scored by this ``ChunkScore``.
|
|
199
|
-
|
|
200
|
-
:rtype: float
|
|
201
|
-
"""
|
|
202
|
-
self._updateMeasures()
|
|
203
|
-
div = self._tp_num + self._fn_num
|
|
204
|
-
if div == 0: return 0
|
|
205
|
-
else: return self._tp_num / div
|
|
206
|
-
|
|
207
|
-
def f_measure(self, alpha=0.5):
|
|
208
|
-
"""
|
|
209
|
-
Return the overall F measure for all texts that have been
|
|
210
|
-
scored by this ``ChunkScore``.
|
|
211
|
-
|
|
212
|
-
:param alpha: the relative weighting of precision and recall.
|
|
213
|
-
Larger alpha biases the score towards the precision value,
|
|
214
|
-
while smaller alpha biases the score towards the recall
|
|
215
|
-
value. ``alpha`` should have a value in the range [0,1].
|
|
216
|
-
:type alpha: float
|
|
217
|
-
:rtype: float
|
|
218
|
-
"""
|
|
219
|
-
self._updateMeasures()
|
|
220
|
-
p = self.precision()
|
|
221
|
-
r = self.recall()
|
|
222
|
-
if p == 0 or r == 0: # what if alpha is 0 or 1?
|
|
223
|
-
return 0
|
|
224
|
-
return 1/(alpha/p + (1-alpha)/r)
|
|
225
|
-
|
|
226
|
-
def missed(self):
|
|
227
|
-
"""
|
|
228
|
-
Return the chunks which were included in the
|
|
229
|
-
correct chunk structures, but not in the guessed chunk
|
|
230
|
-
structures, listed in input order.
|
|
231
|
-
|
|
232
|
-
:rtype: list of chunks
|
|
233
|
-
"""
|
|
234
|
-
self._updateMeasures()
|
|
235
|
-
chunks = list(self._fn)
|
|
236
|
-
return [c[1] for c in chunks] # discard position information
|
|
237
|
-
|
|
238
|
-
def incorrect(self):
|
|
239
|
-
"""
|
|
240
|
-
Return the chunks which were included in the guessed chunk structures,
|
|
241
|
-
but not in the correct chunk structures, listed in input order.
|
|
242
|
-
|
|
243
|
-
:rtype: list of chunks
|
|
244
|
-
"""
|
|
245
|
-
self._updateMeasures()
|
|
246
|
-
chunks = list(self._fp)
|
|
247
|
-
return [c[1] for c in chunks] # discard position information
|
|
248
|
-
|
|
249
|
-
def correct(self):
|
|
250
|
-
"""
|
|
251
|
-
Return the chunks which were included in the correct
|
|
252
|
-
chunk structures, listed in input order.
|
|
253
|
-
|
|
254
|
-
:rtype: list of chunks
|
|
255
|
-
"""
|
|
256
|
-
chunks = list(self._correct)
|
|
257
|
-
return [c[1] for c in chunks] # discard position information
|
|
258
|
-
|
|
259
|
-
def guessed(self):
|
|
260
|
-
"""
|
|
261
|
-
Return the chunks which were included in the guessed
|
|
262
|
-
chunk structures, listed in input order.
|
|
263
|
-
|
|
264
|
-
:rtype: list of chunks
|
|
265
|
-
"""
|
|
266
|
-
chunks = list(self._guessed)
|
|
267
|
-
return [c[1] for c in chunks] # discard position information
|
|
268
|
-
|
|
269
|
-
def __len__(self):
|
|
270
|
-
self._updateMeasures()
|
|
271
|
-
return self._tp_num + self._fn_num
|
|
272
|
-
|
|
273
|
-
def __repr__(self):
|
|
274
|
-
"""
|
|
275
|
-
Return a concise representation of this ``ChunkScoring``.
|
|
276
|
-
|
|
277
|
-
:rtype: str
|
|
278
|
-
"""
|
|
279
|
-
return '<ChunkScoring of '+repr(len(self))+' chunks>'
|
|
280
|
-
|
|
281
|
-
def __str__(self):
|
|
282
|
-
"""
|
|
283
|
-
Return a verbose representation of this ``ChunkScoring``.
|
|
284
|
-
This representation includes the precision, recall, and
|
|
285
|
-
f-measure scores. For other information about the score,
|
|
286
|
-
use the accessor methods (e.g., ``missed()`` and ``incorrect()``).
|
|
287
|
-
|
|
288
|
-
:rtype: str
|
|
289
|
-
"""
|
|
290
|
-
return ("ChunkParse score:\n" +
|
|
291
|
-
(" IOB Accuracy:
|
|
292
|
-
(" Precision:
|
|
293
|
-
(" Recall:
|
|
294
|
-
(" F-Measure:
|
|
295
|
-
|
|
296
|
-
# extract chunks, and assign unique id, the absolute position of
|
|
297
|
-
# the first word of the chunk
|
|
298
|
-
def _chunksets(t, count, chunk_label):
|
|
299
|
-
pos = 0
|
|
300
|
-
chunks = []
|
|
301
|
-
for child in t:
|
|
302
|
-
if isinstance(child, Tree):
|
|
303
|
-
if re.match(chunk_label, child.label()):
|
|
304
|
-
chunks.append(((count, pos), child.freeze()))
|
|
305
|
-
pos += len(child.leaves())
|
|
306
|
-
else:
|
|
307
|
-
pos += 1
|
|
308
|
-
return set(chunks)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
def tagstr2tree(s, chunk_label="NP", root_label="S", sep='/',
|
|
312
|
-
source_tagset=None, target_tagset=None):
|
|
313
|
-
"""
|
|
314
|
-
Divide a string of bracketted tagged text into
|
|
315
|
-
chunks and unchunked tokens, and produce a Tree.
|
|
316
|
-
Chunks are marked by square brackets (``[...]``). Words are
|
|
317
|
-
delimited by whitespace, and each word should have the form
|
|
318
|
-
``text/tag``. Words that do not contain a slash are
|
|
319
|
-
assigned a ``tag`` of None.
|
|
320
|
-
|
|
321
|
-
:param s: The string to be converted
|
|
322
|
-
:type s: str
|
|
323
|
-
:param chunk_label: The label to use for chunk nodes
|
|
324
|
-
:type chunk_label: str
|
|
325
|
-
:param root_label: The label to use for the root of the tree
|
|
326
|
-
:type root_label: str
|
|
327
|
-
:rtype: Tree
|
|
328
|
-
"""
|
|
329
|
-
|
|
330
|
-
WORD_OR_BRACKET = re.compile(r'\[|\]|[^\[\]\s]+')
|
|
331
|
-
|
|
332
|
-
stack = [Tree(root_label, [])]
|
|
333
|
-
for match in WORD_OR_BRACKET.finditer(s):
|
|
334
|
-
text = match.group()
|
|
335
|
-
if text[0] == '[':
|
|
336
|
-
if len(stack) != 1:
|
|
337
|
-
raise ValueError('Unexpected [ at char
|
|
338
|
-
chunk = Tree(chunk_label, [])
|
|
339
|
-
stack[-1].append(chunk)
|
|
340
|
-
stack.append(chunk)
|
|
341
|
-
elif text[0] == ']':
|
|
342
|
-
if len(stack) != 2:
|
|
343
|
-
raise ValueError('Unexpected ] at char
|
|
344
|
-
stack.pop()
|
|
345
|
-
else:
|
|
346
|
-
if sep is None:
|
|
347
|
-
stack[-1].append(text)
|
|
348
|
-
else:
|
|
349
|
-
word, tag = str2tuple(text, sep)
|
|
350
|
-
if source_tagset and target_tagset:
|
|
351
|
-
tag = map_tag(source_tagset, target_tagset, tag)
|
|
352
|
-
stack[-1].append((word, tag))
|
|
353
|
-
|
|
354
|
-
if len(stack) != 1:
|
|
355
|
-
raise ValueError('Expected ] at char
|
|
356
|
-
return stack[0]
|
|
357
|
-
|
|
358
|
-
### CONLL
|
|
359
|
-
|
|
360
|
-
_LINE_RE = re.compile('(\S+)\s+(\S+)\s+([IOB])-?(\S+)?')
|
|
361
|
-
def conllstr2tree(s, chunk_types=('NP', 'PP', 'VP'), root_label="S"):
|
|
362
|
-
"""
|
|
363
|
-
Return a chunk structure for a single sentence
|
|
364
|
-
encoded in the given CONLL 2000 style string.
|
|
365
|
-
This function converts a CoNLL IOB string into a tree.
|
|
366
|
-
It uses the specified chunk types
|
|
367
|
-
(defaults to NP, PP and VP), and creates a tree rooted at a node
|
|
368
|
-
labeled S (by default).
|
|
369
|
-
|
|
370
|
-
:param s: The CoNLL string to be converted.
|
|
371
|
-
:type s: str
|
|
372
|
-
:param chunk_types: The chunk types to be converted.
|
|
373
|
-
:type chunk_types: tuple
|
|
374
|
-
:param root_label: The node label to use for the root.
|
|
375
|
-
:type root_label: str
|
|
376
|
-
:rtype: Tree
|
|
377
|
-
"""
|
|
378
|
-
|
|
379
|
-
stack = [Tree(root_label, [])]
|
|
380
|
-
|
|
381
|
-
for lineno, line in enumerate(s.split('\n')):
|
|
382
|
-
if not line.strip(): continue
|
|
383
|
-
|
|
384
|
-
# Decode the line.
|
|
385
|
-
match = _LINE_RE.match(line)
|
|
386
|
-
if match is None:
|
|
387
|
-
raise ValueError('Error on line
|
|
388
|
-
(word, tag, state, chunk_type) = match.groups()
|
|
389
|
-
|
|
390
|
-
# If it's a chunk type we don't care about, treat it as O.
|
|
391
|
-
if (chunk_types is not None and
|
|
392
|
-
chunk_type not in chunk_types):
|
|
393
|
-
state = 'O'
|
|
394
|
-
|
|
395
|
-
# For "Begin"/"Outside", finish any completed chunks -
|
|
396
|
-
# also do so for "Inside" which don't match the previous token.
|
|
397
|
-
mismatch_I = state == 'I' and chunk_type != stack[-1].label()
|
|
398
|
-
if state in 'BO' or mismatch_I:
|
|
399
|
-
if len(stack) == 2: stack.pop()
|
|
400
|
-
|
|
401
|
-
# For "Begin", start a new chunk.
|
|
402
|
-
if state == 'B' or mismatch_I:
|
|
403
|
-
chunk = Tree(chunk_type, [])
|
|
404
|
-
stack[-1].append(chunk)
|
|
405
|
-
stack.append(chunk)
|
|
406
|
-
|
|
407
|
-
# Add the new word token.
|
|
408
|
-
stack[-1].append((word, tag))
|
|
409
|
-
|
|
410
|
-
return stack[0]
|
|
411
|
-
|
|
412
|
-
def tree2conlltags(t):
|
|
413
|
-
"""
|
|
414
|
-
Return a list of 3-tuples containing ``(word, tag, IOB-tag)``.
|
|
415
|
-
Convert a tree to the CoNLL IOB tag format.
|
|
416
|
-
|
|
417
|
-
:param t: The tree to be converted.
|
|
418
|
-
:type t: Tree
|
|
419
|
-
:rtype: list(tuple)
|
|
420
|
-
"""
|
|
421
|
-
|
|
422
|
-
tags = []
|
|
423
|
-
for child in t:
|
|
424
|
-
try:
|
|
425
|
-
category = child.label()
|
|
426
|
-
prefix = "B-"
|
|
427
|
-
for contents in child:
|
|
428
|
-
if isinstance(contents, Tree):
|
|
429
|
-
raise ValueError("Tree is too deeply nested to be printed in CoNLL format")
|
|
430
|
-
tags.append((contents[0], contents[1], prefix+category))
|
|
431
|
-
prefix = "I-"
|
|
432
|
-
except AttributeError:
|
|
433
|
-
tags.append((child[0], child[1], "O"))
|
|
434
|
-
return tags
|
|
435
|
-
|
|
436
|
-
def conlltags2tree(sentence, chunk_types=('NP','PP','VP'),
|
|
437
|
-
root_label='S', strict=False):
|
|
438
|
-
"""
|
|
439
|
-
Convert the CoNLL IOB format to a tree.
|
|
440
|
-
"""
|
|
441
|
-
tree = Tree(root_label, [])
|
|
442
|
-
for (word, postag, chunktag) in sentence:
|
|
443
|
-
if chunktag is None:
|
|
444
|
-
if strict:
|
|
445
|
-
raise ValueError("Bad conll tag sequence")
|
|
446
|
-
else:
|
|
447
|
-
# Treat as O
|
|
448
|
-
tree.append((word,postag))
|
|
449
|
-
elif chunktag.startswith('B-'):
|
|
450
|
-
tree.append(Tree(chunktag[2:], [(word,postag)]))
|
|
451
|
-
elif chunktag.startswith('I-'):
|
|
452
|
-
if (len(tree)==0 or not isinstance(tree[-1], Tree) or
|
|
453
|
-
tree[-1].label() != chunktag[2:]):
|
|
454
|
-
if strict:
|
|
455
|
-
raise ValueError("Bad conll tag sequence")
|
|
456
|
-
else:
|
|
457
|
-
# Treat as B-*
|
|
458
|
-
tree.append(Tree(chunktag[2:], [(word,postag)]))
|
|
459
|
-
else:
|
|
460
|
-
tree[-1].append((word,postag))
|
|
461
|
-
elif chunktag == 'O':
|
|
462
|
-
tree.append((word,postag))
|
|
463
|
-
else:
|
|
464
|
-
raise ValueError("Bad conll tag
|
|
465
|
-
return tree
|
|
466
|
-
|
|
467
|
-
def tree2conllstr(t):
|
|
468
|
-
"""
|
|
469
|
-
Return a multiline string where each line contains a word, tag and IOB tag.
|
|
470
|
-
Convert a tree to the CoNLL IOB string format
|
|
471
|
-
|
|
472
|
-
:param t: The tree to be converted.
|
|
473
|
-
:type t: Tree
|
|
474
|
-
:rtype: str
|
|
475
|
-
"""
|
|
476
|
-
lines = [" ".join(token) for token in tree2conlltags(t)]
|
|
477
|
-
return '\n'.join(lines)
|
|
478
|
-
|
|
479
|
-
### IEER
|
|
480
|
-
|
|
481
|
-
_IEER_DOC_RE = re.compile(r'<DOC>\s*'
|
|
482
|
-
r'(<DOCNO>\s*(?P<docno>.+?)\s*</DOCNO>\s*)?'
|
|
483
|
-
r'(<DOCTYPE>\s*(?P<doctype>.+?)\s*</DOCTYPE>\s*)?'
|
|
484
|
-
r'(<DATE_TIME>\s*(?P<date_time>.+?)\s*</DATE_TIME>\s*)?'
|
|
485
|
-
r'<BODY>\s*'
|
|
486
|
-
r'(<HEADLINE>\s*(?P<headline>.+?)\s*</HEADLINE>\s*)?'
|
|
487
|
-
r'<TEXT>(?P<text>.*?)</TEXT>\s*'
|
|
488
|
-
r'</BODY>\s*</DOC>\s*', re.DOTALL)
|
|
489
|
-
|
|
490
|
-
_IEER_TYPE_RE = re.compile('<b_\w+\s+[^>]*?type="(?P<type>\w+)"')
|
|
491
|
-
|
|
492
|
-
def _ieer_read_text(s, root_label):
|
|
493
|
-
stack = [Tree(root_label, [])]
|
|
494
|
-
# s will be None if there is no headline in the text
|
|
495
|
-
# return the empty list in place of a Tree
|
|
496
|
-
if s is None:
|
|
497
|
-
return []
|
|
498
|
-
for piece_m in re.finditer('<[^>]+>|[^\s<]+', s):
|
|
499
|
-
piece = piece_m.group()
|
|
500
|
-
try:
|
|
501
|
-
if piece.startswith('<b_'):
|
|
502
|
-
m = _IEER_TYPE_RE.match(piece)
|
|
503
|
-
if m is None: print('XXXX', piece)
|
|
504
|
-
chunk = Tree(m.group('type'), [])
|
|
505
|
-
stack[-1].append(chunk)
|
|
506
|
-
stack.append(chunk)
|
|
507
|
-
elif piece.startswith('<e_'):
|
|
508
|
-
stack.pop()
|
|
509
|
-
# elif piece.startswith('<'):
|
|
510
|
-
# print "ERROR:", piece
|
|
511
|
-
# raise ValueError # Unexpected HTML
|
|
512
|
-
else:
|
|
513
|
-
stack[-1].append(piece)
|
|
514
|
-
except (IndexError, ValueError):
|
|
515
|
-
raise ValueError('Bad IEER string (error at character
|
|
516
|
-
piece_m.start())
|
|
517
|
-
if len(stack) != 1:
|
|
518
|
-
raise ValueError('Bad IEER string')
|
|
519
|
-
return stack[0]
|
|
520
|
-
|
|
521
|
-
def ieerstr2tree(s, chunk_types = ['LOCATION', 'ORGANIZATION', 'PERSON', 'DURATION',
|
|
522
|
-
'DATE', 'CARDINAL', 'PERCENT', 'MONEY', 'MEASURE'], root_label="S"):
|
|
523
|
-
"""
|
|
524
|
-
Return a chunk structure containing the chunked tagged text that is
|
|
525
|
-
encoded in the given IEER style string.
|
|
526
|
-
Convert a string of chunked tagged text in the IEER named
|
|
527
|
-
entity format into a chunk structure. Chunks are of several
|
|
528
|
-
types, LOCATION, ORGANIZATION, PERSON, DURATION, DATE, CARDINAL,
|
|
529
|
-
PERCENT, MONEY, and MEASURE.
|
|
530
|
-
|
|
531
|
-
:rtype: Tree
|
|
532
|
-
"""
|
|
533
|
-
|
|
534
|
-
# Try looking for a single document. If that doesn't work, then just
|
|
535
|
-
# treat everything as if it was within the <TEXT>...</TEXT>.
|
|
536
|
-
m = _IEER_DOC_RE.match(s)
|
|
537
|
-
if m:
|
|
538
|
-
return {
|
|
539
|
-
'text': _ieer_read_text(m.group('text'), root_label),
|
|
540
|
-
'docno': m.group('docno'),
|
|
541
|
-
'doctype': m.group('doctype'),
|
|
542
|
-
'date_time': m.group('date_time'),
|
|
543
|
-
#'headline': m.group('headline')
|
|
544
|
-
# we want to capture NEs in the headline too!
|
|
545
|
-
'headline': _ieer_read_text(m.group('headline'), root_label),
|
|
546
|
-
}
|
|
547
|
-
else:
|
|
548
|
-
return _ieer_read_text(s, root_label)
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
def demo():
|
|
552
|
-
|
|
553
|
-
s = "[ Pierre/NNP Vinken/NNP ] ,/, [ 61/CD years/NNS ] old/JJ ,/, will/MD join/VB [ the/DT board/NN ] ./."
|
|
554
|
-
import nltk
|
|
555
|
-
t = nltk.chunk.tagstr2tree(s, chunk_label='NP')
|
|
556
|
-
t.pprint()
|
|
557
|
-
print()
|
|
558
|
-
|
|
559
|
-
s = """
|
|
560
|
-
These DT B-NP
|
|
561
|
-
research NN I-NP
|
|
562
|
-
protocols NNS I-NP
|
|
563
|
-
offer VBP B-VP
|
|
564
|
-
to TO B-PP
|
|
565
|
-
the DT B-NP
|
|
566
|
-
patient NN I-NP
|
|
567
|
-
not RB O
|
|
568
|
-
only RB O
|
|
569
|
-
the DT B-NP
|
|
570
|
-
very RB I-NP
|
|
571
|
-
best JJS I-NP
|
|
572
|
-
therapy NN I-NP
|
|
573
|
-
which WDT B-NP
|
|
574
|
-
we PRP B-NP
|
|
575
|
-
have VBP B-VP
|
|
576
|
-
established VBN I-VP
|
|
577
|
-
today NN B-NP
|
|
578
|
-
but CC B-NP
|
|
579
|
-
also RB I-NP
|
|
580
|
-
the DT B-NP
|
|
581
|
-
hope NN I-NP
|
|
582
|
-
of IN B-PP
|
|
583
|
-
something NN B-NP
|
|
584
|
-
still RB B-ADJP
|
|
585
|
-
better JJR I-ADJP
|
|
586
|
-
. . O
|
|
587
|
-
"""
|
|
588
|
-
|
|
589
|
-
conll_tree = conllstr2tree(s, chunk_types=('NP', 'PP'))
|
|
590
|
-
conll_tree.pprint()
|
|
591
|
-
|
|
592
|
-
# Demonstrate CoNLL output
|
|
593
|
-
print("CoNLL output:")
|
|
594
|
-
print(nltk.chunk.tree2conllstr(conll_tree))
|
|
595
|
-
print()
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
if __name__ == '__main__':
|
|
599
|
-
demo()
|
|
600
|
-
|
|
1
|
+
# Natural Language Toolkit: Chunk format conversions
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
4
|
+
# Author: Edward Loper <edloper@gmail.com>
|
|
5
|
+
# Steven Bird <stevenbird1@gmail.com> (minor additions)
|
|
6
|
+
# URL: <http://nltk.org/>
|
|
7
|
+
# For license information, see LICENSE.TXT
|
|
8
|
+
from __future__ import print_function, unicode_literals, division
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
from nltk.tree import Tree
|
|
13
|
+
from nltk.tag.mapping import map_tag
|
|
14
|
+
from nltk.tag.util import str2tuple
|
|
15
|
+
from nltk.compat import python_2_unicode_compatible
|
|
16
|
+
|
|
17
|
+
##//////////////////////////////////////////////////////
|
|
18
|
+
## EVALUATION
|
|
19
|
+
##//////////////////////////////////////////////////////
|
|
20
|
+
|
|
21
|
+
from nltk.metrics import accuracy as _accuracy
|
|
22
|
+
def accuracy(chunker, gold):
|
|
23
|
+
"""
|
|
24
|
+
Score the accuracy of the chunker against the gold standard.
|
|
25
|
+
Strip the chunk information from the gold standard and rechunk it using
|
|
26
|
+
the chunker, then compute the accuracy score.
|
|
27
|
+
|
|
28
|
+
:type chunker: ChunkParserI
|
|
29
|
+
:param chunker: The chunker being evaluated.
|
|
30
|
+
:type gold: tree
|
|
31
|
+
:param gold: The chunk structures to score the chunker on.
|
|
32
|
+
:rtype: float
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
gold_tags = []
|
|
36
|
+
test_tags = []
|
|
37
|
+
for gold_tree in gold:
|
|
38
|
+
test_tree = chunker.parse(gold_tree.flatten())
|
|
39
|
+
gold_tags += tree2conlltags(gold_tree)
|
|
40
|
+
test_tags += tree2conlltags(test_tree)
|
|
41
|
+
|
|
42
|
+
# print 'GOLD:', gold_tags[:50]
|
|
43
|
+
# print 'TEST:', test_tags[:50]
|
|
44
|
+
return _accuracy(gold_tags, test_tags)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Patched for increased performance by Yoav Goldberg <yoavg@cs.bgu.ac.il>, 2006-01-13
|
|
48
|
+
# -- statistics are evaluated only on demand, instead of at every sentence evaluation
|
|
49
|
+
#
|
|
50
|
+
# SB: use nltk.metrics for precision/recall scoring?
|
|
51
|
+
#
|
|
52
|
+
class ChunkScore(object):
|
|
53
|
+
"""
|
|
54
|
+
A utility class for scoring chunk parsers. ``ChunkScore`` can
|
|
55
|
+
evaluate a chunk parser's output, based on a number of statistics
|
|
56
|
+
(precision, recall, f-measure, misssed chunks, incorrect chunks).
|
|
57
|
+
It can also combine the scores from the parsing of multiple texts;
|
|
58
|
+
this makes it significantly easier to evaluate a chunk parser that
|
|
59
|
+
operates one sentence at a time.
|
|
60
|
+
|
|
61
|
+
Texts are evaluated with the ``score`` method. The results of
|
|
62
|
+
evaluation can be accessed via a number of accessor methods, such
|
|
63
|
+
as ``precision`` and ``f_measure``. A typical use of the
|
|
64
|
+
``ChunkScore`` class is::
|
|
65
|
+
|
|
66
|
+
>>> chunkscore = ChunkScore() # doctest: +SKIP
|
|
67
|
+
>>> for correct in correct_sentences: # doctest: +SKIP
|
|
68
|
+
... guess = chunkparser.parse(correct.leaves()) # doctest: +SKIP
|
|
69
|
+
... chunkscore.score(correct, guess) # doctest: +SKIP
|
|
70
|
+
>>> print('F Measure:', chunkscore.f_measure()) # doctest: +SKIP
|
|
71
|
+
F Measure: 0.823
|
|
72
|
+
|
|
73
|
+
:ivar kwargs: Keyword arguments:
|
|
74
|
+
|
|
75
|
+
- max_tp_examples: The maximum number actual examples of true
|
|
76
|
+
positives to record. This affects the ``correct`` member
|
|
77
|
+
function: ``correct`` will not return more than this number
|
|
78
|
+
of true positive examples. This does *not* affect any of
|
|
79
|
+
the numerical metrics (precision, recall, or f-measure)
|
|
80
|
+
|
|
81
|
+
- max_fp_examples: The maximum number actual examples of false
|
|
82
|
+
positives to record. This affects the ``incorrect`` member
|
|
83
|
+
function and the ``guessed`` member function: ``incorrect``
|
|
84
|
+
will not return more than this number of examples, and
|
|
85
|
+
``guessed`` will not return more than this number of true
|
|
86
|
+
positive examples. This does *not* affect any of the
|
|
87
|
+
numerical metrics (precision, recall, or f-measure)
|
|
88
|
+
|
|
89
|
+
- max_fn_examples: The maximum number actual examples of false
|
|
90
|
+
negatives to record. This affects the ``missed`` member
|
|
91
|
+
function and the ``correct`` member function: ``missed``
|
|
92
|
+
will not return more than this number of examples, and
|
|
93
|
+
``correct`` will not return more than this number of true
|
|
94
|
+
negative examples. This does *not* affect any of the
|
|
95
|
+
numerical metrics (precision, recall, or f-measure)
|
|
96
|
+
|
|
97
|
+
- chunk_label: A regular expression indicating which chunks
|
|
98
|
+
should be compared. Defaults to ``'.*'`` (i.e., all chunks).
|
|
99
|
+
|
|
100
|
+
:type _tp: list(Token)
|
|
101
|
+
:ivar _tp: List of true positives
|
|
102
|
+
:type _fp: list(Token)
|
|
103
|
+
:ivar _fp: List of false positives
|
|
104
|
+
:type _fn: list(Token)
|
|
105
|
+
:ivar _fn: List of false negatives
|
|
106
|
+
|
|
107
|
+
:type _tp_num: int
|
|
108
|
+
:ivar _tp_num: Number of true positives
|
|
109
|
+
:type _fp_num: int
|
|
110
|
+
:ivar _fp_num: Number of false positives
|
|
111
|
+
:type _fn_num: int
|
|
112
|
+
:ivar _fn_num: Number of false negatives.
|
|
113
|
+
"""
|
|
114
|
+
def __init__(self, **kwargs):
|
|
115
|
+
self._correct = set()
|
|
116
|
+
self._guessed = set()
|
|
117
|
+
self._tp = set()
|
|
118
|
+
self._fp = set()
|
|
119
|
+
self._fn = set()
|
|
120
|
+
self._max_tp = kwargs.get('max_tp_examples', 100)
|
|
121
|
+
self._max_fp = kwargs.get('max_fp_examples', 100)
|
|
122
|
+
self._max_fn = kwargs.get('max_fn_examples', 100)
|
|
123
|
+
self._chunk_label = kwargs.get('chunk_label', '.*')
|
|
124
|
+
self._tp_num = 0
|
|
125
|
+
self._fp_num = 0
|
|
126
|
+
self._fn_num = 0
|
|
127
|
+
self._count = 0
|
|
128
|
+
self._tags_correct = 0.0
|
|
129
|
+
self._tags_total = 0.0
|
|
130
|
+
|
|
131
|
+
self._measuresNeedUpdate = False
|
|
132
|
+
|
|
133
|
+
def _updateMeasures(self):
|
|
134
|
+
if (self._measuresNeedUpdate):
|
|
135
|
+
self._tp = self._guessed & self._correct
|
|
136
|
+
self._fn = self._correct - self._guessed
|
|
137
|
+
self._fp = self._guessed - self._correct
|
|
138
|
+
self._tp_num = len(self._tp)
|
|
139
|
+
self._fp_num = len(self._fp)
|
|
140
|
+
self._fn_num = len(self._fn)
|
|
141
|
+
self._measuresNeedUpdate = False
|
|
142
|
+
|
|
143
|
+
def score(self, correct, guessed):
|
|
144
|
+
"""
|
|
145
|
+
Given a correctly chunked sentence, score another chunked
|
|
146
|
+
version of the same sentence.
|
|
147
|
+
|
|
148
|
+
:type correct: chunk structure
|
|
149
|
+
:param correct: The known-correct ("gold standard") chunked
|
|
150
|
+
sentence.
|
|
151
|
+
:type guessed: chunk structure
|
|
152
|
+
:param guessed: The chunked sentence to be scored.
|
|
153
|
+
"""
|
|
154
|
+
self._correct |= _chunksets(correct, self._count, self._chunk_label)
|
|
155
|
+
self._guessed |= _chunksets(guessed, self._count, self._chunk_label)
|
|
156
|
+
self._count += 1
|
|
157
|
+
self._measuresNeedUpdate = True
|
|
158
|
+
# Keep track of per-tag accuracy (if possible)
|
|
159
|
+
try:
|
|
160
|
+
correct_tags = tree2conlltags(correct)
|
|
161
|
+
guessed_tags = tree2conlltags(guessed)
|
|
162
|
+
except ValueError:
|
|
163
|
+
# This exception case is for nested chunk structures,
|
|
164
|
+
# where tree2conlltags will fail with a ValueError: "Tree
|
|
165
|
+
# is too deeply nested to be printed in CoNLL format."
|
|
166
|
+
correct_tags = guessed_tags = ()
|
|
167
|
+
self._tags_total += len(correct_tags)
|
|
168
|
+
self._tags_correct += sum(1 for (t,g) in zip(guessed_tags,
|
|
169
|
+
correct_tags)
|
|
170
|
+
if t==g)
|
|
171
|
+
|
|
172
|
+
def accuracy(self):
|
|
173
|
+
"""
|
|
174
|
+
Return the overall tag-based accuracy for all text that have
|
|
175
|
+
been scored by this ``ChunkScore``, using the IOB (conll2000)
|
|
176
|
+
tag encoding.
|
|
177
|
+
|
|
178
|
+
:rtype: float
|
|
179
|
+
"""
|
|
180
|
+
if self._tags_total == 0: return 1
|
|
181
|
+
return self._tags_correct/self._tags_total
|
|
182
|
+
|
|
183
|
+
def precision(self):
|
|
184
|
+
"""
|
|
185
|
+
Return the overall precision for all texts that have been
|
|
186
|
+
scored by this ``ChunkScore``.
|
|
187
|
+
|
|
188
|
+
:rtype: float
|
|
189
|
+
"""
|
|
190
|
+
self._updateMeasures()
|
|
191
|
+
div = self._tp_num + self._fp_num
|
|
192
|
+
if div == 0: return 0
|
|
193
|
+
else: return self._tp_num / div
|
|
194
|
+
|
|
195
|
+
def recall(self):
|
|
196
|
+
"""
|
|
197
|
+
Return the overall recall for all texts that have been
|
|
198
|
+
scored by this ``ChunkScore``.
|
|
199
|
+
|
|
200
|
+
:rtype: float
|
|
201
|
+
"""
|
|
202
|
+
self._updateMeasures()
|
|
203
|
+
div = self._tp_num + self._fn_num
|
|
204
|
+
if div == 0: return 0
|
|
205
|
+
else: return self._tp_num / div
|
|
206
|
+
|
|
207
|
+
def f_measure(self, alpha=0.5):
|
|
208
|
+
"""
|
|
209
|
+
Return the overall F measure for all texts that have been
|
|
210
|
+
scored by this ``ChunkScore``.
|
|
211
|
+
|
|
212
|
+
:param alpha: the relative weighting of precision and recall.
|
|
213
|
+
Larger alpha biases the score towards the precision value,
|
|
214
|
+
while smaller alpha biases the score towards the recall
|
|
215
|
+
value. ``alpha`` should have a value in the range [0,1].
|
|
216
|
+
:type alpha: float
|
|
217
|
+
:rtype: float
|
|
218
|
+
"""
|
|
219
|
+
self._updateMeasures()
|
|
220
|
+
p = self.precision()
|
|
221
|
+
r = self.recall()
|
|
222
|
+
if p == 0 or r == 0: # what if alpha is 0 or 1?
|
|
223
|
+
return 0
|
|
224
|
+
return 1/(alpha/p + (1-alpha)/r)
|
|
225
|
+
|
|
226
|
+
def missed(self):
|
|
227
|
+
"""
|
|
228
|
+
Return the chunks which were included in the
|
|
229
|
+
correct chunk structures, but not in the guessed chunk
|
|
230
|
+
structures, listed in input order.
|
|
231
|
+
|
|
232
|
+
:rtype: list of chunks
|
|
233
|
+
"""
|
|
234
|
+
self._updateMeasures()
|
|
235
|
+
chunks = list(self._fn)
|
|
236
|
+
return [c[1] for c in chunks] # discard position information
|
|
237
|
+
|
|
238
|
+
def incorrect(self):
|
|
239
|
+
"""
|
|
240
|
+
Return the chunks which were included in the guessed chunk structures,
|
|
241
|
+
but not in the correct chunk structures, listed in input order.
|
|
242
|
+
|
|
243
|
+
:rtype: list of chunks
|
|
244
|
+
"""
|
|
245
|
+
self._updateMeasures()
|
|
246
|
+
chunks = list(self._fp)
|
|
247
|
+
return [c[1] for c in chunks] # discard position information
|
|
248
|
+
|
|
249
|
+
def correct(self):
|
|
250
|
+
"""
|
|
251
|
+
Return the chunks which were included in the correct
|
|
252
|
+
chunk structures, listed in input order.
|
|
253
|
+
|
|
254
|
+
:rtype: list of chunks
|
|
255
|
+
"""
|
|
256
|
+
chunks = list(self._correct)
|
|
257
|
+
return [c[1] for c in chunks] # discard position information
|
|
258
|
+
|
|
259
|
+
def guessed(self):
|
|
260
|
+
"""
|
|
261
|
+
Return the chunks which were included in the guessed
|
|
262
|
+
chunk structures, listed in input order.
|
|
263
|
+
|
|
264
|
+
:rtype: list of chunks
|
|
265
|
+
"""
|
|
266
|
+
chunks = list(self._guessed)
|
|
267
|
+
return [c[1] for c in chunks] # discard position information
|
|
268
|
+
|
|
269
|
+
def __len__(self):
|
|
270
|
+
self._updateMeasures()
|
|
271
|
+
return self._tp_num + self._fn_num
|
|
272
|
+
|
|
273
|
+
def __repr__(self):
|
|
274
|
+
"""
|
|
275
|
+
Return a concise representation of this ``ChunkScoring``.
|
|
276
|
+
|
|
277
|
+
:rtype: str
|
|
278
|
+
"""
|
|
279
|
+
return '<ChunkScoring of '+repr(len(self))+' chunks>'
|
|
280
|
+
|
|
281
|
+
def __str__(self):
|
|
282
|
+
"""
|
|
283
|
+
Return a verbose representation of this ``ChunkScoring``.
|
|
284
|
+
This representation includes the precision, recall, and
|
|
285
|
+
f-measure scores. For other information about the score,
|
|
286
|
+
use the accessor methods (e.g., ``missed()`` and ``incorrect()``).
|
|
287
|
+
|
|
288
|
+
:rtype: str
|
|
289
|
+
"""
|
|
290
|
+
return ("ChunkParse score:\n" +
|
|
291
|
+
(" IOB Accuracy: {:5.1f}%%\n".format(self.accuracy()*100)) +
|
|
292
|
+
(" Precision: {:5.1f}%%\n".format(self.precision()*100)) +
|
|
293
|
+
(" Recall: {:5.1f}%%\n".format(self.recall()*100))+
|
|
294
|
+
(" F-Measure: {:5.1f}%%".format(self.f_measure()*100)))
|
|
295
|
+
|
|
296
|
+
# extract chunks, and assign unique id, the absolute position of
|
|
297
|
+
# the first word of the chunk
|
|
298
|
+
def _chunksets(t, count, chunk_label):
|
|
299
|
+
pos = 0
|
|
300
|
+
chunks = []
|
|
301
|
+
for child in t:
|
|
302
|
+
if isinstance(child, Tree):
|
|
303
|
+
if re.match(chunk_label, child.label()):
|
|
304
|
+
chunks.append(((count, pos), child.freeze()))
|
|
305
|
+
pos += len(child.leaves())
|
|
306
|
+
else:
|
|
307
|
+
pos += 1
|
|
308
|
+
return set(chunks)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def tagstr2tree(s, chunk_label="NP", root_label="S", sep='/',
|
|
312
|
+
source_tagset=None, target_tagset=None):
|
|
313
|
+
"""
|
|
314
|
+
Divide a string of bracketted tagged text into
|
|
315
|
+
chunks and unchunked tokens, and produce a Tree.
|
|
316
|
+
Chunks are marked by square brackets (``[...]``). Words are
|
|
317
|
+
delimited by whitespace, and each word should have the form
|
|
318
|
+
``text/tag``. Words that do not contain a slash are
|
|
319
|
+
assigned a ``tag`` of None.
|
|
320
|
+
|
|
321
|
+
:param s: The string to be converted
|
|
322
|
+
:type s: str
|
|
323
|
+
:param chunk_label: The label to use for chunk nodes
|
|
324
|
+
:type chunk_label: str
|
|
325
|
+
:param root_label: The label to use for the root of the tree
|
|
326
|
+
:type root_label: str
|
|
327
|
+
:rtype: Tree
|
|
328
|
+
"""
|
|
329
|
+
|
|
330
|
+
WORD_OR_BRACKET = re.compile(r'\[|\]|[^\[\]\s]+')
|
|
331
|
+
|
|
332
|
+
stack = [Tree(root_label, [])]
|
|
333
|
+
for match in WORD_OR_BRACKET.finditer(s):
|
|
334
|
+
text = match.group()
|
|
335
|
+
if text[0] == '[':
|
|
336
|
+
if len(stack) != 1:
|
|
337
|
+
raise ValueError('Unexpected [ at char {:d}'.format(match.start()))
|
|
338
|
+
chunk = Tree(chunk_label, [])
|
|
339
|
+
stack[-1].append(chunk)
|
|
340
|
+
stack.append(chunk)
|
|
341
|
+
elif text[0] == ']':
|
|
342
|
+
if len(stack) != 2:
|
|
343
|
+
raise ValueError('Unexpected ] at char {:d}'.format(match.start()))
|
|
344
|
+
stack.pop()
|
|
345
|
+
else:
|
|
346
|
+
if sep is None:
|
|
347
|
+
stack[-1].append(text)
|
|
348
|
+
else:
|
|
349
|
+
word, tag = str2tuple(text, sep)
|
|
350
|
+
if source_tagset and target_tagset:
|
|
351
|
+
tag = map_tag(source_tagset, target_tagset, tag)
|
|
352
|
+
stack[-1].append((word, tag))
|
|
353
|
+
|
|
354
|
+
if len(stack) != 1:
|
|
355
|
+
raise ValueError('Expected ] at char {:d}'.format(len(s)))
|
|
356
|
+
return stack[0]
|
|
357
|
+
|
|
358
|
+
### CONLL
|
|
359
|
+
|
|
360
|
+
_LINE_RE = re.compile('(\S+)\s+(\S+)\s+([IOB])-?(\S+)?')
|
|
361
|
+
def conllstr2tree(s, chunk_types=('NP', 'PP', 'VP'), root_label="S"):
|
|
362
|
+
"""
|
|
363
|
+
Return a chunk structure for a single sentence
|
|
364
|
+
encoded in the given CONLL 2000 style string.
|
|
365
|
+
This function converts a CoNLL IOB string into a tree.
|
|
366
|
+
It uses the specified chunk types
|
|
367
|
+
(defaults to NP, PP and VP), and creates a tree rooted at a node
|
|
368
|
+
labeled S (by default).
|
|
369
|
+
|
|
370
|
+
:param s: The CoNLL string to be converted.
|
|
371
|
+
:type s: str
|
|
372
|
+
:param chunk_types: The chunk types to be converted.
|
|
373
|
+
:type chunk_types: tuple
|
|
374
|
+
:param root_label: The node label to use for the root.
|
|
375
|
+
:type root_label: str
|
|
376
|
+
:rtype: Tree
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
stack = [Tree(root_label, [])]
|
|
380
|
+
|
|
381
|
+
for lineno, line in enumerate(s.split('\n')):
|
|
382
|
+
if not line.strip(): continue
|
|
383
|
+
|
|
384
|
+
# Decode the line.
|
|
385
|
+
match = _LINE_RE.match(line)
|
|
386
|
+
if match is None:
|
|
387
|
+
raise ValueError('Error on line {:d}'.format(lineno))
|
|
388
|
+
(word, tag, state, chunk_type) = match.groups()
|
|
389
|
+
|
|
390
|
+
# If it's a chunk type we don't care about, treat it as O.
|
|
391
|
+
if (chunk_types is not None and
|
|
392
|
+
chunk_type not in chunk_types):
|
|
393
|
+
state = 'O'
|
|
394
|
+
|
|
395
|
+
# For "Begin"/"Outside", finish any completed chunks -
|
|
396
|
+
# also do so for "Inside" which don't match the previous token.
|
|
397
|
+
mismatch_I = state == 'I' and chunk_type != stack[-1].label()
|
|
398
|
+
if state in 'BO' or mismatch_I:
|
|
399
|
+
if len(stack) == 2: stack.pop()
|
|
400
|
+
|
|
401
|
+
# For "Begin", start a new chunk.
|
|
402
|
+
if state == 'B' or mismatch_I:
|
|
403
|
+
chunk = Tree(chunk_type, [])
|
|
404
|
+
stack[-1].append(chunk)
|
|
405
|
+
stack.append(chunk)
|
|
406
|
+
|
|
407
|
+
# Add the new word token.
|
|
408
|
+
stack[-1].append((word, tag))
|
|
409
|
+
|
|
410
|
+
return stack[0]
|
|
411
|
+
|
|
412
|
+
def tree2conlltags(t):
|
|
413
|
+
"""
|
|
414
|
+
Return a list of 3-tuples containing ``(word, tag, IOB-tag)``.
|
|
415
|
+
Convert a tree to the CoNLL IOB tag format.
|
|
416
|
+
|
|
417
|
+
:param t: The tree to be converted.
|
|
418
|
+
:type t: Tree
|
|
419
|
+
:rtype: list(tuple)
|
|
420
|
+
"""
|
|
421
|
+
|
|
422
|
+
tags = []
|
|
423
|
+
for child in t:
|
|
424
|
+
try:
|
|
425
|
+
category = child.label()
|
|
426
|
+
prefix = "B-"
|
|
427
|
+
for contents in child:
|
|
428
|
+
if isinstance(contents, Tree):
|
|
429
|
+
raise ValueError("Tree is too deeply nested to be printed in CoNLL format")
|
|
430
|
+
tags.append((contents[0], contents[1], prefix+category))
|
|
431
|
+
prefix = "I-"
|
|
432
|
+
except AttributeError:
|
|
433
|
+
tags.append((child[0], child[1], "O"))
|
|
434
|
+
return tags
|
|
435
|
+
|
|
436
|
+
def conlltags2tree(sentence, chunk_types=('NP','PP','VP'),
|
|
437
|
+
root_label='S', strict=False):
|
|
438
|
+
"""
|
|
439
|
+
Convert the CoNLL IOB format to a tree.
|
|
440
|
+
"""
|
|
441
|
+
tree = Tree(root_label, [])
|
|
442
|
+
for (word, postag, chunktag) in sentence:
|
|
443
|
+
if chunktag is None:
|
|
444
|
+
if strict:
|
|
445
|
+
raise ValueError("Bad conll tag sequence")
|
|
446
|
+
else:
|
|
447
|
+
# Treat as O
|
|
448
|
+
tree.append((word,postag))
|
|
449
|
+
elif chunktag.startswith('B-'):
|
|
450
|
+
tree.append(Tree(chunktag[2:], [(word,postag)]))
|
|
451
|
+
elif chunktag.startswith('I-'):
|
|
452
|
+
if (len(tree)==0 or not isinstance(tree[-1], Tree) or
|
|
453
|
+
tree[-1].label() != chunktag[2:]):
|
|
454
|
+
if strict:
|
|
455
|
+
raise ValueError("Bad conll tag sequence")
|
|
456
|
+
else:
|
|
457
|
+
# Treat as B-*
|
|
458
|
+
tree.append(Tree(chunktag[2:], [(word,postag)]))
|
|
459
|
+
else:
|
|
460
|
+
tree[-1].append((word,postag))
|
|
461
|
+
elif chunktag == 'O':
|
|
462
|
+
tree.append((word,postag))
|
|
463
|
+
else:
|
|
464
|
+
raise ValueError("Bad conll tag {0!r}".format(chunktag))
|
|
465
|
+
return tree
|
|
466
|
+
|
|
467
|
+
def tree2conllstr(t):
|
|
468
|
+
"""
|
|
469
|
+
Return a multiline string where each line contains a word, tag and IOB tag.
|
|
470
|
+
Convert a tree to the CoNLL IOB string format
|
|
471
|
+
|
|
472
|
+
:param t: The tree to be converted.
|
|
473
|
+
:type t: Tree
|
|
474
|
+
:rtype: str
|
|
475
|
+
"""
|
|
476
|
+
lines = [" ".join(token) for token in tree2conlltags(t)]
|
|
477
|
+
return '\n'.join(lines)
|
|
478
|
+
|
|
479
|
+
### IEER
|
|
480
|
+
|
|
481
|
+
_IEER_DOC_RE = re.compile(r'<DOC>\s*'
|
|
482
|
+
r'(<DOCNO>\s*(?P<docno>.+?)\s*</DOCNO>\s*)?'
|
|
483
|
+
r'(<DOCTYPE>\s*(?P<doctype>.+?)\s*</DOCTYPE>\s*)?'
|
|
484
|
+
r'(<DATE_TIME>\s*(?P<date_time>.+?)\s*</DATE_TIME>\s*)?'
|
|
485
|
+
r'<BODY>\s*'
|
|
486
|
+
r'(<HEADLINE>\s*(?P<headline>.+?)\s*</HEADLINE>\s*)?'
|
|
487
|
+
r'<TEXT>(?P<text>.*?)</TEXT>\s*'
|
|
488
|
+
r'</BODY>\s*</DOC>\s*', re.DOTALL)
|
|
489
|
+
|
|
490
|
+
_IEER_TYPE_RE = re.compile('<b_\w+\s+[^>]*?type="(?P<type>\w+)"')
|
|
491
|
+
|
|
492
|
+
def _ieer_read_text(s, root_label):
|
|
493
|
+
stack = [Tree(root_label, [])]
|
|
494
|
+
# s will be None if there is no headline in the text
|
|
495
|
+
# return the empty list in place of a Tree
|
|
496
|
+
if s is None:
|
|
497
|
+
return []
|
|
498
|
+
for piece_m in re.finditer('<[^>]+>|[^\s<]+', s):
|
|
499
|
+
piece = piece_m.group()
|
|
500
|
+
try:
|
|
501
|
+
if piece.startswith('<b_'):
|
|
502
|
+
m = _IEER_TYPE_RE.match(piece)
|
|
503
|
+
if m is None: print('XXXX', piece)
|
|
504
|
+
chunk = Tree(m.group('type'), [])
|
|
505
|
+
stack[-1].append(chunk)
|
|
506
|
+
stack.append(chunk)
|
|
507
|
+
elif piece.startswith('<e_'):
|
|
508
|
+
stack.pop()
|
|
509
|
+
# elif piece.startswith('<'):
|
|
510
|
+
# print "ERROR:", piece
|
|
511
|
+
# raise ValueError # Unexpected HTML
|
|
512
|
+
else:
|
|
513
|
+
stack[-1].append(piece)
|
|
514
|
+
except (IndexError, ValueError):
|
|
515
|
+
raise ValueError('Bad IEER string (error at character {:d})'.format \
|
|
516
|
+
(piece_m.start()))
|
|
517
|
+
if len(stack) != 1:
|
|
518
|
+
raise ValueError('Bad IEER string')
|
|
519
|
+
return stack[0]
|
|
520
|
+
|
|
521
|
+
def ieerstr2tree(s, chunk_types = ['LOCATION', 'ORGANIZATION', 'PERSON', 'DURATION',
|
|
522
|
+
'DATE', 'CARDINAL', 'PERCENT', 'MONEY', 'MEASURE'], root_label="S"):
|
|
523
|
+
"""
|
|
524
|
+
Return a chunk structure containing the chunked tagged text that is
|
|
525
|
+
encoded in the given IEER style string.
|
|
526
|
+
Convert a string of chunked tagged text in the IEER named
|
|
527
|
+
entity format into a chunk structure. Chunks are of several
|
|
528
|
+
types, LOCATION, ORGANIZATION, PERSON, DURATION, DATE, CARDINAL,
|
|
529
|
+
PERCENT, MONEY, and MEASURE.
|
|
530
|
+
|
|
531
|
+
:rtype: Tree
|
|
532
|
+
"""
|
|
533
|
+
|
|
534
|
+
# Try looking for a single document. If that doesn't work, then just
|
|
535
|
+
# treat everything as if it was within the <TEXT>...</TEXT>.
|
|
536
|
+
m = _IEER_DOC_RE.match(s)
|
|
537
|
+
if m:
|
|
538
|
+
return {
|
|
539
|
+
'text': _ieer_read_text(m.group('text'), root_label),
|
|
540
|
+
'docno': m.group('docno'),
|
|
541
|
+
'doctype': m.group('doctype'),
|
|
542
|
+
'date_time': m.group('date_time'),
|
|
543
|
+
#'headline': m.group('headline')
|
|
544
|
+
# we want to capture NEs in the headline too!
|
|
545
|
+
'headline': _ieer_read_text(m.group('headline'), root_label),
|
|
546
|
+
}
|
|
547
|
+
else:
|
|
548
|
+
return _ieer_read_text(s, root_label)
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
def demo():
|
|
552
|
+
|
|
553
|
+
s = "[ Pierre/NNP Vinken/NNP ] ,/, [ 61/CD years/NNS ] old/JJ ,/, will/MD join/VB [ the/DT board/NN ] ./."
|
|
554
|
+
import nltk
|
|
555
|
+
t = nltk.chunk.tagstr2tree(s, chunk_label='NP')
|
|
556
|
+
t.pprint()
|
|
557
|
+
print()
|
|
558
|
+
|
|
559
|
+
s = """
|
|
560
|
+
These DT B-NP
|
|
561
|
+
research NN I-NP
|
|
562
|
+
protocols NNS I-NP
|
|
563
|
+
offer VBP B-VP
|
|
564
|
+
to TO B-PP
|
|
565
|
+
the DT B-NP
|
|
566
|
+
patient NN I-NP
|
|
567
|
+
not RB O
|
|
568
|
+
only RB O
|
|
569
|
+
the DT B-NP
|
|
570
|
+
very RB I-NP
|
|
571
|
+
best JJS I-NP
|
|
572
|
+
therapy NN I-NP
|
|
573
|
+
which WDT B-NP
|
|
574
|
+
we PRP B-NP
|
|
575
|
+
have VBP B-VP
|
|
576
|
+
established VBN I-VP
|
|
577
|
+
today NN B-NP
|
|
578
|
+
but CC B-NP
|
|
579
|
+
also RB I-NP
|
|
580
|
+
the DT B-NP
|
|
581
|
+
hope NN I-NP
|
|
582
|
+
of IN B-PP
|
|
583
|
+
something NN B-NP
|
|
584
|
+
still RB B-ADJP
|
|
585
|
+
better JJR I-ADJP
|
|
586
|
+
. . O
|
|
587
|
+
"""
|
|
588
|
+
|
|
589
|
+
conll_tree = conllstr2tree(s, chunk_types=('NP', 'PP'))
|
|
590
|
+
conll_tree.pprint()
|
|
591
|
+
|
|
592
|
+
# Demonstrate CoNLL output
|
|
593
|
+
print("CoNLL output:")
|
|
594
|
+
print(nltk.chunk.tree2conllstr(conll_tree))
|
|
595
|
+
print()
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
if __name__ == '__main__':
|
|
599
|
+
demo()
|
|
600
|
+
|