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,295 +1,295 @@
|
|
|
1
|
-
# Natural Language Toolkit: Decision Tree Classifiers
|
|
2
|
-
#
|
|
3
|
-
# Copyright (C) 2001-
|
|
4
|
-
# Author: Edward Loper <edloper@gmail.com>
|
|
5
|
-
# URL: <http://nltk.org/>
|
|
6
|
-
# For license information, see LICENSE.TXT
|
|
7
|
-
|
|
8
|
-
"""
|
|
9
|
-
A classifier model that decides which label to assign to a token on
|
|
10
|
-
the basis of a tree structure, where branches correspond to conditions
|
|
11
|
-
on feature values, and leaves correspond to label assignments.
|
|
12
|
-
"""
|
|
13
|
-
from __future__ import print_function, unicode_literals, division
|
|
14
|
-
|
|
15
|
-
from collections import defaultdict
|
|
16
|
-
|
|
17
|
-
from nltk.probability import FreqDist, MLEProbDist, entropy
|
|
18
|
-
from nltk.classify.api import ClassifierI
|
|
19
|
-
from nltk.compat import python_2_unicode_compatible
|
|
20
|
-
|
|
21
|
-
@python_2_unicode_compatible
|
|
22
|
-
class DecisionTreeClassifier(ClassifierI):
|
|
23
|
-
def __init__(self, label, feature_name=None, decisions=None, default=None):
|
|
24
|
-
"""
|
|
25
|
-
:param label: The most likely label for tokens that reach
|
|
26
|
-
this node in the decision tree. If this decision tree
|
|
27
|
-
has no children, then this label will be assigned to
|
|
28
|
-
any token that reaches this decision tree.
|
|
29
|
-
:param feature_name: The name of the feature that this
|
|
30
|
-
decision tree selects for.
|
|
31
|
-
:param decisions: A dictionary mapping from feature values
|
|
32
|
-
for the feature identified by ``feature_name`` to
|
|
33
|
-
child decision trees.
|
|
34
|
-
:param default: The child that will be used if the value of
|
|
35
|
-
feature ``feature_name`` does not match any of the keys in
|
|
36
|
-
``decisions``. This is used when constructing binary
|
|
37
|
-
decision trees.
|
|
38
|
-
"""
|
|
39
|
-
self._label = label
|
|
40
|
-
self._fname = feature_name
|
|
41
|
-
self._decisions = decisions
|
|
42
|
-
self._default = default
|
|
43
|
-
|
|
44
|
-
def labels(self):
|
|
45
|
-
labels = [self._label]
|
|
46
|
-
if self._decisions is not None:
|
|
47
|
-
for dt in self._decisions.values():
|
|
48
|
-
labels.extend(dt.labels())
|
|
49
|
-
if self._default is not None:
|
|
50
|
-
labels.extend(self._default.labels())
|
|
51
|
-
return list(set(labels))
|
|
52
|
-
|
|
53
|
-
def classify(self, featureset):
|
|
54
|
-
# Decision leaf:
|
|
55
|
-
if self._fname is None:
|
|
56
|
-
return self._label
|
|
57
|
-
|
|
58
|
-
# Decision tree:
|
|
59
|
-
fval = featureset.get(self._fname)
|
|
60
|
-
if fval in self._decisions:
|
|
61
|
-
return self._decisions[fval].classify(featureset)
|
|
62
|
-
elif self._default is not None:
|
|
63
|
-
return self._default.classify(featureset)
|
|
64
|
-
else:
|
|
65
|
-
return self._label
|
|
66
|
-
|
|
67
|
-
def error(self, labeled_featuresets):
|
|
68
|
-
errors = 0
|
|
69
|
-
for featureset, label in labeled_featuresets:
|
|
70
|
-
if self.classify(featureset) != label:
|
|
71
|
-
errors += 1
|
|
72
|
-
return errors/len(labeled_featuresets)
|
|
73
|
-
|
|
74
|
-
def pretty_format(self, width=70, prefix='', depth=4):
|
|
75
|
-
"""
|
|
76
|
-
Return a string containing a pretty-printed version of this
|
|
77
|
-
decision tree. Each line in this string corresponds to a
|
|
78
|
-
single decision tree node or leaf, and indentation is used to
|
|
79
|
-
display the structure of the decision tree.
|
|
80
|
-
"""
|
|
81
|
-
# [xx] display default!!
|
|
82
|
-
if self._fname is None:
|
|
83
|
-
n = width-len(prefix)-15
|
|
84
|
-
return '
|
|
85
|
-
s = ''
|
|
86
|
-
for i, (fval, result) in enumerate(sorted(self._decisions.items())):
|
|
87
|
-
hdr = '
|
|
88
|
-
n = width-15-len(hdr)
|
|
89
|
-
s += '
|
|
90
|
-
if result._fname is not None and depth>1:
|
|
91
|
-
s += result.pretty_format(width, prefix+' ', depth-1)
|
|
92
|
-
if self._default is not None:
|
|
93
|
-
n = width-len(prefix)-21
|
|
94
|
-
s += '
|
|
95
|
-
if self._default._fname is not None and depth>1:
|
|
96
|
-
s += self._default.pretty_format(width, prefix+' ', depth-1)
|
|
97
|
-
return s
|
|
98
|
-
|
|
99
|
-
def pseudocode(self, prefix='', depth=4):
|
|
100
|
-
"""
|
|
101
|
-
Return a string representation of this decision tree that
|
|
102
|
-
expresses the decisions it makes as a nested set of pseudocode
|
|
103
|
-
if statements.
|
|
104
|
-
"""
|
|
105
|
-
if self._fname is None:
|
|
106
|
-
return "
|
|
107
|
-
s = ''
|
|
108
|
-
for (fval, result) in sorted(self._decisions.items()):
|
|
109
|
-
s += '
|
|
110
|
-
if result._fname is not None and depth>1:
|
|
111
|
-
s += '\n'+result.pseudocode(prefix+' ', depth-1)
|
|
112
|
-
else:
|
|
113
|
-
s += 'return
|
|
114
|
-
if self._default is not None:
|
|
115
|
-
if len(self._decisions) == 1:
|
|
116
|
-
s += '
|
|
117
|
-
list(self._decisions.keys())[0])
|
|
118
|
-
else:
|
|
119
|
-
s += '
|
|
120
|
-
if self._default._fname is not None and depth>1:
|
|
121
|
-
s += '\n'+self._default.pseudocode(prefix+' ', depth-1)
|
|
122
|
-
else:
|
|
123
|
-
s += 'return
|
|
124
|
-
return s
|
|
125
|
-
|
|
126
|
-
def __str__(self):
|
|
127
|
-
return self.pretty_format()
|
|
128
|
-
|
|
129
|
-
@staticmethod
|
|
130
|
-
def train(labeled_featuresets, entropy_cutoff=0.05, depth_cutoff=100,
|
|
131
|
-
support_cutoff=10, binary=False, feature_values=None,
|
|
132
|
-
verbose=False):
|
|
133
|
-
"""
|
|
134
|
-
:param binary: If true, then treat all feature/value pairs as
|
|
135
|
-
individual binary features, rather than using a single n-way
|
|
136
|
-
branch for each feature.
|
|
137
|
-
"""
|
|
138
|
-
# Collect a list of all feature names.
|
|
139
|
-
feature_names = set()
|
|
140
|
-
for featureset, label in labeled_featuresets:
|
|
141
|
-
for fname in featureset:
|
|
142
|
-
feature_names.add(fname)
|
|
143
|
-
|
|
144
|
-
# Collect a list of the values each feature can take.
|
|
145
|
-
if feature_values is None and binary:
|
|
146
|
-
feature_values = defaultdict(set)
|
|
147
|
-
for featureset, label in labeled_featuresets:
|
|
148
|
-
for fname, fval in featureset.items():
|
|
149
|
-
feature_values[fname].add(fval)
|
|
150
|
-
|
|
151
|
-
# Start with a stump.
|
|
152
|
-
if not binary:
|
|
153
|
-
tree = DecisionTreeClassifier.best_stump(
|
|
154
|
-
feature_names, labeled_featuresets, verbose)
|
|
155
|
-
else:
|
|
156
|
-
tree = DecisionTreeClassifier.best_binary_stump(
|
|
157
|
-
feature_names, labeled_featuresets, feature_values, verbose)
|
|
158
|
-
|
|
159
|
-
# Refine the stump.
|
|
160
|
-
tree.refine(labeled_featuresets, entropy_cutoff, depth_cutoff-1,
|
|
161
|
-
support_cutoff, binary, feature_values, verbose)
|
|
162
|
-
|
|
163
|
-
# Return it
|
|
164
|
-
return tree
|
|
165
|
-
|
|
166
|
-
@staticmethod
|
|
167
|
-
def leaf(labeled_featuresets):
|
|
168
|
-
label = FreqDist(label for (featureset, label)
|
|
169
|
-
in labeled_featuresets).max()
|
|
170
|
-
return DecisionTreeClassifier(label)
|
|
171
|
-
|
|
172
|
-
@staticmethod
|
|
173
|
-
def stump(feature_name, labeled_featuresets):
|
|
174
|
-
label = FreqDist(label for (featureset, label)
|
|
175
|
-
in labeled_featuresets).max()
|
|
176
|
-
|
|
177
|
-
# Find the best label for each value.
|
|
178
|
-
freqs = defaultdict(FreqDist) # freq(label|value)
|
|
179
|
-
for featureset, label in labeled_featuresets:
|
|
180
|
-
feature_value = featureset.get(feature_name)
|
|
181
|
-
freqs[feature_value][label] += 1
|
|
182
|
-
|
|
183
|
-
decisions = dict((val, DecisionTreeClassifier(freqs[val].max()))
|
|
184
|
-
for val in freqs)
|
|
185
|
-
return DecisionTreeClassifier(label, feature_name, decisions)
|
|
186
|
-
|
|
187
|
-
def refine(self, labeled_featuresets, entropy_cutoff, depth_cutoff,
|
|
188
|
-
support_cutoff, binary=False, feature_values=None,
|
|
189
|
-
verbose=False):
|
|
190
|
-
if len(labeled_featuresets) <= support_cutoff: return
|
|
191
|
-
if self._fname is None: return
|
|
192
|
-
if depth_cutoff <= 0: return
|
|
193
|
-
for fval in self._decisions:
|
|
194
|
-
fval_featuresets = [(featureset, label) for (featureset, label)
|
|
195
|
-
in labeled_featuresets
|
|
196
|
-
if featureset.get(self._fname) == fval]
|
|
197
|
-
|
|
198
|
-
label_freqs = FreqDist(label for (featureset, label)
|
|
199
|
-
in fval_featuresets)
|
|
200
|
-
if entropy(MLEProbDist(label_freqs)) > entropy_cutoff:
|
|
201
|
-
self._decisions[fval] = DecisionTreeClassifier.train(
|
|
202
|
-
fval_featuresets, entropy_cutoff, depth_cutoff,
|
|
203
|
-
support_cutoff, binary, feature_values, verbose)
|
|
204
|
-
if self._default is not None:
|
|
205
|
-
default_featuresets = [(featureset, label) for (featureset, label)
|
|
206
|
-
in labeled_featuresets
|
|
207
|
-
if featureset.get(self._fname) not in
|
|
208
|
-
self._decisions]
|
|
209
|
-
label_freqs = FreqDist(label for (featureset, label)
|
|
210
|
-
in default_featuresets)
|
|
211
|
-
if entropy(MLEProbDist(label_freqs)) > entropy_cutoff:
|
|
212
|
-
self._default = DecisionTreeClassifier.train(
|
|
213
|
-
default_featuresets, entropy_cutoff, depth_cutoff,
|
|
214
|
-
support_cutoff, binary, feature_values, verbose)
|
|
215
|
-
|
|
216
|
-
@staticmethod
|
|
217
|
-
def best_stump(feature_names, labeled_featuresets, verbose=False):
|
|
218
|
-
best_stump = DecisionTreeClassifier.leaf(labeled_featuresets)
|
|
219
|
-
best_error = best_stump.error(labeled_featuresets)
|
|
220
|
-
for fname in feature_names:
|
|
221
|
-
stump = DecisionTreeClassifier.stump(fname, labeled_featuresets)
|
|
222
|
-
stump_error = stump.error(labeled_featuresets)
|
|
223
|
-
if stump_error < best_error:
|
|
224
|
-
best_error = stump_error
|
|
225
|
-
best_stump = stump
|
|
226
|
-
if verbose:
|
|
227
|
-
print(('best stump for
|
|
228
|
-
(len(labeled_featuresets), best_stump._fname, best_error)))
|
|
229
|
-
return best_stump
|
|
230
|
-
|
|
231
|
-
@staticmethod
|
|
232
|
-
def binary_stump(feature_name, feature_value, labeled_featuresets):
|
|
233
|
-
label = FreqDist(label for (featureset, label)
|
|
234
|
-
in labeled_featuresets).max()
|
|
235
|
-
|
|
236
|
-
# Find the best label for each value.
|
|
237
|
-
pos_fdist = FreqDist()
|
|
238
|
-
neg_fdist = FreqDist()
|
|
239
|
-
for featureset, label in labeled_featuresets:
|
|
240
|
-
if featureset.get(feature_name) == feature_value:
|
|
241
|
-
pos_fdist[label] += 1
|
|
242
|
-
else:
|
|
243
|
-
neg_fdist[label] += 1
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
decisions = {}
|
|
247
|
-
default = label
|
|
248
|
-
# But hopefully we have observations!
|
|
249
|
-
if pos_fdist.N() > 0:
|
|
250
|
-
decisions = {feature_value: DecisionTreeClassifier(pos_fdist.max())}
|
|
251
|
-
if neg_fdist.N() > 0:
|
|
252
|
-
default = DecisionTreeClassifier(neg_fdist.max())
|
|
253
|
-
|
|
254
|
-
return DecisionTreeClassifier(label, feature_name, decisions, default)
|
|
255
|
-
|
|
256
|
-
@staticmethod
|
|
257
|
-
def best_binary_stump(feature_names, labeled_featuresets, feature_values,
|
|
258
|
-
verbose=False):
|
|
259
|
-
best_stump = DecisionTreeClassifier.leaf(labeled_featuresets)
|
|
260
|
-
best_error = best_stump.error(labeled_featuresets)
|
|
261
|
-
for fname in feature_names:
|
|
262
|
-
for fval in feature_values[fname]:
|
|
263
|
-
stump = DecisionTreeClassifier.binary_stump(
|
|
264
|
-
fname, fval, labeled_featuresets)
|
|
265
|
-
stump_error = stump.error(labeled_featuresets)
|
|
266
|
-
if stump_error < best_error:
|
|
267
|
-
best_error = stump_error
|
|
268
|
-
best_stump = stump
|
|
269
|
-
if
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
print(('best stump for
|
|
276
|
-
(len(labeled_featuresets), descr, best_error)))
|
|
277
|
-
return best_stump
|
|
278
|
-
|
|
279
|
-
##//////////////////////////////////////////////////////
|
|
280
|
-
## Demo
|
|
281
|
-
##//////////////////////////////////////////////////////
|
|
282
|
-
|
|
283
|
-
def f(x):
|
|
284
|
-
return DecisionTreeClassifier.train(x, binary=True, verbose=True)
|
|
285
|
-
|
|
286
|
-
def demo():
|
|
287
|
-
from nltk.classify.util import names_demo, binary_names_demo_features
|
|
288
|
-
classifier = names_demo(f, #DecisionTreeClassifier.train,
|
|
289
|
-
binary_names_demo_features)
|
|
290
|
-
print(classifier.pp(depth=7))
|
|
291
|
-
print(classifier.pseudocode(depth=7))
|
|
292
|
-
|
|
293
|
-
if __name__ == '__main__':
|
|
294
|
-
demo()
|
|
295
|
-
|
|
1
|
+
# Natural Language Toolkit: Decision Tree Classifiers
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
4
|
+
# Author: Edward Loper <edloper@gmail.com>
|
|
5
|
+
# URL: <http://nltk.org/>
|
|
6
|
+
# For license information, see LICENSE.TXT
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
A classifier model that decides which label to assign to a token on
|
|
10
|
+
the basis of a tree structure, where branches correspond to conditions
|
|
11
|
+
on feature values, and leaves correspond to label assignments.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import print_function, unicode_literals, division
|
|
14
|
+
|
|
15
|
+
from collections import defaultdict
|
|
16
|
+
|
|
17
|
+
from nltk.probability import FreqDist, MLEProbDist, entropy
|
|
18
|
+
from nltk.classify.api import ClassifierI
|
|
19
|
+
from nltk.compat import python_2_unicode_compatible
|
|
20
|
+
|
|
21
|
+
@python_2_unicode_compatible
|
|
22
|
+
class DecisionTreeClassifier(ClassifierI):
|
|
23
|
+
def __init__(self, label, feature_name=None, decisions=None, default=None):
|
|
24
|
+
"""
|
|
25
|
+
:param label: The most likely label for tokens that reach
|
|
26
|
+
this node in the decision tree. If this decision tree
|
|
27
|
+
has no children, then this label will be assigned to
|
|
28
|
+
any token that reaches this decision tree.
|
|
29
|
+
:param feature_name: The name of the feature that this
|
|
30
|
+
decision tree selects for.
|
|
31
|
+
:param decisions: A dictionary mapping from feature values
|
|
32
|
+
for the feature identified by ``feature_name`` to
|
|
33
|
+
child decision trees.
|
|
34
|
+
:param default: The child that will be used if the value of
|
|
35
|
+
feature ``feature_name`` does not match any of the keys in
|
|
36
|
+
``decisions``. This is used when constructing binary
|
|
37
|
+
decision trees.
|
|
38
|
+
"""
|
|
39
|
+
self._label = label
|
|
40
|
+
self._fname = feature_name
|
|
41
|
+
self._decisions = decisions
|
|
42
|
+
self._default = default
|
|
43
|
+
|
|
44
|
+
def labels(self):
|
|
45
|
+
labels = [self._label]
|
|
46
|
+
if self._decisions is not None:
|
|
47
|
+
for dt in self._decisions.values():
|
|
48
|
+
labels.extend(dt.labels())
|
|
49
|
+
if self._default is not None:
|
|
50
|
+
labels.extend(self._default.labels())
|
|
51
|
+
return list(set(labels))
|
|
52
|
+
|
|
53
|
+
def classify(self, featureset):
|
|
54
|
+
# Decision leaf:
|
|
55
|
+
if self._fname is None:
|
|
56
|
+
return self._label
|
|
57
|
+
|
|
58
|
+
# Decision tree:
|
|
59
|
+
fval = featureset.get(self._fname)
|
|
60
|
+
if fval in self._decisions:
|
|
61
|
+
return self._decisions[fval].classify(featureset)
|
|
62
|
+
elif self._default is not None:
|
|
63
|
+
return self._default.classify(featureset)
|
|
64
|
+
else:
|
|
65
|
+
return self._label
|
|
66
|
+
|
|
67
|
+
def error(self, labeled_featuresets):
|
|
68
|
+
errors = 0
|
|
69
|
+
for featureset, label in labeled_featuresets:
|
|
70
|
+
if self.classify(featureset) != label:
|
|
71
|
+
errors += 1
|
|
72
|
+
return errors/len(labeled_featuresets)
|
|
73
|
+
|
|
74
|
+
def pretty_format(self, width=70, prefix='', depth=4):
|
|
75
|
+
"""
|
|
76
|
+
Return a string containing a pretty-printed version of this
|
|
77
|
+
decision tree. Each line in this string corresponds to a
|
|
78
|
+
single decision tree node or leaf, and indentation is used to
|
|
79
|
+
display the structure of the decision tree.
|
|
80
|
+
"""
|
|
81
|
+
# [xx] display default!!
|
|
82
|
+
if self._fname is None:
|
|
83
|
+
n = width-len(prefix)-15
|
|
84
|
+
return '{0}{1} {2}\n'.format(prefix, '.'*n, self._label)
|
|
85
|
+
s = ''
|
|
86
|
+
for i, (fval, result) in enumerate(sorted(self._decisions.items())):
|
|
87
|
+
hdr = '{0}{1}={2}? '.format(prefix, self._fname, fval)
|
|
88
|
+
n = width-15-len(hdr)
|
|
89
|
+
s += '{0}{1} {2}\n'.format(hdr, '.'*(n), result._label)
|
|
90
|
+
if result._fname is not None and depth>1:
|
|
91
|
+
s += result.pretty_format(width, prefix+' ', depth-1)
|
|
92
|
+
if self._default is not None:
|
|
93
|
+
n = width-len(prefix)-21
|
|
94
|
+
s += '{0}else: {1} {2}\n'.format(prefix, '.'*n, self._default._label)
|
|
95
|
+
if self._default._fname is not None and depth>1:
|
|
96
|
+
s += self._default.pretty_format(width, prefix+' ', depth-1)
|
|
97
|
+
return s
|
|
98
|
+
|
|
99
|
+
def pseudocode(self, prefix='', depth=4):
|
|
100
|
+
"""
|
|
101
|
+
Return a string representation of this decision tree that
|
|
102
|
+
expresses the decisions it makes as a nested set of pseudocode
|
|
103
|
+
if statements.
|
|
104
|
+
"""
|
|
105
|
+
if self._fname is None:
|
|
106
|
+
return "{0}return {1!r}\n".format(prefix, self._label)
|
|
107
|
+
s = ''
|
|
108
|
+
for (fval, result) in sorted(self._decisions.items()):
|
|
109
|
+
s += '{0}if {1} == {2!r}: '.format(prefix, self._fname, fval)
|
|
110
|
+
if result._fname is not None and depth>1:
|
|
111
|
+
s += '\n'+result.pseudocode(prefix+' ', depth-1)
|
|
112
|
+
else:
|
|
113
|
+
s += 'return {0!r}\n'.format(result._label)
|
|
114
|
+
if self._default is not None:
|
|
115
|
+
if len(self._decisions) == 1:
|
|
116
|
+
s += '{0}if {1} != {2!r}: '.format(prefix, self._fname,
|
|
117
|
+
list(self._decisions.keys())[0])
|
|
118
|
+
else:
|
|
119
|
+
s += '{0}else: '.format(prefix)
|
|
120
|
+
if self._default._fname is not None and depth>1:
|
|
121
|
+
s += '\n'+self._default.pseudocode(prefix+' ', depth-1)
|
|
122
|
+
else:
|
|
123
|
+
s += 'return {0!r}\n'.format(self._default._label)
|
|
124
|
+
return s
|
|
125
|
+
|
|
126
|
+
def __str__(self):
|
|
127
|
+
return self.pretty_format()
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def train(labeled_featuresets, entropy_cutoff=0.05, depth_cutoff=100,
|
|
131
|
+
support_cutoff=10, binary=False, feature_values=None,
|
|
132
|
+
verbose=False):
|
|
133
|
+
"""
|
|
134
|
+
:param binary: If true, then treat all feature/value pairs as
|
|
135
|
+
individual binary features, rather than using a single n-way
|
|
136
|
+
branch for each feature.
|
|
137
|
+
"""
|
|
138
|
+
# Collect a list of all feature names.
|
|
139
|
+
feature_names = set()
|
|
140
|
+
for featureset, label in labeled_featuresets:
|
|
141
|
+
for fname in featureset:
|
|
142
|
+
feature_names.add(fname)
|
|
143
|
+
|
|
144
|
+
# Collect a list of the values each feature can take.
|
|
145
|
+
if feature_values is None and binary:
|
|
146
|
+
feature_values = defaultdict(set)
|
|
147
|
+
for featureset, label in labeled_featuresets:
|
|
148
|
+
for fname, fval in featureset.items():
|
|
149
|
+
feature_values[fname].add(fval)
|
|
150
|
+
|
|
151
|
+
# Start with a stump.
|
|
152
|
+
if not binary:
|
|
153
|
+
tree = DecisionTreeClassifier.best_stump(
|
|
154
|
+
feature_names, labeled_featuresets, verbose)
|
|
155
|
+
else:
|
|
156
|
+
tree = DecisionTreeClassifier.best_binary_stump(
|
|
157
|
+
feature_names, labeled_featuresets, feature_values, verbose)
|
|
158
|
+
|
|
159
|
+
# Refine the stump.
|
|
160
|
+
tree.refine(labeled_featuresets, entropy_cutoff, depth_cutoff-1,
|
|
161
|
+
support_cutoff, binary, feature_values, verbose)
|
|
162
|
+
|
|
163
|
+
# Return it
|
|
164
|
+
return tree
|
|
165
|
+
|
|
166
|
+
@staticmethod
|
|
167
|
+
def leaf(labeled_featuresets):
|
|
168
|
+
label = FreqDist(label for (featureset, label)
|
|
169
|
+
in labeled_featuresets).max()
|
|
170
|
+
return DecisionTreeClassifier(label)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def stump(feature_name, labeled_featuresets):
|
|
174
|
+
label = FreqDist(label for (featureset, label)
|
|
175
|
+
in labeled_featuresets).max()
|
|
176
|
+
|
|
177
|
+
# Find the best label for each value.
|
|
178
|
+
freqs = defaultdict(FreqDist) # freq(label|value)
|
|
179
|
+
for featureset, label in labeled_featuresets:
|
|
180
|
+
feature_value = featureset.get(feature_name)
|
|
181
|
+
freqs[feature_value][label] += 1
|
|
182
|
+
|
|
183
|
+
decisions = dict((val, DecisionTreeClassifier(freqs[val].max()))
|
|
184
|
+
for val in freqs)
|
|
185
|
+
return DecisionTreeClassifier(label, feature_name, decisions)
|
|
186
|
+
|
|
187
|
+
def refine(self, labeled_featuresets, entropy_cutoff, depth_cutoff,
|
|
188
|
+
support_cutoff, binary=False, feature_values=None,
|
|
189
|
+
verbose=False):
|
|
190
|
+
if len(labeled_featuresets) <= support_cutoff: return
|
|
191
|
+
if self._fname is None: return
|
|
192
|
+
if depth_cutoff <= 0: return
|
|
193
|
+
for fval in self._decisions:
|
|
194
|
+
fval_featuresets = [(featureset, label) for (featureset, label)
|
|
195
|
+
in labeled_featuresets
|
|
196
|
+
if featureset.get(self._fname) == fval]
|
|
197
|
+
|
|
198
|
+
label_freqs = FreqDist(label for (featureset, label)
|
|
199
|
+
in fval_featuresets)
|
|
200
|
+
if entropy(MLEProbDist(label_freqs)) > entropy_cutoff:
|
|
201
|
+
self._decisions[fval] = DecisionTreeClassifier.train(
|
|
202
|
+
fval_featuresets, entropy_cutoff, depth_cutoff,
|
|
203
|
+
support_cutoff, binary, feature_values, verbose)
|
|
204
|
+
if self._default is not None:
|
|
205
|
+
default_featuresets = [(featureset, label) for (featureset, label)
|
|
206
|
+
in labeled_featuresets
|
|
207
|
+
if featureset.get(self._fname) not in
|
|
208
|
+
self._decisions]
|
|
209
|
+
label_freqs = FreqDist(label for (featureset, label)
|
|
210
|
+
in default_featuresets)
|
|
211
|
+
if entropy(MLEProbDist(label_freqs)) > entropy_cutoff:
|
|
212
|
+
self._default = DecisionTreeClassifier.train(
|
|
213
|
+
default_featuresets, entropy_cutoff, depth_cutoff,
|
|
214
|
+
support_cutoff, binary, feature_values, verbose)
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def best_stump(feature_names, labeled_featuresets, verbose=False):
|
|
218
|
+
best_stump = DecisionTreeClassifier.leaf(labeled_featuresets)
|
|
219
|
+
best_error = best_stump.error(labeled_featuresets)
|
|
220
|
+
for fname in feature_names:
|
|
221
|
+
stump = DecisionTreeClassifier.stump(fname, labeled_featuresets)
|
|
222
|
+
stump_error = stump.error(labeled_featuresets)
|
|
223
|
+
if stump_error < best_error:
|
|
224
|
+
best_error = stump_error
|
|
225
|
+
best_stump = stump
|
|
226
|
+
if verbose:
|
|
227
|
+
print(('best stump for {:6d} toks uses {:20} err={:6.4f}'.format \
|
|
228
|
+
(len(labeled_featuresets), best_stump._fname, best_error)))
|
|
229
|
+
return best_stump
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
def binary_stump(feature_name, feature_value, labeled_featuresets):
|
|
233
|
+
label = FreqDist(label for (featureset, label)
|
|
234
|
+
in labeled_featuresets).max()
|
|
235
|
+
|
|
236
|
+
# Find the best label for each value.
|
|
237
|
+
pos_fdist = FreqDist()
|
|
238
|
+
neg_fdist = FreqDist()
|
|
239
|
+
for featureset, label in labeled_featuresets:
|
|
240
|
+
if featureset.get(feature_name) == feature_value:
|
|
241
|
+
pos_fdist[label] += 1
|
|
242
|
+
else:
|
|
243
|
+
neg_fdist[label] += 1
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
decisions = {}
|
|
247
|
+
default = label
|
|
248
|
+
# But hopefully we have observations!
|
|
249
|
+
if pos_fdist.N() > 0:
|
|
250
|
+
decisions = {feature_value: DecisionTreeClassifier(pos_fdist.max())}
|
|
251
|
+
if neg_fdist.N() > 0:
|
|
252
|
+
default = DecisionTreeClassifier(neg_fdist.max())
|
|
253
|
+
|
|
254
|
+
return DecisionTreeClassifier(label, feature_name, decisions, default)
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
def best_binary_stump(feature_names, labeled_featuresets, feature_values,
|
|
258
|
+
verbose=False):
|
|
259
|
+
best_stump = DecisionTreeClassifier.leaf(labeled_featuresets)
|
|
260
|
+
best_error = best_stump.error(labeled_featuresets)
|
|
261
|
+
for fname in feature_names:
|
|
262
|
+
for fval in feature_values[fname]:
|
|
263
|
+
stump = DecisionTreeClassifier.binary_stump(
|
|
264
|
+
fname, fval, labeled_featuresets)
|
|
265
|
+
stump_error = stump.error(labeled_featuresets)
|
|
266
|
+
if stump_error < best_error:
|
|
267
|
+
best_error = stump_error
|
|
268
|
+
best_stump = stump
|
|
269
|
+
if verbose:
|
|
270
|
+
if best_stump._decisions:
|
|
271
|
+
descr = '{0}={1}'.format(best_stump._fname,
|
|
272
|
+
list(best_stump._decisions.keys())[0])
|
|
273
|
+
else:
|
|
274
|
+
descr = '(default)'
|
|
275
|
+
print(('best stump for {:6d} toks uses {:20} err={:6.4f}'.format \
|
|
276
|
+
(len(labeled_featuresets), descr, best_error)))
|
|
277
|
+
return best_stump
|
|
278
|
+
|
|
279
|
+
##//////////////////////////////////////////////////////
|
|
280
|
+
## Demo
|
|
281
|
+
##//////////////////////////////////////////////////////
|
|
282
|
+
|
|
283
|
+
def f(x):
|
|
284
|
+
return DecisionTreeClassifier.train(x, binary=True, verbose=True)
|
|
285
|
+
|
|
286
|
+
def demo():
|
|
287
|
+
from nltk.classify.util import names_demo, binary_names_demo_features
|
|
288
|
+
classifier = names_demo(f, #DecisionTreeClassifier.train,
|
|
289
|
+
binary_names_demo_features)
|
|
290
|
+
print(classifier.pp(depth=7))
|
|
291
|
+
print(classifier.pseudocode(depth=7))
|
|
292
|
+
|
|
293
|
+
if __name__ == '__main__':
|
|
294
|
+
demo()
|
|
295
|
+
|