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,2036 +1,2108 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# Natural Language Toolkit: WordNet
|
|
3
|
-
#
|
|
4
|
-
# Copyright (C) 2001-
|
|
5
|
-
# Author: Steven Bethard <Steven.Bethard@colorado.edu>
|
|
6
|
-
# Steven Bird <stevenbird1@gmail.com>
|
|
7
|
-
# Edward Loper <edloper@gmail.com>
|
|
8
|
-
# Nitin Madnani <nmadnani@ets.org>
|
|
9
|
-
# Nasruddin A’aidil Shari
|
|
10
|
-
# Sim Wei Ying Geraldine
|
|
11
|
-
# Soe Lynn
|
|
12
|
-
# Francis Bond <bond@ieee.org>
|
|
13
|
-
# URL: <http://nltk.org/>
|
|
14
|
-
# For license information, see LICENSE.TXT
|
|
15
|
-
|
|
16
|
-
"""
|
|
17
|
-
An NLTK interface for WordNet
|
|
18
|
-
|
|
19
|
-
WordNet is a lexical database of English.
|
|
20
|
-
Using synsets, helps find conceptual relationships between words
|
|
21
|
-
such as hypernyms, hyponyms, synonyms, antonyms etc.
|
|
22
|
-
|
|
23
|
-
For details about WordNet see:
|
|
24
|
-
http://wordnet.princeton.edu/
|
|
25
|
-
|
|
26
|
-
This module also allows you to find lemmas in languages
|
|
27
|
-
other than English from the Open Multilingual Wordnet
|
|
28
|
-
http://compling.hss.ntu.edu.sg/omw/
|
|
29
|
-
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
from __future__ import print_function, unicode_literals
|
|
33
|
-
|
|
34
|
-
import math
|
|
35
|
-
import re
|
|
36
|
-
from itertools import islice, chain
|
|
37
|
-
from
|
|
38
|
-
from
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
from
|
|
42
|
-
from
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"Something %s
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"Something %s
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"Somebody %s
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"Somebody %s
|
|
92
|
-
"Somebody %s somebody
|
|
93
|
-
"Somebody %s something
|
|
94
|
-
"Somebody %s somebody
|
|
95
|
-
"Somebody %s something
|
|
96
|
-
"Somebody %s
|
|
97
|
-
"Somebody
|
|
98
|
-
"Somebody %s somebody
|
|
99
|
-
"Somebody %s
|
|
100
|
-
"Somebody %s
|
|
101
|
-
"Somebody %s
|
|
102
|
-
"Somebody %s to INFINITIVE",
|
|
103
|
-
"Somebody %s
|
|
104
|
-
"Somebody %s
|
|
105
|
-
"Somebody %s
|
|
106
|
-
"Somebody %s INFINITIVE",
|
|
107
|
-
"Somebody %s
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def
|
|
132
|
-
return self._related('@
|
|
133
|
-
|
|
134
|
-
def
|
|
135
|
-
return self._related('@
|
|
136
|
-
|
|
137
|
-
def
|
|
138
|
-
return self._related('
|
|
139
|
-
|
|
140
|
-
def
|
|
141
|
-
return self._related('
|
|
142
|
-
|
|
143
|
-
def
|
|
144
|
-
return self._related('
|
|
145
|
-
|
|
146
|
-
def
|
|
147
|
-
return self._related('
|
|
148
|
-
|
|
149
|
-
def
|
|
150
|
-
return self._related('#
|
|
151
|
-
|
|
152
|
-
def
|
|
153
|
-
return self._related('
|
|
154
|
-
|
|
155
|
-
def
|
|
156
|
-
return self._related('
|
|
157
|
-
|
|
158
|
-
def
|
|
159
|
-
return self._related('%
|
|
160
|
-
|
|
161
|
-
def
|
|
162
|
-
return self._related('
|
|
163
|
-
|
|
164
|
-
def
|
|
165
|
-
return self._related('
|
|
166
|
-
|
|
167
|
-
def
|
|
168
|
-
return self._related(';
|
|
169
|
-
|
|
170
|
-
def
|
|
171
|
-
return self._related('
|
|
172
|
-
|
|
173
|
-
def
|
|
174
|
-
return self._related('
|
|
175
|
-
|
|
176
|
-
def
|
|
177
|
-
return self._related('
|
|
178
|
-
|
|
179
|
-
def
|
|
180
|
-
return self._related('
|
|
181
|
-
|
|
182
|
-
def
|
|
183
|
-
return self._related('
|
|
184
|
-
|
|
185
|
-
def
|
|
186
|
-
return self._related('
|
|
187
|
-
|
|
188
|
-
def
|
|
189
|
-
return
|
|
190
|
-
|
|
191
|
-
def
|
|
192
|
-
return self.
|
|
193
|
-
|
|
194
|
-
def
|
|
195
|
-
return self._name
|
|
196
|
-
|
|
197
|
-
def
|
|
198
|
-
return self._name
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
-
|
|
247
|
-
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
self.
|
|
263
|
-
self.
|
|
264
|
-
self.
|
|
265
|
-
|
|
266
|
-
self.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def
|
|
275
|
-
return self.
|
|
276
|
-
|
|
277
|
-
def
|
|
278
|
-
return self.
|
|
279
|
-
|
|
280
|
-
def
|
|
281
|
-
return self.
|
|
282
|
-
|
|
283
|
-
def
|
|
284
|
-
return self.
|
|
285
|
-
|
|
286
|
-
def
|
|
287
|
-
return self.
|
|
288
|
-
|
|
289
|
-
def
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
def
|
|
300
|
-
|
|
301
|
-
return
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
-
|
|
356
|
-
-
|
|
357
|
-
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
-
|
|
364
|
-
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
self.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
self.
|
|
387
|
-
self.
|
|
388
|
-
|
|
389
|
-
self.
|
|
390
|
-
self.
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
"""
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
synsets
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
:
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
:
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
:
|
|
947
|
-
:
|
|
948
|
-
:
|
|
949
|
-
:
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
"""
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
return
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
"""
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
#
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
def
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
if
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
#
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
return
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
return
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
return
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
return
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
ic
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
#
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
return
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Natural Language Toolkit: WordNet
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
5
|
+
# Author: Steven Bethard <Steven.Bethard@colorado.edu>
|
|
6
|
+
# Steven Bird <stevenbird1@gmail.com>
|
|
7
|
+
# Edward Loper <edloper@gmail.com>
|
|
8
|
+
# Nitin Madnani <nmadnani@ets.org>
|
|
9
|
+
# Nasruddin A’aidil Shari
|
|
10
|
+
# Sim Wei Ying Geraldine
|
|
11
|
+
# Soe Lynn
|
|
12
|
+
# Francis Bond <bond@ieee.org>
|
|
13
|
+
# URL: <http://nltk.org/>
|
|
14
|
+
# For license information, see LICENSE.TXT
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
An NLTK interface for WordNet
|
|
18
|
+
|
|
19
|
+
WordNet is a lexical database of English.
|
|
20
|
+
Using synsets, helps find conceptual relationships between words
|
|
21
|
+
such as hypernyms, hyponyms, synonyms, antonyms etc.
|
|
22
|
+
|
|
23
|
+
For details about WordNet see:
|
|
24
|
+
http://wordnet.princeton.edu/
|
|
25
|
+
|
|
26
|
+
This module also allows you to find lemmas in languages
|
|
27
|
+
other than English from the Open Multilingual Wordnet
|
|
28
|
+
http://compling.hss.ntu.edu.sg/omw/
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import print_function, unicode_literals
|
|
33
|
+
|
|
34
|
+
import math
|
|
35
|
+
import re
|
|
36
|
+
from itertools import islice, chain
|
|
37
|
+
from functools import total_ordering
|
|
38
|
+
from operator import itemgetter
|
|
39
|
+
from collections import defaultdict, deque
|
|
40
|
+
|
|
41
|
+
from six import iteritems
|
|
42
|
+
from six.moves import range
|
|
43
|
+
|
|
44
|
+
from nltk.corpus.reader import CorpusReader
|
|
45
|
+
from nltk.util import binary_search_file as _binary_search_file
|
|
46
|
+
from nltk.probability import FreqDist
|
|
47
|
+
from nltk.compat import python_2_unicode_compatible
|
|
48
|
+
from nltk.internals import deprecated
|
|
49
|
+
|
|
50
|
+
######################################################################
|
|
51
|
+
# Table of Contents
|
|
52
|
+
######################################################################
|
|
53
|
+
# - Constants
|
|
54
|
+
# - Data Classes
|
|
55
|
+
# - WordNetError
|
|
56
|
+
# - Lemma
|
|
57
|
+
# - Synset
|
|
58
|
+
# - WordNet Corpus Reader
|
|
59
|
+
# - WordNet Information Content Corpus Reader
|
|
60
|
+
# - Similarity Metrics
|
|
61
|
+
# - Demo
|
|
62
|
+
|
|
63
|
+
######################################################################
|
|
64
|
+
# Constants
|
|
65
|
+
######################################################################
|
|
66
|
+
|
|
67
|
+
#: Positive infinity (for similarity functions)
|
|
68
|
+
_INF = 1e300
|
|
69
|
+
|
|
70
|
+
# { Part-of-speech constants
|
|
71
|
+
ADJ, ADJ_SAT, ADV, NOUN, VERB = 'a', 's', 'r', 'n', 'v'
|
|
72
|
+
# }
|
|
73
|
+
|
|
74
|
+
POS_LIST = [NOUN, VERB, ADJ, ADV]
|
|
75
|
+
|
|
76
|
+
# A table of strings that are used to express verb frames.
|
|
77
|
+
VERB_FRAME_STRINGS = (
|
|
78
|
+
None,
|
|
79
|
+
"Something %s",
|
|
80
|
+
"Somebody %s",
|
|
81
|
+
"It is %sing",
|
|
82
|
+
"Something is %sing PP",
|
|
83
|
+
"Something %s something Adjective/Noun",
|
|
84
|
+
"Something %s Adjective/Noun",
|
|
85
|
+
"Somebody %s Adjective",
|
|
86
|
+
"Somebody %s something",
|
|
87
|
+
"Somebody %s somebody",
|
|
88
|
+
"Something %s somebody",
|
|
89
|
+
"Something %s something",
|
|
90
|
+
"Something %s to somebody",
|
|
91
|
+
"Somebody %s on something",
|
|
92
|
+
"Somebody %s somebody something",
|
|
93
|
+
"Somebody %s something to somebody",
|
|
94
|
+
"Somebody %s something from somebody",
|
|
95
|
+
"Somebody %s somebody with something",
|
|
96
|
+
"Somebody %s somebody of something",
|
|
97
|
+
"Somebody %s something on somebody",
|
|
98
|
+
"Somebody %s somebody PP",
|
|
99
|
+
"Somebody %s something PP",
|
|
100
|
+
"Somebody %s PP",
|
|
101
|
+
"Somebody's (body part) %s",
|
|
102
|
+
"Somebody %s somebody to INFINITIVE",
|
|
103
|
+
"Somebody %s somebody INFINITIVE",
|
|
104
|
+
"Somebody %s that CLAUSE",
|
|
105
|
+
"Somebody %s to somebody",
|
|
106
|
+
"Somebody %s to INFINITIVE",
|
|
107
|
+
"Somebody %s whether INFINITIVE",
|
|
108
|
+
"Somebody %s somebody into V-ing something",
|
|
109
|
+
"Somebody %s something with something",
|
|
110
|
+
"Somebody %s INFINITIVE",
|
|
111
|
+
"Somebody %s VERB-ing",
|
|
112
|
+
"It %s that CLAUSE",
|
|
113
|
+
"Something %s INFINITIVE")
|
|
114
|
+
|
|
115
|
+
SENSENUM_RE = re.compile(r'\.[\d]+\.')
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
######################################################################
|
|
119
|
+
# Data Classes
|
|
120
|
+
######################################################################
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class WordNetError(Exception):
|
|
124
|
+
"""An exception class for wordnet-related errors."""
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@total_ordering
|
|
128
|
+
class _WordNetObject(object):
|
|
129
|
+
"""A common base class for lemmas and synsets."""
|
|
130
|
+
|
|
131
|
+
def hypernyms(self):
|
|
132
|
+
return self._related('@')
|
|
133
|
+
|
|
134
|
+
def _hypernyms(self):
|
|
135
|
+
return self._related('@')
|
|
136
|
+
|
|
137
|
+
def instance_hypernyms(self):
|
|
138
|
+
return self._related('@i')
|
|
139
|
+
|
|
140
|
+
def _instance_hypernyms(self):
|
|
141
|
+
return self._related('@i')
|
|
142
|
+
|
|
143
|
+
def hyponyms(self):
|
|
144
|
+
return self._related('~')
|
|
145
|
+
|
|
146
|
+
def instance_hyponyms(self):
|
|
147
|
+
return self._related('~i')
|
|
148
|
+
|
|
149
|
+
def member_holonyms(self):
|
|
150
|
+
return self._related('#m')
|
|
151
|
+
|
|
152
|
+
def substance_holonyms(self):
|
|
153
|
+
return self._related('#s')
|
|
154
|
+
|
|
155
|
+
def part_holonyms(self):
|
|
156
|
+
return self._related('#p')
|
|
157
|
+
|
|
158
|
+
def member_meronyms(self):
|
|
159
|
+
return self._related('%m')
|
|
160
|
+
|
|
161
|
+
def substance_meronyms(self):
|
|
162
|
+
return self._related('%s')
|
|
163
|
+
|
|
164
|
+
def part_meronyms(self):
|
|
165
|
+
return self._related('%p')
|
|
166
|
+
|
|
167
|
+
def topic_domains(self):
|
|
168
|
+
return self._related(';c')
|
|
169
|
+
|
|
170
|
+
def region_domains(self):
|
|
171
|
+
return self._related(';r')
|
|
172
|
+
|
|
173
|
+
def usage_domains(self):
|
|
174
|
+
return self._related(';u')
|
|
175
|
+
|
|
176
|
+
def attributes(self):
|
|
177
|
+
return self._related('=')
|
|
178
|
+
|
|
179
|
+
def entailments(self):
|
|
180
|
+
return self._related('*')
|
|
181
|
+
|
|
182
|
+
def causes(self):
|
|
183
|
+
return self._related('>')
|
|
184
|
+
|
|
185
|
+
def also_sees(self):
|
|
186
|
+
return self._related('^')
|
|
187
|
+
|
|
188
|
+
def verb_groups(self):
|
|
189
|
+
return self._related('$')
|
|
190
|
+
|
|
191
|
+
def similar_tos(self):
|
|
192
|
+
return self._related('&')
|
|
193
|
+
|
|
194
|
+
def __hash__(self):
|
|
195
|
+
return hash(self._name)
|
|
196
|
+
|
|
197
|
+
def __eq__(self, other):
|
|
198
|
+
return self._name == other._name
|
|
199
|
+
|
|
200
|
+
def __ne__(self, other):
|
|
201
|
+
return self._name != other._name
|
|
202
|
+
|
|
203
|
+
def __lt__(self, other):
|
|
204
|
+
return self._name < other._name
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@python_2_unicode_compatible
|
|
208
|
+
class Lemma(_WordNetObject):
|
|
209
|
+
"""
|
|
210
|
+
The lexical entry for a single morphological form of a
|
|
211
|
+
sense-disambiguated word.
|
|
212
|
+
|
|
213
|
+
Create a Lemma from a "<word>.<pos>.<number>.<lemma>" string where:
|
|
214
|
+
<word> is the morphological stem identifying the synset
|
|
215
|
+
<pos> is one of the module attributes ADJ, ADJ_SAT, ADV, NOUN or VERB
|
|
216
|
+
<number> is the sense number, counting from 0.
|
|
217
|
+
<lemma> is the morphological form of interest
|
|
218
|
+
|
|
219
|
+
Note that <word> and <lemma> can be different, e.g. the Synset
|
|
220
|
+
'salt.n.03' has the Lemmas 'salt.n.03.salt', 'salt.n.03.saltiness' and
|
|
221
|
+
'salt.n.03.salinity'.
|
|
222
|
+
|
|
223
|
+
Lemma attributes, accessible via methods with the same name::
|
|
224
|
+
|
|
225
|
+
- name: The canonical name of this lemma.
|
|
226
|
+
- synset: The synset that this lemma belongs to.
|
|
227
|
+
- syntactic_marker: For adjectives, the WordNet string identifying the
|
|
228
|
+
syntactic position relative modified noun. See:
|
|
229
|
+
http://wordnet.princeton.edu/man/wninput.5WN.html#sect10
|
|
230
|
+
For all other parts of speech, this attribute is None.
|
|
231
|
+
- count: The frequency of this lemma in wordnet.
|
|
232
|
+
|
|
233
|
+
Lemma methods:
|
|
234
|
+
|
|
235
|
+
Lemmas have the following methods for retrieving related Lemmas. They
|
|
236
|
+
correspond to the names for the pointer symbols defined here:
|
|
237
|
+
http://wordnet.princeton.edu/man/wninput.5WN.html#sect3
|
|
238
|
+
These methods all return lists of Lemmas:
|
|
239
|
+
|
|
240
|
+
- antonyms
|
|
241
|
+
- hypernyms, instance_hypernyms
|
|
242
|
+
- hyponyms, instance_hyponyms
|
|
243
|
+
- member_holonyms, substance_holonyms, part_holonyms
|
|
244
|
+
- member_meronyms, substance_meronyms, part_meronyms
|
|
245
|
+
- topic_domains, region_domains, usage_domains
|
|
246
|
+
- attributes
|
|
247
|
+
- derivationally_related_forms
|
|
248
|
+
- entailments
|
|
249
|
+
- causes
|
|
250
|
+
- also_sees
|
|
251
|
+
- verb_groups
|
|
252
|
+
- similar_tos
|
|
253
|
+
- pertainyms
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
__slots__ = ['_wordnet_corpus_reader', '_name', '_syntactic_marker',
|
|
257
|
+
'_synset', '_frame_strings', '_frame_ids',
|
|
258
|
+
'_lexname_index', '_lex_id', '_lang', '_key']
|
|
259
|
+
|
|
260
|
+
def __init__(self, wordnet_corpus_reader, synset, name,
|
|
261
|
+
lexname_index, lex_id, syntactic_marker):
|
|
262
|
+
self._wordnet_corpus_reader = wordnet_corpus_reader
|
|
263
|
+
self._name = name
|
|
264
|
+
self._syntactic_marker = syntactic_marker
|
|
265
|
+
self._synset = synset
|
|
266
|
+
self._frame_strings = []
|
|
267
|
+
self._frame_ids = []
|
|
268
|
+
self._lexname_index = lexname_index
|
|
269
|
+
self._lex_id = lex_id
|
|
270
|
+
self._lang = 'eng'
|
|
271
|
+
|
|
272
|
+
self._key = None # gets set later.
|
|
273
|
+
|
|
274
|
+
def name(self):
|
|
275
|
+
return self._name
|
|
276
|
+
|
|
277
|
+
def syntactic_marker(self):
|
|
278
|
+
return self._syntactic_marker
|
|
279
|
+
|
|
280
|
+
def synset(self):
|
|
281
|
+
return self._synset
|
|
282
|
+
|
|
283
|
+
def frame_strings(self):
|
|
284
|
+
return self._frame_strings
|
|
285
|
+
|
|
286
|
+
def frame_ids(self):
|
|
287
|
+
return self._frame_ids
|
|
288
|
+
|
|
289
|
+
def lang(self):
|
|
290
|
+
return self._lang
|
|
291
|
+
|
|
292
|
+
def key(self):
|
|
293
|
+
return self._key
|
|
294
|
+
|
|
295
|
+
def __repr__(self):
|
|
296
|
+
tup = type(self).__name__, self._synset._name, self._name
|
|
297
|
+
return "%s('%s.%s')" % tup
|
|
298
|
+
|
|
299
|
+
def _related(self, relation_symbol):
|
|
300
|
+
get_synset = self._wordnet_corpus_reader.synset_from_pos_and_offset
|
|
301
|
+
return [
|
|
302
|
+
get_synset(pos, offset)._lemmas[lemma_index]
|
|
303
|
+
for pos, offset, lemma_index
|
|
304
|
+
in self._synset._lemma_pointers[self._name, relation_symbol]
|
|
305
|
+
]
|
|
306
|
+
|
|
307
|
+
def count(self):
|
|
308
|
+
"""Return the frequency count for this Lemma"""
|
|
309
|
+
return self._wordnet_corpus_reader.lemma_count(self)
|
|
310
|
+
|
|
311
|
+
def antonyms(self):
|
|
312
|
+
return self._related('!')
|
|
313
|
+
|
|
314
|
+
def derivationally_related_forms(self):
|
|
315
|
+
return self._related('+')
|
|
316
|
+
|
|
317
|
+
def pertainyms(self):
|
|
318
|
+
return self._related('\\')
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@python_2_unicode_compatible
|
|
322
|
+
class Synset(_WordNetObject):
|
|
323
|
+
"""Create a Synset from a "<lemma>.<pos>.<number>" string where:
|
|
324
|
+
<lemma> is the word's morphological stem
|
|
325
|
+
<pos> is one of the module attributes ADJ, ADJ_SAT, ADV, NOUN or VERB
|
|
326
|
+
<number> is the sense number, counting from 0.
|
|
327
|
+
|
|
328
|
+
Synset attributes, accessible via methods with the same name:
|
|
329
|
+
|
|
330
|
+
- name: The canonical name of this synset, formed using the first lemma
|
|
331
|
+
of this synset. Note that this may be different from the name
|
|
332
|
+
passed to the constructor if that string used a different lemma to
|
|
333
|
+
identify the synset.
|
|
334
|
+
- pos: The synset's part of speech, matching one of the module level
|
|
335
|
+
attributes ADJ, ADJ_SAT, ADV, NOUN or VERB.
|
|
336
|
+
- lemmas: A list of the Lemma objects for this synset.
|
|
337
|
+
- definition: The definition for this synset.
|
|
338
|
+
- examples: A list of example strings for this synset.
|
|
339
|
+
- offset: The offset in the WordNet dict file of this synset.
|
|
340
|
+
- lexname: The name of the lexicographer file containing this synset.
|
|
341
|
+
|
|
342
|
+
Synset methods:
|
|
343
|
+
|
|
344
|
+
Synsets have the following methods for retrieving related Synsets.
|
|
345
|
+
They correspond to the names for the pointer symbols defined here:
|
|
346
|
+
http://wordnet.princeton.edu/man/wninput.5WN.html#sect3
|
|
347
|
+
These methods all return lists of Synsets.
|
|
348
|
+
|
|
349
|
+
- hypernyms, instance_hypernyms
|
|
350
|
+
- hyponyms, instance_hyponyms
|
|
351
|
+
- member_holonyms, substance_holonyms, part_holonyms
|
|
352
|
+
- member_meronyms, substance_meronyms, part_meronyms
|
|
353
|
+
- attributes
|
|
354
|
+
- entailments
|
|
355
|
+
- causes
|
|
356
|
+
- also_sees
|
|
357
|
+
- verb_groups
|
|
358
|
+
- similar_tos
|
|
359
|
+
|
|
360
|
+
Additionally, Synsets support the following methods specific to the
|
|
361
|
+
hypernym relation:
|
|
362
|
+
|
|
363
|
+
- root_hypernyms
|
|
364
|
+
- common_hypernyms
|
|
365
|
+
- lowest_common_hypernyms
|
|
366
|
+
|
|
367
|
+
Note that Synsets do not support the following relations because
|
|
368
|
+
these are defined by WordNet as lexical relations:
|
|
369
|
+
|
|
370
|
+
- antonyms
|
|
371
|
+
- derivationally_related_forms
|
|
372
|
+
- pertainyms
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
__slots__ = ['_pos', '_offset', '_name', '_frame_ids',
|
|
376
|
+
'_lemmas', '_lemma_names',
|
|
377
|
+
'_definition', '_examples', '_lexname',
|
|
378
|
+
'_pointers', '_lemma_pointers', '_max_depth',
|
|
379
|
+
'_min_depth']
|
|
380
|
+
|
|
381
|
+
def __init__(self, wordnet_corpus_reader):
|
|
382
|
+
self._wordnet_corpus_reader = wordnet_corpus_reader
|
|
383
|
+
# All of these attributes get initialized by
|
|
384
|
+
# WordNetCorpusReader._synset_from_pos_and_line()
|
|
385
|
+
|
|
386
|
+
self._pos = None
|
|
387
|
+
self._offset = None
|
|
388
|
+
self._name = None
|
|
389
|
+
self._frame_ids = []
|
|
390
|
+
self._lemmas = []
|
|
391
|
+
self._lemma_names = []
|
|
392
|
+
self._definition = None
|
|
393
|
+
self._examples = []
|
|
394
|
+
self._lexname = None # lexicographer name
|
|
395
|
+
self._all_hypernyms = None
|
|
396
|
+
|
|
397
|
+
self._pointers = defaultdict(set)
|
|
398
|
+
self._lemma_pointers = defaultdict(list)
|
|
399
|
+
|
|
400
|
+
def pos(self):
|
|
401
|
+
return self._pos
|
|
402
|
+
|
|
403
|
+
def offset(self):
|
|
404
|
+
return self._offset
|
|
405
|
+
|
|
406
|
+
def name(self):
|
|
407
|
+
return self._name
|
|
408
|
+
|
|
409
|
+
def frame_ids(self):
|
|
410
|
+
return self._frame_ids
|
|
411
|
+
|
|
412
|
+
def definition(self):
|
|
413
|
+
return self._definition
|
|
414
|
+
|
|
415
|
+
def examples(self):
|
|
416
|
+
return self._examples
|
|
417
|
+
|
|
418
|
+
def lexname(self):
|
|
419
|
+
return self._lexname
|
|
420
|
+
|
|
421
|
+
def _needs_root(self):
|
|
422
|
+
if self._pos == NOUN:
|
|
423
|
+
if self._wordnet_corpus_reader.get_version() == '1.6':
|
|
424
|
+
return True
|
|
425
|
+
else:
|
|
426
|
+
return False
|
|
427
|
+
elif self._pos == VERB:
|
|
428
|
+
return True
|
|
429
|
+
|
|
430
|
+
def lemma_names(self, lang='eng'):
|
|
431
|
+
'''Return all the lemma_names associated with the synset'''
|
|
432
|
+
if lang == 'eng':
|
|
433
|
+
return self._lemma_names
|
|
434
|
+
else:
|
|
435
|
+
self._wordnet_corpus_reader._load_lang_data(lang)
|
|
436
|
+
|
|
437
|
+
i = self._wordnet_corpus_reader.ss2of(self)
|
|
438
|
+
if i in self._wordnet_corpus_reader._lang_data[lang][0]:
|
|
439
|
+
return self._wordnet_corpus_reader._lang_data[lang][0][i]
|
|
440
|
+
else:
|
|
441
|
+
return []
|
|
442
|
+
|
|
443
|
+
def lemmas(self, lang='eng'):
|
|
444
|
+
'''Return all the lemma objects associated with the synset'''
|
|
445
|
+
if lang == 'eng':
|
|
446
|
+
return self._lemmas
|
|
447
|
+
else:
|
|
448
|
+
self._wordnet_corpus_reader._load_lang_data(lang)
|
|
449
|
+
lemmark = []
|
|
450
|
+
lemmy = self.lemma_names(lang)
|
|
451
|
+
for lem in lemmy:
|
|
452
|
+
temp = Lemma(
|
|
453
|
+
self._wordnet_corpus_reader,
|
|
454
|
+
self,
|
|
455
|
+
lem,
|
|
456
|
+
self._wordnet_corpus_reader._lexnames.index(
|
|
457
|
+
self.lexname()
|
|
458
|
+
),
|
|
459
|
+
0,
|
|
460
|
+
None
|
|
461
|
+
)
|
|
462
|
+
temp._lang = lang
|
|
463
|
+
lemmark.append(temp)
|
|
464
|
+
return lemmark
|
|
465
|
+
|
|
466
|
+
def root_hypernyms(self):
|
|
467
|
+
"""Get the topmost hypernyms of this synset in WordNet."""
|
|
468
|
+
|
|
469
|
+
result = []
|
|
470
|
+
seen = set()
|
|
471
|
+
todo = [self]
|
|
472
|
+
while todo:
|
|
473
|
+
next_synset = todo.pop()
|
|
474
|
+
if next_synset not in seen:
|
|
475
|
+
seen.add(next_synset)
|
|
476
|
+
next_hypernyms = next_synset.hypernyms() + \
|
|
477
|
+
next_synset.instance_hypernyms()
|
|
478
|
+
if not next_hypernyms:
|
|
479
|
+
result.append(next_synset)
|
|
480
|
+
else:
|
|
481
|
+
todo.extend(next_hypernyms)
|
|
482
|
+
return result
|
|
483
|
+
|
|
484
|
+
# Simpler implementation which makes incorrect assumption that
|
|
485
|
+
# hypernym hierarchy is acyclic:
|
|
486
|
+
#
|
|
487
|
+
# if not self.hypernyms():
|
|
488
|
+
# return [self]
|
|
489
|
+
# else:
|
|
490
|
+
# return list(set(root for h in self.hypernyms()
|
|
491
|
+
# for root in h.root_hypernyms()))
|
|
492
|
+
def max_depth(self):
|
|
493
|
+
"""
|
|
494
|
+
:return: The length of the longest hypernym path from this
|
|
495
|
+
synset to the root.
|
|
496
|
+
"""
|
|
497
|
+
|
|
498
|
+
if "_max_depth" not in self.__dict__:
|
|
499
|
+
hypernyms = self.hypernyms() + self.instance_hypernyms()
|
|
500
|
+
if not hypernyms:
|
|
501
|
+
self._max_depth = 0
|
|
502
|
+
else:
|
|
503
|
+
self._max_depth = 1 + max(h.max_depth() for h in hypernyms)
|
|
504
|
+
return self._max_depth
|
|
505
|
+
|
|
506
|
+
def min_depth(self):
|
|
507
|
+
"""
|
|
508
|
+
:return: The length of the shortest hypernym path from this
|
|
509
|
+
synset to the root.
|
|
510
|
+
"""
|
|
511
|
+
|
|
512
|
+
if "_min_depth" not in self.__dict__:
|
|
513
|
+
hypernyms = self.hypernyms() + self.instance_hypernyms()
|
|
514
|
+
if not hypernyms:
|
|
515
|
+
self._min_depth = 0
|
|
516
|
+
else:
|
|
517
|
+
self._min_depth = 1 + min(h.min_depth() for h in hypernyms)
|
|
518
|
+
return self._min_depth
|
|
519
|
+
|
|
520
|
+
def closure(self, rel, depth=-1):
|
|
521
|
+
"""Return the transitive closure of source under the rel
|
|
522
|
+
relationship, breadth-first
|
|
523
|
+
|
|
524
|
+
>>> from nltk.corpus import wordnet as wn
|
|
525
|
+
>>> dog = wn.synset('dog.n.01')
|
|
526
|
+
>>> hyp = lambda s:s.hypernyms()
|
|
527
|
+
>>> list(dog.closure(hyp))
|
|
528
|
+
[Synset('canine.n.02'), Synset('domestic_animal.n.01'),
|
|
529
|
+
Synset('carnivore.n.01'), Synset('animal.n.01'),
|
|
530
|
+
Synset('placental.n.01'), Synset('organism.n.01'),
|
|
531
|
+
Synset('mammal.n.01'), Synset('living_thing.n.01'),
|
|
532
|
+
Synset('vertebrate.n.01'), Synset('whole.n.02'),
|
|
533
|
+
Synset('chordate.n.01'), Synset('object.n.01'),
|
|
534
|
+
Synset('physical_entity.n.01'), Synset('entity.n.01')]
|
|
535
|
+
|
|
536
|
+
"""
|
|
537
|
+
from nltk.util import breadth_first
|
|
538
|
+
synset_offsets = []
|
|
539
|
+
for synset in breadth_first(self, rel, depth):
|
|
540
|
+
if synset._offset != self._offset:
|
|
541
|
+
if synset._offset not in synset_offsets:
|
|
542
|
+
synset_offsets.append(synset._offset)
|
|
543
|
+
yield synset
|
|
544
|
+
|
|
545
|
+
def hypernym_paths(self):
|
|
546
|
+
"""
|
|
547
|
+
Get the path(s) from this synset to the root, where each path is a
|
|
548
|
+
list of the synset nodes traversed on the way to the root.
|
|
549
|
+
|
|
550
|
+
:return: A list of lists, where each list gives the node sequence
|
|
551
|
+
connecting the initial ``Synset`` node and a root node.
|
|
552
|
+
"""
|
|
553
|
+
paths = []
|
|
554
|
+
|
|
555
|
+
hypernyms = self.hypernyms() + self.instance_hypernyms()
|
|
556
|
+
if len(hypernyms) == 0:
|
|
557
|
+
paths = [[self]]
|
|
558
|
+
|
|
559
|
+
for hypernym in hypernyms:
|
|
560
|
+
for ancestor_list in hypernym.hypernym_paths():
|
|
561
|
+
ancestor_list.append(self)
|
|
562
|
+
paths.append(ancestor_list)
|
|
563
|
+
return paths
|
|
564
|
+
|
|
565
|
+
def common_hypernyms(self, other):
|
|
566
|
+
"""
|
|
567
|
+
Find all synsets that are hypernyms of this synset and the
|
|
568
|
+
other synset.
|
|
569
|
+
|
|
570
|
+
:type other: Synset
|
|
571
|
+
:param other: other input synset.
|
|
572
|
+
:return: The synsets that are hypernyms of both synsets.
|
|
573
|
+
"""
|
|
574
|
+
if not self._all_hypernyms:
|
|
575
|
+
self._all_hypernyms = set(
|
|
576
|
+
self_synset
|
|
577
|
+
for self_synsets in self._iter_hypernym_lists()
|
|
578
|
+
for self_synset in self_synsets
|
|
579
|
+
)
|
|
580
|
+
if not other._all_hypernyms:
|
|
581
|
+
other._all_hypernyms = set(
|
|
582
|
+
other_synset
|
|
583
|
+
for other_synsets in other._iter_hypernym_lists()
|
|
584
|
+
for other_synset in other_synsets
|
|
585
|
+
)
|
|
586
|
+
return list(self._all_hypernyms.intersection(other._all_hypernyms))
|
|
587
|
+
|
|
588
|
+
def lowest_common_hypernyms(
|
|
589
|
+
self, other, simulate_root=False, use_min_depth=False
|
|
590
|
+
):
|
|
591
|
+
"""
|
|
592
|
+
Get a list of lowest synset(s) that both synsets have as a hypernym.
|
|
593
|
+
When `use_min_depth == False` this means that the synset which appears
|
|
594
|
+
as a hypernym of both `self` and `other` with the lowest maximum depth
|
|
595
|
+
is returned or if there are multiple such synsets at the same depth
|
|
596
|
+
they are all returned
|
|
597
|
+
|
|
598
|
+
However, if `use_min_depth == True` then the synset(s) which has/have
|
|
599
|
+
the lowest minimum depth and appear(s) in both paths is/are returned.
|
|
600
|
+
|
|
601
|
+
By setting the use_min_depth flag to True, the behavior of NLTK2 can be
|
|
602
|
+
preserved. This was changed in NLTK3 to give more accurate results in a
|
|
603
|
+
small set of cases, generally with synsets concerning people. (eg:
|
|
604
|
+
'chef.n.01', 'fireman.n.01', etc.)
|
|
605
|
+
|
|
606
|
+
This method is an implementation of Ted Pedersen's "Lowest Common
|
|
607
|
+
Subsumer" method from the Perl Wordnet module. It can return either
|
|
608
|
+
"self" or "other" if they are a hypernym of the other.
|
|
609
|
+
|
|
610
|
+
:type other: Synset
|
|
611
|
+
:param other: other input synset
|
|
612
|
+
:type simulate_root: bool
|
|
613
|
+
:param simulate_root: The various verb taxonomies do not
|
|
614
|
+
share a single root which disallows this metric from working for
|
|
615
|
+
synsets that are not connected. This flag (False by default)
|
|
616
|
+
creates a fake root that connects all the taxonomies. Set it
|
|
617
|
+
to True to enable this behavior. For the noun taxonomy,
|
|
618
|
+
there is usually a default root except for WordNet version 1.6.
|
|
619
|
+
If you are using wordnet 1.6, a fake root will need to be added
|
|
620
|
+
for nouns as well.
|
|
621
|
+
:type use_min_depth: bool
|
|
622
|
+
:param use_min_depth: This setting mimics older (v2) behavior of NLTK
|
|
623
|
+
wordnet If True, will use the min_depth function to calculate the
|
|
624
|
+
lowest common hypernyms. This is known to give strange results for
|
|
625
|
+
some synset pairs (eg: 'chef.n.01', 'fireman.n.01') but is retained
|
|
626
|
+
for backwards compatibility
|
|
627
|
+
:return: The synsets that are the lowest common hypernyms of both
|
|
628
|
+
synsets
|
|
629
|
+
"""
|
|
630
|
+
synsets = self.common_hypernyms(other)
|
|
631
|
+
if simulate_root:
|
|
632
|
+
fake_synset = Synset(None)
|
|
633
|
+
fake_synset._name = '*ROOT*'
|
|
634
|
+
fake_synset.hypernyms = lambda: []
|
|
635
|
+
fake_synset.instance_hypernyms = lambda: []
|
|
636
|
+
synsets.append(fake_synset)
|
|
637
|
+
|
|
638
|
+
try:
|
|
639
|
+
if use_min_depth:
|
|
640
|
+
max_depth = max(s.min_depth() for s in synsets)
|
|
641
|
+
unsorted_lch = [
|
|
642
|
+
s for s in synsets if s.min_depth() == max_depth
|
|
643
|
+
]
|
|
644
|
+
else:
|
|
645
|
+
max_depth = max(s.max_depth() for s in synsets)
|
|
646
|
+
unsorted_lch = [
|
|
647
|
+
s for s in synsets if s.max_depth() == max_depth
|
|
648
|
+
]
|
|
649
|
+
return sorted(unsorted_lch)
|
|
650
|
+
except ValueError:
|
|
651
|
+
return []
|
|
652
|
+
|
|
653
|
+
def hypernym_distances(self, distance=0, simulate_root=False):
|
|
654
|
+
"""
|
|
655
|
+
Get the path(s) from this synset to the root, counting the distance
|
|
656
|
+
of each node from the initial node on the way. A set of
|
|
657
|
+
(synset, distance) tuples is returned.
|
|
658
|
+
|
|
659
|
+
:type distance: int
|
|
660
|
+
:param distance: the distance (number of edges) from this hypernym to
|
|
661
|
+
the original hypernym ``Synset`` on which this method was called.
|
|
662
|
+
:return: A set of ``(Synset, int)`` tuples where each ``Synset`` is
|
|
663
|
+
a hypernym of the first ``Synset``.
|
|
664
|
+
"""
|
|
665
|
+
distances = set([(self, distance)])
|
|
666
|
+
for hypernym in self._hypernyms() + self._instance_hypernyms():
|
|
667
|
+
distances |= hypernym.hypernym_distances(
|
|
668
|
+
distance+1,
|
|
669
|
+
simulate_root=False
|
|
670
|
+
)
|
|
671
|
+
if simulate_root:
|
|
672
|
+
fake_synset = Synset(None)
|
|
673
|
+
fake_synset._name = '*ROOT*'
|
|
674
|
+
fake_synset_distance = max(distances, key=itemgetter(1))[1]
|
|
675
|
+
distances.add((fake_synset, fake_synset_distance+1))
|
|
676
|
+
return distances
|
|
677
|
+
|
|
678
|
+
def _shortest_hypernym_paths(self, simulate_root):
|
|
679
|
+
if self._name == '*ROOT*':
|
|
680
|
+
return {self: 0}
|
|
681
|
+
|
|
682
|
+
queue = deque([(self, 0)])
|
|
683
|
+
path = {}
|
|
684
|
+
|
|
685
|
+
while queue:
|
|
686
|
+
s, depth = queue.popleft()
|
|
687
|
+
if s in path:
|
|
688
|
+
continue
|
|
689
|
+
path[s] = depth
|
|
690
|
+
|
|
691
|
+
depth += 1
|
|
692
|
+
queue.extend((hyp, depth) for hyp in s._hypernyms())
|
|
693
|
+
queue.extend((hyp, depth) for hyp in s._instance_hypernyms())
|
|
694
|
+
|
|
695
|
+
if simulate_root:
|
|
696
|
+
fake_synset = Synset(None)
|
|
697
|
+
fake_synset._name = '*ROOT*'
|
|
698
|
+
path[fake_synset] = max(path.values()) + 1
|
|
699
|
+
|
|
700
|
+
return path
|
|
701
|
+
|
|
702
|
+
def shortest_path_distance(self, other, simulate_root=False):
|
|
703
|
+
"""
|
|
704
|
+
Returns the distance of the shortest path linking the two synsets (if
|
|
705
|
+
one exists). For each synset, all the ancestor nodes and their
|
|
706
|
+
distances are recorded and compared. The ancestor node common to both
|
|
707
|
+
synsets that can be reached with the minimum number of traversals is
|
|
708
|
+
used. If no ancestor nodes are common, None is returned. If a node is
|
|
709
|
+
compared with itself 0 is returned.
|
|
710
|
+
|
|
711
|
+
:type other: Synset
|
|
712
|
+
:param other: The Synset to which the shortest path will be found.
|
|
713
|
+
:return: The number of edges in the shortest path connecting the two
|
|
714
|
+
nodes, or None if no path exists.
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
if self == other:
|
|
718
|
+
return 0
|
|
719
|
+
|
|
720
|
+
dist_dict1 = self._shortest_hypernym_paths(simulate_root)
|
|
721
|
+
dist_dict2 = other._shortest_hypernym_paths(simulate_root)
|
|
722
|
+
|
|
723
|
+
# For each ancestor synset common to both subject synsets, find the
|
|
724
|
+
# connecting path length. Return the shortest of these.
|
|
725
|
+
|
|
726
|
+
inf = float('inf')
|
|
727
|
+
path_distance = inf
|
|
728
|
+
for synset, d1 in iteritems(dist_dict1):
|
|
729
|
+
d2 = dist_dict2.get(synset, inf)
|
|
730
|
+
path_distance = min(path_distance, d1 + d2)
|
|
731
|
+
|
|
732
|
+
return None if math.isinf(path_distance) else path_distance
|
|
733
|
+
|
|
734
|
+
def tree(self, rel, depth=-1, cut_mark=None):
|
|
735
|
+
"""
|
|
736
|
+
>>> from nltk.corpus import wordnet as wn
|
|
737
|
+
>>> dog = wn.synset('dog.n.01')
|
|
738
|
+
>>> hyp = lambda s:s.hypernyms()
|
|
739
|
+
>>> from pprint import pprint
|
|
740
|
+
>>> pprint(dog.tree(hyp))
|
|
741
|
+
[Synset('dog.n.01'),
|
|
742
|
+
[Synset('canine.n.02'),
|
|
743
|
+
[Synset('carnivore.n.01'),
|
|
744
|
+
[Synset('placental.n.01'),
|
|
745
|
+
[Synset('mammal.n.01'),
|
|
746
|
+
[Synset('vertebrate.n.01'),
|
|
747
|
+
[Synset('chordate.n.01'),
|
|
748
|
+
[Synset('animal.n.01'),
|
|
749
|
+
[Synset('organism.n.01'),
|
|
750
|
+
[Synset('living_thing.n.01'),
|
|
751
|
+
[Synset('whole.n.02'),
|
|
752
|
+
[Synset('object.n.01'),
|
|
753
|
+
[Synset('physical_entity.n.01'),
|
|
754
|
+
[Synset('entity.n.01')]]]]]]]]]]]]],
|
|
755
|
+
[Synset('domestic_animal.n.01'),
|
|
756
|
+
[Synset('animal.n.01'),
|
|
757
|
+
[Synset('organism.n.01'),
|
|
758
|
+
[Synset('living_thing.n.01'),
|
|
759
|
+
[Synset('whole.n.02'),
|
|
760
|
+
[Synset('object.n.01'),
|
|
761
|
+
[Synset('physical_entity.n.01'), [Synset('entity.n.01')]]]]]]]]]
|
|
762
|
+
"""
|
|
763
|
+
|
|
764
|
+
tree = [self]
|
|
765
|
+
if depth != 0:
|
|
766
|
+
tree += [x.tree(rel, depth-1, cut_mark) for x in rel(self)]
|
|
767
|
+
elif cut_mark:
|
|
768
|
+
tree += [cut_mark]
|
|
769
|
+
return tree
|
|
770
|
+
|
|
771
|
+
# interface to similarity methods
|
|
772
|
+
def path_similarity(self, other, verbose=False, simulate_root=True):
|
|
773
|
+
"""
|
|
774
|
+
Path Distance Similarity:
|
|
775
|
+
Return a score denoting how similar two word senses are, based on the
|
|
776
|
+
shortest path that connects the senses in the is-a (hypernym/hypnoym)
|
|
777
|
+
taxonomy. The score is in the range 0 to 1, except in those cases where
|
|
778
|
+
a path cannot be found (will only be true for verbs as there are many
|
|
779
|
+
distinct verb taxonomies), in which case None is returned. A score of
|
|
780
|
+
1 represents identity i.e. comparing a sense with itself will return 1.
|
|
781
|
+
|
|
782
|
+
:type other: Synset
|
|
783
|
+
:param other: The ``Synset`` that this ``Synset`` is being compared to.
|
|
784
|
+
:type simulate_root: bool
|
|
785
|
+
:param simulate_root: The various verb taxonomies do not
|
|
786
|
+
share a single root which disallows this metric from working for
|
|
787
|
+
synsets that are not connected. This flag (True by default)
|
|
788
|
+
creates a fake root that connects all the taxonomies. Set it
|
|
789
|
+
to false to disable this behavior. For the noun taxonomy,
|
|
790
|
+
there is usually a default root except for WordNet version 1.6.
|
|
791
|
+
If you are using wordnet 1.6, a fake root will be added for nouns
|
|
792
|
+
as well.
|
|
793
|
+
:return: A score denoting the similarity of the two ``Synset`` objects,
|
|
794
|
+
normally between 0 and 1. None is returned if no connecting path
|
|
795
|
+
could be found. 1 is returned if a ``Synset`` is compared with
|
|
796
|
+
itself.
|
|
797
|
+
"""
|
|
798
|
+
|
|
799
|
+
distance = self.shortest_path_distance(
|
|
800
|
+
other,
|
|
801
|
+
simulate_root=simulate_root and self._needs_root()
|
|
802
|
+
)
|
|
803
|
+
if distance is None or distance < 0:
|
|
804
|
+
return None
|
|
805
|
+
return 1.0 / (distance + 1)
|
|
806
|
+
|
|
807
|
+
def lch_similarity(self, other, verbose=False, simulate_root=True):
|
|
808
|
+
"""
|
|
809
|
+
Leacock Chodorow Similarity:
|
|
810
|
+
Return a score denoting how similar two word senses are, based on the
|
|
811
|
+
shortest path that connects the senses (as above) and the maximum depth
|
|
812
|
+
of the taxonomy in which the senses occur. The relationship is given as
|
|
813
|
+
-log(p/2d) where p is the shortest path length and d is the taxonomy
|
|
814
|
+
depth.
|
|
815
|
+
|
|
816
|
+
:type other: Synset
|
|
817
|
+
:param other: The ``Synset`` that this ``Synset`` is being compared to.
|
|
818
|
+
:type simulate_root: bool
|
|
819
|
+
:param simulate_root: The various verb taxonomies do not
|
|
820
|
+
share a single root which disallows this metric from working for
|
|
821
|
+
synsets that are not connected. This flag (True by default)
|
|
822
|
+
creates a fake root that connects all the taxonomies. Set it
|
|
823
|
+
to false to disable this behavior. For the noun taxonomy,
|
|
824
|
+
there is usually a default root except for WordNet version 1.6.
|
|
825
|
+
If you are using wordnet 1.6, a fake root will be added for nouns
|
|
826
|
+
as well.
|
|
827
|
+
:return: A score denoting the similarity of the two ``Synset`` objects,
|
|
828
|
+
normally greater than 0. None is returned if no connecting path
|
|
829
|
+
could be found. If a ``Synset`` is compared with itself, the
|
|
830
|
+
maximum score is returned, which varies depending on the taxonomy
|
|
831
|
+
depth.
|
|
832
|
+
"""
|
|
833
|
+
|
|
834
|
+
if self._pos != other._pos:
|
|
835
|
+
raise WordNetError(
|
|
836
|
+
'Computing the lch similarity requires '
|
|
837
|
+
'%s and %s to have the same part of speech.' %
|
|
838
|
+
(self, other)
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
need_root = self._needs_root()
|
|
842
|
+
|
|
843
|
+
if self._pos not in self._wordnet_corpus_reader._max_depth:
|
|
844
|
+
self._wordnet_corpus_reader._compute_max_depth(
|
|
845
|
+
self._pos, need_root
|
|
846
|
+
)
|
|
847
|
+
|
|
848
|
+
depth = self._wordnet_corpus_reader._max_depth[self._pos]
|
|
849
|
+
|
|
850
|
+
distance = self.shortest_path_distance(
|
|
851
|
+
other,
|
|
852
|
+
simulate_root=simulate_root and need_root
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
if distance is None or distance < 0 or depth == 0:
|
|
856
|
+
return None
|
|
857
|
+
return -math.log((distance + 1) / (2.0 * depth))
|
|
858
|
+
|
|
859
|
+
def wup_similarity(self, other, verbose=False, simulate_root=True):
|
|
860
|
+
"""
|
|
861
|
+
Wu-Palmer Similarity:
|
|
862
|
+
Return a score denoting how similar two word senses are, based on the
|
|
863
|
+
depth of the two senses in the taxonomy and that of their Least Common
|
|
864
|
+
Subsumer (most specific ancestor node). Previously, the scores computed
|
|
865
|
+
by this implementation did _not_ always agree with those given by
|
|
866
|
+
Pedersen's Perl implementation of WordNet Similarity. However, with
|
|
867
|
+
the addition of the simulate_root flag (see below), the score for
|
|
868
|
+
verbs now almost always agree but not always for nouns.
|
|
869
|
+
|
|
870
|
+
The LCS does not necessarily feature in the shortest path connecting
|
|
871
|
+
the two senses, as it is by definition the common ancestor deepest in
|
|
872
|
+
the taxonomy, not closest to the two senses. Typically, however, it
|
|
873
|
+
will so feature. Where multiple candidates for the LCS exist, that
|
|
874
|
+
whose shortest path to the root node is the longest will be selected.
|
|
875
|
+
Where the LCS has multiple paths to the root, the longer path is used
|
|
876
|
+
for the purposes of the calculation.
|
|
877
|
+
|
|
878
|
+
:type other: Synset
|
|
879
|
+
:param other: The ``Synset`` that this ``Synset`` is being compared to.
|
|
880
|
+
:type simulate_root: bool
|
|
881
|
+
:param simulate_root: The various verb taxonomies do not
|
|
882
|
+
share a single root which disallows this metric from working for
|
|
883
|
+
synsets that are not connected. This flag (True by default)
|
|
884
|
+
creates a fake root that connects all the taxonomies. Set it
|
|
885
|
+
to false to disable this behavior. For the noun taxonomy,
|
|
886
|
+
there is usually a default root except for WordNet version 1.6.
|
|
887
|
+
If you are using wordnet 1.6, a fake root will be added for nouns
|
|
888
|
+
as well.
|
|
889
|
+
:return: A float score denoting the similarity of the two ``Synset``
|
|
890
|
+
objects, normally greater than zero. If no connecting path between
|
|
891
|
+
the two senses can be found, None is returned.
|
|
892
|
+
|
|
893
|
+
"""
|
|
894
|
+
|
|
895
|
+
need_root = self._needs_root()
|
|
896
|
+
# Note that to preserve behavior from NLTK2 we set use_min_depth=True
|
|
897
|
+
# It is possible that more accurate results could be obtained by
|
|
898
|
+
# removing this setting and it should be tested later on
|
|
899
|
+
subsumers = self.lowest_common_hypernyms(
|
|
900
|
+
other,
|
|
901
|
+
simulate_root=simulate_root and need_root, use_min_depth=True
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
# If no LCS was found return None
|
|
905
|
+
if len(subsumers) == 0:
|
|
906
|
+
return None
|
|
907
|
+
|
|
908
|
+
subsumer = self if self in subsumers else subsumers[0]
|
|
909
|
+
|
|
910
|
+
# Get the longest path from the LCS to the root,
|
|
911
|
+
# including a correction:
|
|
912
|
+
# - add one because the calculations include both the start and end
|
|
913
|
+
# nodes
|
|
914
|
+
depth = subsumer.max_depth() + 1
|
|
915
|
+
|
|
916
|
+
# Note: No need for an additional add-one correction for non-nouns
|
|
917
|
+
# to account for an imaginary root node because that is now
|
|
918
|
+
# automatically handled by simulate_root
|
|
919
|
+
# if subsumer._pos != NOUN:
|
|
920
|
+
# depth += 1
|
|
921
|
+
|
|
922
|
+
# Get the shortest path from the LCS to each of the synsets it is
|
|
923
|
+
# subsuming. Add this to the LCS path length to get the path
|
|
924
|
+
# length from each synset to the root.
|
|
925
|
+
len1 = self.shortest_path_distance(
|
|
926
|
+
subsumer,
|
|
927
|
+
simulate_root=simulate_root and need_root
|
|
928
|
+
)
|
|
929
|
+
len2 = other.shortest_path_distance(
|
|
930
|
+
subsumer,
|
|
931
|
+
simulate_root=simulate_root and need_root
|
|
932
|
+
)
|
|
933
|
+
if len1 is None or len2 is None:
|
|
934
|
+
return None
|
|
935
|
+
len1 += depth
|
|
936
|
+
len2 += depth
|
|
937
|
+
return (2.0 * depth) / (len1 + len2)
|
|
938
|
+
|
|
939
|
+
def res_similarity(self, other, ic, verbose=False):
|
|
940
|
+
"""
|
|
941
|
+
Resnik Similarity:
|
|
942
|
+
Return a score denoting how similar two word senses are, based on the
|
|
943
|
+
Information Content (IC) of the Least Common Subsumer (most specific
|
|
944
|
+
ancestor node).
|
|
945
|
+
|
|
946
|
+
:type other: Synset
|
|
947
|
+
:param other: The ``Synset`` that this ``Synset`` is being compared to.
|
|
948
|
+
:type ic: dict
|
|
949
|
+
:param ic: an information content object (as returned by
|
|
950
|
+
``nltk.corpus.wordnet_ic.ic()``).
|
|
951
|
+
:return: A float score denoting the similarity of the two ``Synset``
|
|
952
|
+
objects. Synsets whose LCS is the root node of the taxonomy will
|
|
953
|
+
have a score of 0 (e.g. N['dog'][0] and N['table'][0]).
|
|
954
|
+
"""
|
|
955
|
+
|
|
956
|
+
ic1, ic2, lcs_ic = _lcs_ic(self, other, ic)
|
|
957
|
+
return lcs_ic
|
|
958
|
+
|
|
959
|
+
def jcn_similarity(self, other, ic, verbose=False):
|
|
960
|
+
"""
|
|
961
|
+
Jiang-Conrath Similarity:
|
|
962
|
+
Return a score denoting how similar two word senses are, based on the
|
|
963
|
+
Information Content (IC) of the Least Common Subsumer (most specific
|
|
964
|
+
ancestor node) and that of the two input Synsets. The relationship is
|
|
965
|
+
given by the equation 1 / (IC(s1) + IC(s2) - 2 * IC(lcs)).
|
|
966
|
+
|
|
967
|
+
:type other: Synset
|
|
968
|
+
:param other: The ``Synset`` that this ``Synset`` is being compared to.
|
|
969
|
+
:type ic: dict
|
|
970
|
+
:param ic: an information content object (as returned by
|
|
971
|
+
``nltk.corpus.wordnet_ic.ic()``).
|
|
972
|
+
:return: A float score denoting the similarity of the two ``Synset``
|
|
973
|
+
objects.
|
|
974
|
+
"""
|
|
975
|
+
|
|
976
|
+
if self == other:
|
|
977
|
+
return _INF
|
|
978
|
+
|
|
979
|
+
ic1, ic2, lcs_ic = _lcs_ic(self, other, ic)
|
|
980
|
+
|
|
981
|
+
# If either of the input synsets are the root synset, or have a
|
|
982
|
+
# frequency of 0 (sparse data problem), return 0.
|
|
983
|
+
if ic1 == 0 or ic2 == 0:
|
|
984
|
+
return 0
|
|
985
|
+
|
|
986
|
+
ic_difference = ic1 + ic2 - 2 * lcs_ic
|
|
987
|
+
|
|
988
|
+
if ic_difference == 0:
|
|
989
|
+
return _INF
|
|
990
|
+
|
|
991
|
+
return 1 / ic_difference
|
|
992
|
+
|
|
993
|
+
def lin_similarity(self, other, ic, verbose=False):
|
|
994
|
+
"""
|
|
995
|
+
Lin Similarity:
|
|
996
|
+
Return a score denoting how similar two word senses are, based on the
|
|
997
|
+
Information Content (IC) of the Least Common Subsumer (most specific
|
|
998
|
+
ancestor node) and that of the two input Synsets. The relationship is
|
|
999
|
+
given by the equation 2 * IC(lcs) / (IC(s1) + IC(s2)).
|
|
1000
|
+
|
|
1001
|
+
:type other: Synset
|
|
1002
|
+
:param other: The ``Synset`` that this ``Synset`` is being compared to.
|
|
1003
|
+
:type ic: dict
|
|
1004
|
+
:param ic: an information content object (as returned by
|
|
1005
|
+
``nltk.corpus.wordnet_ic.ic()``).
|
|
1006
|
+
:return: A float score denoting the similarity of the two ``Synset``
|
|
1007
|
+
objects, in the range 0 to 1.
|
|
1008
|
+
"""
|
|
1009
|
+
|
|
1010
|
+
ic1, ic2, lcs_ic = _lcs_ic(self, other, ic)
|
|
1011
|
+
return (2.0 * lcs_ic) / (ic1 + ic2)
|
|
1012
|
+
|
|
1013
|
+
def _iter_hypernym_lists(self):
|
|
1014
|
+
"""
|
|
1015
|
+
:return: An iterator over ``Synset`` objects that are either proper
|
|
1016
|
+
hypernyms or instance of hypernyms of the synset.
|
|
1017
|
+
"""
|
|
1018
|
+
todo = [self]
|
|
1019
|
+
seen = set()
|
|
1020
|
+
while todo:
|
|
1021
|
+
for synset in todo:
|
|
1022
|
+
seen.add(synset)
|
|
1023
|
+
yield todo
|
|
1024
|
+
todo = [hypernym
|
|
1025
|
+
for synset in todo
|
|
1026
|
+
for hypernym in (
|
|
1027
|
+
synset.hypernyms() + synset.instance_hypernyms()
|
|
1028
|
+
)
|
|
1029
|
+
if hypernym not in seen]
|
|
1030
|
+
|
|
1031
|
+
def __repr__(self):
|
|
1032
|
+
return "%s('%s')" % (type(self).__name__, self._name)
|
|
1033
|
+
|
|
1034
|
+
def _related(self, relation_symbol, sort=True):
|
|
1035
|
+
get_synset = self._wordnet_corpus_reader.synset_from_pos_and_offset
|
|
1036
|
+
pointer_tuples = self._pointers[relation_symbol]
|
|
1037
|
+
r = [get_synset(pos, offset) for pos, offset in pointer_tuples]
|
|
1038
|
+
if sort:
|
|
1039
|
+
r.sort()
|
|
1040
|
+
return r
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
######################################################################
|
|
1044
|
+
# WordNet Corpus Reader
|
|
1045
|
+
######################################################################
|
|
1046
|
+
|
|
1047
|
+
class WordNetCorpusReader(CorpusReader):
|
|
1048
|
+
"""
|
|
1049
|
+
A corpus reader used to access wordnet or its variants.
|
|
1050
|
+
"""
|
|
1051
|
+
|
|
1052
|
+
_ENCODING = 'utf8'
|
|
1053
|
+
|
|
1054
|
+
# { Part-of-speech constants
|
|
1055
|
+
ADJ, ADJ_SAT, ADV, NOUN, VERB = 'a', 's', 'r', 'n', 'v'
|
|
1056
|
+
# }
|
|
1057
|
+
|
|
1058
|
+
# { Filename constants
|
|
1059
|
+
_FILEMAP = {ADJ: 'adj', ADV: 'adv', NOUN: 'noun', VERB: 'verb'}
|
|
1060
|
+
# }
|
|
1061
|
+
|
|
1062
|
+
# { Part of speech constants
|
|
1063
|
+
_pos_numbers = {NOUN: 1, VERB: 2, ADJ: 3, ADV: 4, ADJ_SAT: 5}
|
|
1064
|
+
_pos_names = dict(tup[::-1] for tup in _pos_numbers.items())
|
|
1065
|
+
# }
|
|
1066
|
+
|
|
1067
|
+
#: A list of file identifiers for all the fileids used by this
|
|
1068
|
+
#: corpus reader.
|
|
1069
|
+
_FILES = ('cntlist.rev', 'lexnames', 'index.sense',
|
|
1070
|
+
'index.adj', 'index.adv', 'index.noun', 'index.verb',
|
|
1071
|
+
'data.adj', 'data.adv', 'data.noun', 'data.verb',
|
|
1072
|
+
'adj.exc', 'adv.exc', 'noun.exc', 'verb.exc', )
|
|
1073
|
+
|
|
1074
|
+
def __init__(self, root, omw_reader):
|
|
1075
|
+
"""
|
|
1076
|
+
Construct a new wordnet corpus reader, with the given root
|
|
1077
|
+
directory.
|
|
1078
|
+
"""
|
|
1079
|
+
super(WordNetCorpusReader, self).__init__(root, self._FILES,
|
|
1080
|
+
encoding=self._ENCODING)
|
|
1081
|
+
|
|
1082
|
+
# A index that provides the file offset
|
|
1083
|
+
# Map from lemma -> pos -> synset_index -> offset
|
|
1084
|
+
self._lemma_pos_offset_map = defaultdict(dict)
|
|
1085
|
+
|
|
1086
|
+
# A cache so we don't have to reconstuct synsets
|
|
1087
|
+
# Map from pos -> offset -> synset
|
|
1088
|
+
self._synset_offset_cache = defaultdict(dict)
|
|
1089
|
+
|
|
1090
|
+
# A lookup for the maximum depth of each part of speech. Useful for
|
|
1091
|
+
# the lch similarity metric.
|
|
1092
|
+
self._max_depth = defaultdict(dict)
|
|
1093
|
+
|
|
1094
|
+
# Corpus reader containing omw data.
|
|
1095
|
+
self._omw_reader = omw_reader
|
|
1096
|
+
|
|
1097
|
+
# A cache to store the wordnet data of multiple languages
|
|
1098
|
+
self._lang_data = defaultdict(list)
|
|
1099
|
+
|
|
1100
|
+
self._data_file_map = {}
|
|
1101
|
+
self._exception_map = {}
|
|
1102
|
+
self._lexnames = []
|
|
1103
|
+
self._key_count_file = None
|
|
1104
|
+
self._key_synset_file = None
|
|
1105
|
+
|
|
1106
|
+
# Load the lexnames
|
|
1107
|
+
for i, line in enumerate(self.open('lexnames')):
|
|
1108
|
+
index, lexname, _ = line.split()
|
|
1109
|
+
assert int(index) == i
|
|
1110
|
+
self._lexnames.append(lexname)
|
|
1111
|
+
|
|
1112
|
+
# Load the indices for lemmas and synset offsets
|
|
1113
|
+
self._load_lemma_pos_offset_map()
|
|
1114
|
+
|
|
1115
|
+
# load the exception file data into memory
|
|
1116
|
+
self._load_exception_map()
|
|
1117
|
+
|
|
1118
|
+
# Open Multilingual WordNet functions, contributed by
|
|
1119
|
+
# Nasruddin A’aidil Shari, Sim Wei Ying Geraldine, and Soe Lynn
|
|
1120
|
+
|
|
1121
|
+
def of2ss(self, of):
|
|
1122
|
+
''' take an id and return the synsets '''
|
|
1123
|
+
return self.synset_from_pos_and_offset(of[-1], int(of[:8]))
|
|
1124
|
+
|
|
1125
|
+
def ss2of(self, ss):
|
|
1126
|
+
''' return the ID of the synset '''
|
|
1127
|
+
return ("{:08d}-{}".format(ss.offset(), ss.pos()))
|
|
1128
|
+
|
|
1129
|
+
def _load_lang_data(self, lang):
|
|
1130
|
+
''' load the wordnet data of the requested language from the file to
|
|
1131
|
+
the cache, _lang_data '''
|
|
1132
|
+
|
|
1133
|
+
if lang in self._lang_data.keys():
|
|
1134
|
+
return
|
|
1135
|
+
|
|
1136
|
+
if lang not in self.langs():
|
|
1137
|
+
raise WordNetError("Language is not supported.")
|
|
1138
|
+
|
|
1139
|
+
f = self._omw_reader.open('{0:}/wn-data-{0:}.tab'.format(lang))
|
|
1140
|
+
self.custom_lemmas(f, lang)
|
|
1141
|
+
f.close()
|
|
1142
|
+
|
|
1143
|
+
def langs(self):
|
|
1144
|
+
''' return a list of languages supported by Multilingual Wordnet '''
|
|
1145
|
+
import os
|
|
1146
|
+
langs = ['eng']
|
|
1147
|
+
fileids = self._omw_reader.fileids()
|
|
1148
|
+
for fileid in fileids:
|
|
1149
|
+
file_name, file_extension = os.path.splitext(fileid)
|
|
1150
|
+
if file_extension == '.tab':
|
|
1151
|
+
langs.append(file_name.split('-')[-1])
|
|
1152
|
+
|
|
1153
|
+
return langs
|
|
1154
|
+
|
|
1155
|
+
def _load_lemma_pos_offset_map(self):
|
|
1156
|
+
for suffix in self._FILEMAP.values():
|
|
1157
|
+
|
|
1158
|
+
# parse each line of the file (ignoring comment lines)
|
|
1159
|
+
for i, line in enumerate(self.open('index.%s' % suffix)):
|
|
1160
|
+
if line.startswith(' '):
|
|
1161
|
+
continue
|
|
1162
|
+
|
|
1163
|
+
_iter = iter(line.split())
|
|
1164
|
+
|
|
1165
|
+
def _next_token(): return next(_iter)
|
|
1166
|
+
|
|
1167
|
+
try:
|
|
1168
|
+
|
|
1169
|
+
# get the lemma and part-of-speech
|
|
1170
|
+
lemma = _next_token()
|
|
1171
|
+
pos = _next_token()
|
|
1172
|
+
|
|
1173
|
+
# get the number of synsets for this lemma
|
|
1174
|
+
n_synsets = int(_next_token())
|
|
1175
|
+
assert n_synsets > 0
|
|
1176
|
+
|
|
1177
|
+
# get and ignore the pointer symbols for all synsets of
|
|
1178
|
+
# this lemma
|
|
1179
|
+
n_pointers = int(_next_token())
|
|
1180
|
+
[_next_token() for _ in range(n_pointers)]
|
|
1181
|
+
|
|
1182
|
+
# same as number of synsets
|
|
1183
|
+
n_senses = int(_next_token())
|
|
1184
|
+
assert n_synsets == n_senses
|
|
1185
|
+
|
|
1186
|
+
# get and ignore number of senses ranked according to
|
|
1187
|
+
# frequency
|
|
1188
|
+
_next_token()
|
|
1189
|
+
|
|
1190
|
+
# get synset offsets
|
|
1191
|
+
synset_offsets = [
|
|
1192
|
+
int(_next_token()) for _ in range(n_synsets)
|
|
1193
|
+
]
|
|
1194
|
+
|
|
1195
|
+
# raise more informative error with file name and line number
|
|
1196
|
+
except (AssertionError, ValueError) as e:
|
|
1197
|
+
tup = ('index.%s' % suffix), (i + 1), e
|
|
1198
|
+
raise WordNetError('file %s, line %i: %s' % tup)
|
|
1199
|
+
|
|
1200
|
+
# map lemmas and parts of speech to synsets
|
|
1201
|
+
self._lemma_pos_offset_map[lemma][pos] = synset_offsets
|
|
1202
|
+
if pos == ADJ:
|
|
1203
|
+
self._lemma_pos_offset_map[lemma][ADJ_SAT] = synset_offsets
|
|
1204
|
+
|
|
1205
|
+
def _load_exception_map(self):
|
|
1206
|
+
# load the exception file data into memory
|
|
1207
|
+
for pos, suffix in self._FILEMAP.items():
|
|
1208
|
+
self._exception_map[pos] = {}
|
|
1209
|
+
for line in self.open('%s.exc' % suffix):
|
|
1210
|
+
terms = line.split()
|
|
1211
|
+
self._exception_map[pos][terms[0]] = terms[1:]
|
|
1212
|
+
self._exception_map[ADJ_SAT] = self._exception_map[ADJ]
|
|
1213
|
+
|
|
1214
|
+
def _compute_max_depth(self, pos, simulate_root):
|
|
1215
|
+
"""
|
|
1216
|
+
Compute the max depth for the given part of speech. This is
|
|
1217
|
+
used by the lch similarity metric.
|
|
1218
|
+
"""
|
|
1219
|
+
depth = 0
|
|
1220
|
+
for ii in self.all_synsets(pos):
|
|
1221
|
+
try:
|
|
1222
|
+
depth = max(depth, ii.max_depth())
|
|
1223
|
+
except RuntimeError:
|
|
1224
|
+
print(ii)
|
|
1225
|
+
if simulate_root:
|
|
1226
|
+
depth += 1
|
|
1227
|
+
self._max_depth[pos] = depth
|
|
1228
|
+
|
|
1229
|
+
def get_version(self):
|
|
1230
|
+
fh = self._data_file(ADJ)
|
|
1231
|
+
for line in fh:
|
|
1232
|
+
match = re.search(r'WordNet (\d+\.\d+) Copyright', line)
|
|
1233
|
+
if match is not None:
|
|
1234
|
+
version = match.group(1)
|
|
1235
|
+
fh.seek(0)
|
|
1236
|
+
return version
|
|
1237
|
+
|
|
1238
|
+
#############################################################
|
|
1239
|
+
# Loading Lemmas
|
|
1240
|
+
#############################################################
|
|
1241
|
+
|
|
1242
|
+
def lemma(self, name, lang='eng'):
|
|
1243
|
+
'''Return lemma object that matches the name'''
|
|
1244
|
+
# cannot simply split on first '.',
|
|
1245
|
+
# e.g.: '.45_caliber.a.01..45_caliber'
|
|
1246
|
+
separator = SENSENUM_RE.search(name).start()
|
|
1247
|
+
|
|
1248
|
+
leadingZero = int(name[separator+1]) == 0
|
|
1249
|
+
if (leadingZero):
|
|
1250
|
+
synset_name, lemma_name = name[:separator+3], name[separator+4:]
|
|
1251
|
+
else:
|
|
1252
|
+
synset_name, lemma_name = name[:separator+2], name[separator+3:]
|
|
1253
|
+
|
|
1254
|
+
synset = self.synset(synset_name)
|
|
1255
|
+
for lemma in synset.lemmas(lang):
|
|
1256
|
+
if lemma._name == lemma_name:
|
|
1257
|
+
return lemma
|
|
1258
|
+
raise WordNetError('no lemma %r in %r' % (lemma_name, synset_name))
|
|
1259
|
+
|
|
1260
|
+
def lemma_from_key(self, key):
|
|
1261
|
+
# Keys are case sensitive and always lower-case
|
|
1262
|
+
key = key.lower()
|
|
1263
|
+
|
|
1264
|
+
lemma_name, lex_sense = key.split('%')
|
|
1265
|
+
pos_number, lexname_index, lex_id, _, _ = lex_sense.split(':')
|
|
1266
|
+
pos = self._pos_names[int(pos_number)]
|
|
1267
|
+
|
|
1268
|
+
# open the key -> synset file if necessary
|
|
1269
|
+
if self._key_synset_file is None:
|
|
1270
|
+
self._key_synset_file = self.open('index.sense')
|
|
1271
|
+
|
|
1272
|
+
# Find the synset for the lemma.
|
|
1273
|
+
synset_line = _binary_search_file(self._key_synset_file, key)
|
|
1274
|
+
if not synset_line:
|
|
1275
|
+
raise WordNetError("No synset found for key %r" % key)
|
|
1276
|
+
offset = int(synset_line.split()[1])
|
|
1277
|
+
synset = self.synset_from_pos_and_offset(pos, offset)
|
|
1278
|
+
|
|
1279
|
+
# return the corresponding lemma
|
|
1280
|
+
for lemma in synset._lemmas:
|
|
1281
|
+
if lemma._key == key:
|
|
1282
|
+
return lemma
|
|
1283
|
+
raise WordNetError("No lemma found for for key %r" % key)
|
|
1284
|
+
|
|
1285
|
+
#############################################################
|
|
1286
|
+
# Loading Synsets
|
|
1287
|
+
#############################################################
|
|
1288
|
+
def synset(self, name):
|
|
1289
|
+
# split name into lemma, part of speech and synset number
|
|
1290
|
+
lemma, pos, synset_index_str = name.lower().rsplit('.', 2)
|
|
1291
|
+
synset_index = int(synset_index_str) - 1
|
|
1292
|
+
|
|
1293
|
+
# get the offset for this synset
|
|
1294
|
+
try:
|
|
1295
|
+
offset = self._lemma_pos_offset_map[lemma][pos][synset_index]
|
|
1296
|
+
except KeyError:
|
|
1297
|
+
message = 'no lemma %r with part of speech %r'
|
|
1298
|
+
raise WordNetError(message % (lemma, pos))
|
|
1299
|
+
except IndexError:
|
|
1300
|
+
n_senses = len(self._lemma_pos_offset_map[lemma][pos])
|
|
1301
|
+
message = "lemma %r with part of speech %r has only %i %s"
|
|
1302
|
+
if n_senses == 1:
|
|
1303
|
+
tup = lemma, pos, n_senses, "sense"
|
|
1304
|
+
else:
|
|
1305
|
+
tup = lemma, pos, n_senses, "senses"
|
|
1306
|
+
raise WordNetError(message % tup)
|
|
1307
|
+
|
|
1308
|
+
# load synset information from the appropriate file
|
|
1309
|
+
synset = self.synset_from_pos_and_offset(pos, offset)
|
|
1310
|
+
|
|
1311
|
+
# some basic sanity checks on loaded attributes
|
|
1312
|
+
if pos == 's' and synset._pos == 'a':
|
|
1313
|
+
message = ('adjective satellite requested but only plain '
|
|
1314
|
+
'adjective found for lemma %r')
|
|
1315
|
+
raise WordNetError(message % lemma)
|
|
1316
|
+
assert synset._pos == pos or (pos == 'a' and synset._pos == 's')
|
|
1317
|
+
|
|
1318
|
+
# Return the synset object.
|
|
1319
|
+
return synset
|
|
1320
|
+
|
|
1321
|
+
def _data_file(self, pos):
|
|
1322
|
+
"""
|
|
1323
|
+
Return an open file pointer for the data file for the given
|
|
1324
|
+
part of speech.
|
|
1325
|
+
"""
|
|
1326
|
+
if pos == ADJ_SAT:
|
|
1327
|
+
pos = ADJ
|
|
1328
|
+
if self._data_file_map.get(pos) is None:
|
|
1329
|
+
fileid = 'data.%s' % self._FILEMAP[pos]
|
|
1330
|
+
self._data_file_map[pos] = self.open(fileid)
|
|
1331
|
+
return self._data_file_map[pos]
|
|
1332
|
+
|
|
1333
|
+
def synset_from_pos_and_offset(self, pos, offset):
|
|
1334
|
+
# Check to see if the synset is in the cache
|
|
1335
|
+
if offset in self._synset_offset_cache[pos]:
|
|
1336
|
+
return self._synset_offset_cache[pos][offset]
|
|
1337
|
+
|
|
1338
|
+
data_file = self._data_file(pos)
|
|
1339
|
+
data_file.seek(offset)
|
|
1340
|
+
data_file_line = data_file.readline()
|
|
1341
|
+
synset = self._synset_from_pos_and_line(pos, data_file_line)
|
|
1342
|
+
assert synset._offset == offset
|
|
1343
|
+
self._synset_offset_cache[pos][offset] = synset
|
|
1344
|
+
return synset
|
|
1345
|
+
|
|
1346
|
+
@deprecated('Use public method synset_from_pos_and_offset() instead')
|
|
1347
|
+
def _synset_from_pos_and_offset(self, *args, **kwargs):
|
|
1348
|
+
"""
|
|
1349
|
+
Hack to help people like the readers of
|
|
1350
|
+
http://stackoverflow.com/a/27145655/1709587
|
|
1351
|
+
who were using this function before it was officially a public method
|
|
1352
|
+
"""
|
|
1353
|
+
return self.synset_from_pos_and_offset(*args, **kwargs)
|
|
1354
|
+
|
|
1355
|
+
def _synset_from_pos_and_line(self, pos, data_file_line):
|
|
1356
|
+
# Construct a new (empty) synset.
|
|
1357
|
+
synset = Synset(self)
|
|
1358
|
+
|
|
1359
|
+
# parse the entry for this synset
|
|
1360
|
+
try:
|
|
1361
|
+
|
|
1362
|
+
# parse out the definitions and examples from the gloss
|
|
1363
|
+
columns_str, gloss = data_file_line.split('|')
|
|
1364
|
+
gloss = gloss.strip()
|
|
1365
|
+
definitions = []
|
|
1366
|
+
for gloss_part in gloss.split(';'):
|
|
1367
|
+
gloss_part = gloss_part.strip()
|
|
1368
|
+
if gloss_part.startswith('"'):
|
|
1369
|
+
synset._examples.append(gloss_part.strip('"'))
|
|
1370
|
+
else:
|
|
1371
|
+
definitions.append(gloss_part)
|
|
1372
|
+
synset._definition = '; '.join(definitions)
|
|
1373
|
+
|
|
1374
|
+
# split the other info into fields
|
|
1375
|
+
_iter = iter(columns_str.split())
|
|
1376
|
+
|
|
1377
|
+
def _next_token(): return next(_iter)
|
|
1378
|
+
|
|
1379
|
+
# get the offset
|
|
1380
|
+
synset._offset = int(_next_token())
|
|
1381
|
+
|
|
1382
|
+
# determine the lexicographer file name
|
|
1383
|
+
lexname_index = int(_next_token())
|
|
1384
|
+
synset._lexname = self._lexnames[lexname_index]
|
|
1385
|
+
|
|
1386
|
+
# get the part of speech
|
|
1387
|
+
synset._pos = _next_token()
|
|
1388
|
+
|
|
1389
|
+
# create Lemma objects for each lemma
|
|
1390
|
+
n_lemmas = int(_next_token(), 16)
|
|
1391
|
+
for _ in range(n_lemmas):
|
|
1392
|
+
# get the lemma name
|
|
1393
|
+
lemma_name = _next_token()
|
|
1394
|
+
# get the lex_id (used for sense_keys)
|
|
1395
|
+
lex_id = int(_next_token(), 16)
|
|
1396
|
+
# If the lemma has a syntactic marker, extract it.
|
|
1397
|
+
m = re.match(r'(.*?)(\(.*\))?$', lemma_name)
|
|
1398
|
+
lemma_name, syn_mark = m.groups()
|
|
1399
|
+
# create the lemma object
|
|
1400
|
+
lemma = Lemma(self, synset, lemma_name, lexname_index,
|
|
1401
|
+
lex_id, syn_mark)
|
|
1402
|
+
synset._lemmas.append(lemma)
|
|
1403
|
+
synset._lemma_names.append(lemma._name)
|
|
1404
|
+
|
|
1405
|
+
# collect the pointer tuples
|
|
1406
|
+
n_pointers = int(_next_token())
|
|
1407
|
+
for _ in range(n_pointers):
|
|
1408
|
+
symbol = _next_token()
|
|
1409
|
+
offset = int(_next_token())
|
|
1410
|
+
pos = _next_token()
|
|
1411
|
+
lemma_ids_str = _next_token()
|
|
1412
|
+
if lemma_ids_str == '0000':
|
|
1413
|
+
synset._pointers[symbol].add((pos, offset))
|
|
1414
|
+
else:
|
|
1415
|
+
source_index = int(lemma_ids_str[:2], 16) - 1
|
|
1416
|
+
target_index = int(lemma_ids_str[2:], 16) - 1
|
|
1417
|
+
source_lemma_name = synset._lemmas[source_index]._name
|
|
1418
|
+
lemma_pointers = synset._lemma_pointers
|
|
1419
|
+
tups = lemma_pointers[source_lemma_name, symbol]
|
|
1420
|
+
tups.append((pos, offset, target_index))
|
|
1421
|
+
|
|
1422
|
+
# read the verb frames
|
|
1423
|
+
try:
|
|
1424
|
+
frame_count = int(_next_token())
|
|
1425
|
+
except StopIteration:
|
|
1426
|
+
pass
|
|
1427
|
+
else:
|
|
1428
|
+
for _ in range(frame_count):
|
|
1429
|
+
# read the plus sign
|
|
1430
|
+
plus = _next_token()
|
|
1431
|
+
assert plus == '+'
|
|
1432
|
+
# read the frame and lemma number
|
|
1433
|
+
frame_number = int(_next_token())
|
|
1434
|
+
frame_string_fmt = VERB_FRAME_STRINGS[frame_number]
|
|
1435
|
+
lemma_number = int(_next_token(), 16)
|
|
1436
|
+
# lemma number of 00 means all words in the synset
|
|
1437
|
+
if lemma_number == 0:
|
|
1438
|
+
synset._frame_ids.append(frame_number)
|
|
1439
|
+
for lemma in synset._lemmas:
|
|
1440
|
+
lemma._frame_ids.append(frame_number)
|
|
1441
|
+
lemma._frame_strings.append(
|
|
1442
|
+
frame_string_fmt % lemma._name
|
|
1443
|
+
)
|
|
1444
|
+
# only a specific word in the synset
|
|
1445
|
+
else:
|
|
1446
|
+
lemma = synset._lemmas[lemma_number - 1]
|
|
1447
|
+
lemma._frame_ids.append(frame_number)
|
|
1448
|
+
lemma._frame_strings.append(
|
|
1449
|
+
frame_string_fmt % lemma._name
|
|
1450
|
+
)
|
|
1451
|
+
|
|
1452
|
+
# raise a more informative error with line text
|
|
1453
|
+
except ValueError as e:
|
|
1454
|
+
raise WordNetError('line %r: %s' % (data_file_line, e))
|
|
1455
|
+
|
|
1456
|
+
# set sense keys for Lemma objects - note that this has to be
|
|
1457
|
+
# done afterwards so that the relations are available
|
|
1458
|
+
for lemma in synset._lemmas:
|
|
1459
|
+
if synset._pos == ADJ_SAT:
|
|
1460
|
+
head_lemma = synset.similar_tos()[0]._lemmas[0]
|
|
1461
|
+
head_name = head_lemma._name
|
|
1462
|
+
head_id = '%02d' % head_lemma._lex_id
|
|
1463
|
+
else:
|
|
1464
|
+
head_name = head_id = ''
|
|
1465
|
+
tup = (lemma._name, WordNetCorpusReader._pos_numbers[synset._pos],
|
|
1466
|
+
lemma._lexname_index, lemma._lex_id, head_name, head_id)
|
|
1467
|
+
lemma._key = ('%s%%%d:%02d:%02d:%s:%s' % tup).lower()
|
|
1468
|
+
|
|
1469
|
+
# the canonical name is based on the first lemma
|
|
1470
|
+
lemma_name = synset._lemmas[0]._name.lower()
|
|
1471
|
+
offsets = self._lemma_pos_offset_map[lemma_name][synset._pos]
|
|
1472
|
+
sense_index = offsets.index(synset._offset)
|
|
1473
|
+
tup = lemma_name, synset._pos, sense_index + 1
|
|
1474
|
+
synset._name = '%s.%s.%02i' % tup
|
|
1475
|
+
|
|
1476
|
+
return synset
|
|
1477
|
+
|
|
1478
|
+
def synset_from_sense_key(self, sense_key):
|
|
1479
|
+
"""
|
|
1480
|
+
Retrieves synset based on a given sense_key. Sense keys can be
|
|
1481
|
+
obtained from lemma.key()
|
|
1482
|
+
|
|
1483
|
+
From https://wordnet.princeton.edu/wordnet/man/senseidx.5WN.html:
|
|
1484
|
+
A sense_key is represented as:
|
|
1485
|
+
lemma % lex_sense (e.g. 'dog%1:18:01::')
|
|
1486
|
+
where lex_sense is encoded as:
|
|
1487
|
+
ss_type:lex_filenum:lex_id:head_word:head_id
|
|
1488
|
+
|
|
1489
|
+
lemma: ASCII text of word/collocation, in lower case
|
|
1490
|
+
ss_type: synset type for the sense (1 digit int)
|
|
1491
|
+
The synset type is encoded as follows:
|
|
1492
|
+
1 NOUN
|
|
1493
|
+
2 VERB
|
|
1494
|
+
3 ADJECTIVE
|
|
1495
|
+
4 ADVERB
|
|
1496
|
+
5 ADJECTIVE SATELLITE
|
|
1497
|
+
lex_filenum: name of lexicographer file containing the synset for the sense (2 digit int)
|
|
1498
|
+
lex_id: when paired with lemma, uniquely identifies a sense in the lexicographer file (2 digit int)
|
|
1499
|
+
head_word: lemma of the first word in satellite's head synset
|
|
1500
|
+
Only used if sense is in an adjective satellite synset
|
|
1501
|
+
head_id: uniquely identifies sense in a lexicographer file when paired with head_word
|
|
1502
|
+
Only used if head_word is present (2 digit int)
|
|
1503
|
+
"""
|
|
1504
|
+
sense_key_regex = re.compile(r"(.*)\%(.*):(.*):(.*):(.*):(.*)")
|
|
1505
|
+
synset_types = {1:NOUN, 2:VERB, 3:ADJ, 4:ADV, 5:ADJ_SAT}
|
|
1506
|
+
lemma, ss_type, _, lex_id, _, _ = sense_key_regex.match(sense_key).groups()
|
|
1507
|
+
|
|
1508
|
+
# check that information extracted from sense_key is valid
|
|
1509
|
+
error = None
|
|
1510
|
+
if not lemma:
|
|
1511
|
+
error = "lemma"
|
|
1512
|
+
elif int(ss_type) not in synset_types:
|
|
1513
|
+
error = "ss_type"
|
|
1514
|
+
elif int(lex_id) < 0 or int(lex_id) > 99:
|
|
1515
|
+
error = "lex_id"
|
|
1516
|
+
if error:
|
|
1517
|
+
raise WordNetError("valid {} could not be extracted from the sense key".format(error))
|
|
1518
|
+
|
|
1519
|
+
synset_id = '.'.join([lemma, synset_types[int(ss_type)], lex_id])
|
|
1520
|
+
return self.synset(synset_id)
|
|
1521
|
+
|
|
1522
|
+
#############################################################
|
|
1523
|
+
# Retrieve synsets and lemmas.
|
|
1524
|
+
#############################################################
|
|
1525
|
+
|
|
1526
|
+
def synsets(self, lemma, pos=None, lang='eng', check_exceptions=True):
|
|
1527
|
+
"""Load all synsets with a given lemma and part of speech tag.
|
|
1528
|
+
If no pos is specified, all synsets for all parts of speech
|
|
1529
|
+
will be loaded.
|
|
1530
|
+
If lang is specified, all the synsets associated with the lemma name
|
|
1531
|
+
of that language will be returned.
|
|
1532
|
+
"""
|
|
1533
|
+
lemma = lemma.lower()
|
|
1534
|
+
|
|
1535
|
+
if lang == 'eng':
|
|
1536
|
+
get_synset = self.synset_from_pos_and_offset
|
|
1537
|
+
index = self._lemma_pos_offset_map
|
|
1538
|
+
if pos is None:
|
|
1539
|
+
pos = POS_LIST
|
|
1540
|
+
return [get_synset(p, offset)
|
|
1541
|
+
for p in pos
|
|
1542
|
+
for form in self._morphy(lemma, p, check_exceptions)
|
|
1543
|
+
for offset in index[form].get(p, [])]
|
|
1544
|
+
|
|
1545
|
+
else:
|
|
1546
|
+
self._load_lang_data(lang)
|
|
1547
|
+
synset_list = []
|
|
1548
|
+
for l in self._lang_data[lang][1][lemma]:
|
|
1549
|
+
if pos is not None and l[-1] != pos:
|
|
1550
|
+
continue
|
|
1551
|
+
synset_list.append(self.of2ss(l))
|
|
1552
|
+
return synset_list
|
|
1553
|
+
|
|
1554
|
+
def lemmas(self, lemma, pos=None, lang='eng'):
|
|
1555
|
+
"""Return all Lemma objects with a name matching the specified lemma
|
|
1556
|
+
name and part of speech tag. Matches any part of speech tag if none is
|
|
1557
|
+
specified."""
|
|
1558
|
+
|
|
1559
|
+
lemma = lemma.lower()
|
|
1560
|
+
if lang == 'eng':
|
|
1561
|
+
return [lemma_obj
|
|
1562
|
+
for synset in self.synsets(lemma, pos)
|
|
1563
|
+
for lemma_obj in synset.lemmas()
|
|
1564
|
+
if lemma_obj.name().lower() == lemma]
|
|
1565
|
+
|
|
1566
|
+
else:
|
|
1567
|
+
self._load_lang_data(lang)
|
|
1568
|
+
lemmas = []
|
|
1569
|
+
syn = self.synsets(lemma, lang=lang)
|
|
1570
|
+
for s in syn:
|
|
1571
|
+
if pos is not None and s.pos() != pos:
|
|
1572
|
+
continue
|
|
1573
|
+
for lemma_obj in s.lemmas(lang=lang):
|
|
1574
|
+
if lemma_obj.name().lower() == lemma:
|
|
1575
|
+
lemmas.append(lemma_obj)
|
|
1576
|
+
return lemmas
|
|
1577
|
+
|
|
1578
|
+
def all_lemma_names(self, pos=None, lang='eng'):
|
|
1579
|
+
"""Return all lemma names for all synsets for the given
|
|
1580
|
+
part of speech tag and language or languages. If pos is
|
|
1581
|
+
not specified, all synsets for all parts of speech will
|
|
1582
|
+
be used."""
|
|
1583
|
+
|
|
1584
|
+
if lang == 'eng':
|
|
1585
|
+
if pos is None:
|
|
1586
|
+
return iter(self._lemma_pos_offset_map)
|
|
1587
|
+
else:
|
|
1588
|
+
return (
|
|
1589
|
+
lemma for lemma in self._lemma_pos_offset_map
|
|
1590
|
+
if pos in self._lemma_pos_offset_map[lemma]
|
|
1591
|
+
)
|
|
1592
|
+
else:
|
|
1593
|
+
self._load_lang_data(lang)
|
|
1594
|
+
lemma = []
|
|
1595
|
+
for i in self._lang_data[lang][0]:
|
|
1596
|
+
if pos is not None and i[-1] != pos:
|
|
1597
|
+
continue
|
|
1598
|
+
lemma.extend(self._lang_data[lang][0][i])
|
|
1599
|
+
|
|
1600
|
+
lemma = list(set(lemma))
|
|
1601
|
+
return lemma
|
|
1602
|
+
|
|
1603
|
+
def all_synsets(self, pos=None):
|
|
1604
|
+
"""Iterate over all synsets with a given part of speech tag.
|
|
1605
|
+
If no pos is specified, all synsets for all parts of speech
|
|
1606
|
+
will be loaded.
|
|
1607
|
+
"""
|
|
1608
|
+
if pos is None:
|
|
1609
|
+
pos_tags = self._FILEMAP.keys()
|
|
1610
|
+
else:
|
|
1611
|
+
pos_tags = [pos]
|
|
1612
|
+
|
|
1613
|
+
cache = self._synset_offset_cache
|
|
1614
|
+
from_pos_and_line = self._synset_from_pos_and_line
|
|
1615
|
+
|
|
1616
|
+
# generate all synsets for each part of speech
|
|
1617
|
+
for pos_tag in pos_tags:
|
|
1618
|
+
# Open the file for reading. Note that we can not re-use
|
|
1619
|
+
# the file poitners from self._data_file_map here, because
|
|
1620
|
+
# we're defining an iterator, and those file pointers might
|
|
1621
|
+
# be moved while we're not looking.
|
|
1622
|
+
if pos_tag == ADJ_SAT:
|
|
1623
|
+
pos_tag = ADJ
|
|
1624
|
+
fileid = 'data.%s' % self._FILEMAP[pos_tag]
|
|
1625
|
+
data_file = self.open(fileid)
|
|
1626
|
+
|
|
1627
|
+
try:
|
|
1628
|
+
# generate synsets for each line in the POS file
|
|
1629
|
+
offset = data_file.tell()
|
|
1630
|
+
line = data_file.readline()
|
|
1631
|
+
while line:
|
|
1632
|
+
if not line[0].isspace():
|
|
1633
|
+
if offset in cache[pos_tag]:
|
|
1634
|
+
# See if the synset is cached
|
|
1635
|
+
synset = cache[pos_tag][offset]
|
|
1636
|
+
else:
|
|
1637
|
+
# Otherwise, parse the line
|
|
1638
|
+
synset = from_pos_and_line(pos_tag, line)
|
|
1639
|
+
cache[pos_tag][offset] = synset
|
|
1640
|
+
|
|
1641
|
+
# adjective satellites are in the same file as
|
|
1642
|
+
# adjectives so only yield the synset if it's actually
|
|
1643
|
+
# a satellite
|
|
1644
|
+
if synset._pos == ADJ_SAT:
|
|
1645
|
+
yield synset
|
|
1646
|
+
|
|
1647
|
+
# for all other POS tags, yield all synsets (this means
|
|
1648
|
+
# that adjectives also include adjective satellites)
|
|
1649
|
+
else:
|
|
1650
|
+
yield synset
|
|
1651
|
+
offset = data_file.tell()
|
|
1652
|
+
line = data_file.readline()
|
|
1653
|
+
|
|
1654
|
+
# close the extra file handle we opened
|
|
1655
|
+
except:
|
|
1656
|
+
data_file.close()
|
|
1657
|
+
raise
|
|
1658
|
+
else:
|
|
1659
|
+
data_file.close()
|
|
1660
|
+
|
|
1661
|
+
def words(self, lang='eng'):
|
|
1662
|
+
"""return lemmas of the given language as list of words"""
|
|
1663
|
+
return self.all_lemma_names(lang=lang)
|
|
1664
|
+
|
|
1665
|
+
def license(self, lang='eng'):
|
|
1666
|
+
"""Return the contents of LICENSE (for omw)
|
|
1667
|
+
use lang=lang to get the license for an individual language"""
|
|
1668
|
+
if lang == 'eng':
|
|
1669
|
+
return self.open("LICENSE").read()
|
|
1670
|
+
elif lang in self.langs():
|
|
1671
|
+
return self._omw_reader.open("{}/LICENSE".format(lang)).read()
|
|
1672
|
+
elif lang == 'omw':
|
|
1673
|
+
# under the assumption you don't mean Omwunra-Toqura
|
|
1674
|
+
return self._omw_reader.open("LICENSE").read()
|
|
1675
|
+
elif lang in self._lang_data:
|
|
1676
|
+
raise WordNetError(
|
|
1677
|
+
"Cannot determine license for user-provided tab file"
|
|
1678
|
+
)
|
|
1679
|
+
else:
|
|
1680
|
+
raise WordNetError("Language is not supported.")
|
|
1681
|
+
|
|
1682
|
+
def readme(self, lang='omw'):
|
|
1683
|
+
"""Return the contents of README (for omw)
|
|
1684
|
+
use lang=lang to get the readme for an individual language"""
|
|
1685
|
+
if lang == 'eng':
|
|
1686
|
+
return self.open("README").read()
|
|
1687
|
+
elif lang in self.langs():
|
|
1688
|
+
return self._omw_reader.open("{}/README".format(lang)).read()
|
|
1689
|
+
elif lang == 'omw':
|
|
1690
|
+
# under the assumption you don't mean Omwunra-Toqura
|
|
1691
|
+
return self._omw_reader.open("README").read()
|
|
1692
|
+
elif lang in self._lang_data:
|
|
1693
|
+
raise WordNetError("No README for user-provided tab file")
|
|
1694
|
+
else:
|
|
1695
|
+
raise WordNetError("Language is not supported.")
|
|
1696
|
+
|
|
1697
|
+
def citation(self, lang='omw'):
|
|
1698
|
+
"""Return the contents of citation.bib file (for omw)
|
|
1699
|
+
use lang=lang to get the citation for an individual language"""
|
|
1700
|
+
if lang == 'eng':
|
|
1701
|
+
return self.open("citation.bib").read()
|
|
1702
|
+
elif lang in self.langs():
|
|
1703
|
+
return self._omw_reader.open("{}/citation.bib".format(lang)).read()
|
|
1704
|
+
elif lang == 'omw':
|
|
1705
|
+
# under the assumption you don't mean Omwunra-Toqura
|
|
1706
|
+
return self._omw_reader.open("citation.bib").read()
|
|
1707
|
+
elif lang in self._lang_data:
|
|
1708
|
+
raise WordNetError("citation not known for user-provided tab file")
|
|
1709
|
+
else:
|
|
1710
|
+
raise WordNetError("Language is not supported.")
|
|
1711
|
+
|
|
1712
|
+
#############################################################
|
|
1713
|
+
# Misc
|
|
1714
|
+
#############################################################
|
|
1715
|
+
def lemma_count(self, lemma):
|
|
1716
|
+
"""Return the frequency count for this Lemma"""
|
|
1717
|
+
# Currently, count is only work for English
|
|
1718
|
+
if lemma._lang != 'eng':
|
|
1719
|
+
return 0
|
|
1720
|
+
# open the count file if we haven't already
|
|
1721
|
+
if self._key_count_file is None:
|
|
1722
|
+
self._key_count_file = self.open('cntlist.rev')
|
|
1723
|
+
# find the key in the counts file and return the count
|
|
1724
|
+
line = _binary_search_file(self._key_count_file, lemma._key)
|
|
1725
|
+
if line:
|
|
1726
|
+
return int(line.rsplit(' ', 1)[-1])
|
|
1727
|
+
else:
|
|
1728
|
+
return 0
|
|
1729
|
+
|
|
1730
|
+
def path_similarity(
|
|
1731
|
+
self, synset1, synset2, verbose=False, simulate_root=True
|
|
1732
|
+
):
|
|
1733
|
+
return synset1.path_similarity(synset2, verbose, simulate_root)
|
|
1734
|
+
path_similarity.__doc__ = Synset.path_similarity.__doc__
|
|
1735
|
+
|
|
1736
|
+
def lch_similarity(
|
|
1737
|
+
self, synset1, synset2, verbose=False, simulate_root=True
|
|
1738
|
+
):
|
|
1739
|
+
return synset1.lch_similarity(synset2, verbose, simulate_root)
|
|
1740
|
+
lch_similarity.__doc__ = Synset.lch_similarity.__doc__
|
|
1741
|
+
|
|
1742
|
+
def wup_similarity(
|
|
1743
|
+
self, synset1, synset2, verbose=False, simulate_root=True
|
|
1744
|
+
):
|
|
1745
|
+
return synset1.wup_similarity(synset2, verbose, simulate_root)
|
|
1746
|
+
wup_similarity.__doc__ = Synset.wup_similarity.__doc__
|
|
1747
|
+
|
|
1748
|
+
def res_similarity(self, synset1, synset2, ic, verbose=False):
|
|
1749
|
+
return synset1.res_similarity(synset2, ic, verbose)
|
|
1750
|
+
res_similarity.__doc__ = Synset.res_similarity.__doc__
|
|
1751
|
+
|
|
1752
|
+
def jcn_similarity(self, synset1, synset2, ic, verbose=False):
|
|
1753
|
+
return synset1.jcn_similarity(synset2, ic, verbose)
|
|
1754
|
+
jcn_similarity.__doc__ = Synset.jcn_similarity.__doc__
|
|
1755
|
+
|
|
1756
|
+
def lin_similarity(self, synset1, synset2, ic, verbose=False):
|
|
1757
|
+
return synset1.lin_similarity(synset2, ic, verbose)
|
|
1758
|
+
lin_similarity.__doc__ = Synset.lin_similarity.__doc__
|
|
1759
|
+
|
|
1760
|
+
#############################################################
|
|
1761
|
+
# Morphy
|
|
1762
|
+
#############################################################
|
|
1763
|
+
# Morphy, adapted from Oliver Steele's pywordnet
|
|
1764
|
+
def morphy(self, form, pos=None, check_exceptions=True):
|
|
1765
|
+
"""
|
|
1766
|
+
Find a possible base form for the given form, with the given
|
|
1767
|
+
part of speech, by checking WordNet's list of exceptional
|
|
1768
|
+
forms, and by recursively stripping affixes for this part of
|
|
1769
|
+
speech until a form in WordNet is found.
|
|
1770
|
+
|
|
1771
|
+
>>> from nltk.corpus import wordnet as wn
|
|
1772
|
+
>>> print(wn.morphy('dogs'))
|
|
1773
|
+
dog
|
|
1774
|
+
>>> print(wn.morphy('churches'))
|
|
1775
|
+
church
|
|
1776
|
+
>>> print(wn.morphy('aardwolves'))
|
|
1777
|
+
aardwolf
|
|
1778
|
+
>>> print(wn.morphy('abaci'))
|
|
1779
|
+
abacus
|
|
1780
|
+
>>> wn.morphy('hardrock', wn.ADV)
|
|
1781
|
+
>>> print(wn.morphy('book', wn.NOUN))
|
|
1782
|
+
book
|
|
1783
|
+
>>> wn.morphy('book', wn.ADJ)
|
|
1784
|
+
"""
|
|
1785
|
+
|
|
1786
|
+
if pos is None:
|
|
1787
|
+
morphy = self._morphy
|
|
1788
|
+
analyses = chain(a for p in POS_LIST for a in morphy(form, p))
|
|
1789
|
+
else:
|
|
1790
|
+
analyses = self._morphy(form, pos, check_exceptions)
|
|
1791
|
+
|
|
1792
|
+
# get the first one we find
|
|
1793
|
+
first = list(islice(analyses, 1))
|
|
1794
|
+
if len(first) == 1:
|
|
1795
|
+
return first[0]
|
|
1796
|
+
else:
|
|
1797
|
+
return None
|
|
1798
|
+
|
|
1799
|
+
MORPHOLOGICAL_SUBSTITUTIONS = {
|
|
1800
|
+
NOUN: [('s', ''), ('ses', 's'), ('ves', 'f'), ('xes', 'x'),
|
|
1801
|
+
('zes', 'z'), ('ches', 'ch'), ('shes', 'sh'),
|
|
1802
|
+
('men', 'man'), ('ies', 'y')],
|
|
1803
|
+
VERB: [('s', ''), ('ies', 'y'), ('es', 'e'), ('es', ''),
|
|
1804
|
+
('ed', 'e'), ('ed', ''), ('ing', 'e'), ('ing', '')],
|
|
1805
|
+
ADJ: [('er', ''), ('est', ''), ('er', 'e'), ('est', 'e')],
|
|
1806
|
+
ADV: []}
|
|
1807
|
+
|
|
1808
|
+
MORPHOLOGICAL_SUBSTITUTIONS[ADJ_SAT] = MORPHOLOGICAL_SUBSTITUTIONS[ADJ]
|
|
1809
|
+
|
|
1810
|
+
def _morphy(self, form, pos, check_exceptions=True):
|
|
1811
|
+
# from jordanbg:
|
|
1812
|
+
# Given an original string x
|
|
1813
|
+
# 1. Apply rules once to the input to get y1, y2, y3, etc.
|
|
1814
|
+
# 2. Return all that are in the database
|
|
1815
|
+
# 3. If there are no matches, keep applying rules until you either
|
|
1816
|
+
# find a match or you can't go any further
|
|
1817
|
+
|
|
1818
|
+
exceptions = self._exception_map[pos]
|
|
1819
|
+
substitutions = self.MORPHOLOGICAL_SUBSTITUTIONS[pos]
|
|
1820
|
+
|
|
1821
|
+
def apply_rules(forms):
|
|
1822
|
+
return [form[:-len(old)] + new
|
|
1823
|
+
for form in forms
|
|
1824
|
+
for old, new in substitutions
|
|
1825
|
+
if form.endswith(old)]
|
|
1826
|
+
|
|
1827
|
+
def filter_forms(forms):
|
|
1828
|
+
result = []
|
|
1829
|
+
seen = set()
|
|
1830
|
+
for form in forms:
|
|
1831
|
+
if form in self._lemma_pos_offset_map:
|
|
1832
|
+
if pos in self._lemma_pos_offset_map[form]:
|
|
1833
|
+
if form not in seen:
|
|
1834
|
+
result.append(form)
|
|
1835
|
+
seen.add(form)
|
|
1836
|
+
return result
|
|
1837
|
+
|
|
1838
|
+
# 0. Check the exception lists
|
|
1839
|
+
if check_exceptions:
|
|
1840
|
+
if form in exceptions:
|
|
1841
|
+
return filter_forms([form] + exceptions[form])
|
|
1842
|
+
|
|
1843
|
+
# 1. Apply rules once to the input to get y1, y2, y3, etc.
|
|
1844
|
+
forms = apply_rules([form])
|
|
1845
|
+
|
|
1846
|
+
# 2. Return all that are in the database (and check the original too)
|
|
1847
|
+
results = filter_forms([form] + forms)
|
|
1848
|
+
if results:
|
|
1849
|
+
return results
|
|
1850
|
+
|
|
1851
|
+
# 3. If there are no matches, keep applying rules until we find a match
|
|
1852
|
+
while forms:
|
|
1853
|
+
forms = apply_rules(forms)
|
|
1854
|
+
results = filter_forms(forms)
|
|
1855
|
+
if results:
|
|
1856
|
+
return results
|
|
1857
|
+
|
|
1858
|
+
# Return an empty list if we can't find anything
|
|
1859
|
+
return []
|
|
1860
|
+
|
|
1861
|
+
#############################################################
|
|
1862
|
+
# Create information content from corpus
|
|
1863
|
+
#############################################################
|
|
1864
|
+
def ic(self, corpus, weight_senses_equally=False, smoothing=1.0):
|
|
1865
|
+
"""
|
|
1866
|
+
Creates an information content lookup dictionary from a corpus.
|
|
1867
|
+
|
|
1868
|
+
:type corpus: CorpusReader
|
|
1869
|
+
:param corpus: The corpus from which we create an information
|
|
1870
|
+
content dictionary.
|
|
1871
|
+
:type weight_senses_equally: bool
|
|
1872
|
+
:param weight_senses_equally: If this is True, gives all
|
|
1873
|
+
possible senses equal weight rather than dividing by the
|
|
1874
|
+
number of possible senses. (If a word has 3 synses, each
|
|
1875
|
+
sense gets 0.3333 per appearance when this is False, 1.0 when
|
|
1876
|
+
it is true.)
|
|
1877
|
+
:param smoothing: How much do we smooth synset counts (default is 1.0)
|
|
1878
|
+
:type smoothing: float
|
|
1879
|
+
:return: An information content dictionary
|
|
1880
|
+
"""
|
|
1881
|
+
counts = FreqDist()
|
|
1882
|
+
for ww in corpus.words():
|
|
1883
|
+
counts[ww] += 1
|
|
1884
|
+
|
|
1885
|
+
ic = {}
|
|
1886
|
+
for pp in POS_LIST:
|
|
1887
|
+
ic[pp] = defaultdict(float)
|
|
1888
|
+
|
|
1889
|
+
# Initialize the counts with the smoothing value
|
|
1890
|
+
if smoothing > 0.0:
|
|
1891
|
+
for ss in self.all_synsets():
|
|
1892
|
+
pos = ss._pos
|
|
1893
|
+
if pos == ADJ_SAT:
|
|
1894
|
+
pos = ADJ
|
|
1895
|
+
ic[pos][ss._offset] = smoothing
|
|
1896
|
+
|
|
1897
|
+
for ww in counts:
|
|
1898
|
+
possible_synsets = self.synsets(ww)
|
|
1899
|
+
if len(possible_synsets) == 0:
|
|
1900
|
+
continue
|
|
1901
|
+
|
|
1902
|
+
# Distribute weight among possible synsets
|
|
1903
|
+
weight = float(counts[ww])
|
|
1904
|
+
if not weight_senses_equally:
|
|
1905
|
+
weight /= float(len(possible_synsets))
|
|
1906
|
+
|
|
1907
|
+
for ss in possible_synsets:
|
|
1908
|
+
pos = ss._pos
|
|
1909
|
+
if pos == ADJ_SAT:
|
|
1910
|
+
pos = ADJ
|
|
1911
|
+
for level in ss._iter_hypernym_lists():
|
|
1912
|
+
for hh in level:
|
|
1913
|
+
ic[pos][hh._offset] += weight
|
|
1914
|
+
# Add the weight to the root
|
|
1915
|
+
ic[pos][0] += weight
|
|
1916
|
+
return ic
|
|
1917
|
+
|
|
1918
|
+
def custom_lemmas(self, tab_file, lang):
|
|
1919
|
+
"""
|
|
1920
|
+
Reads a custom tab file containing mappings of lemmas in the given
|
|
1921
|
+
language to Princeton WordNet 3.0 synset offsets, allowing NLTK's
|
|
1922
|
+
WordNet functions to then be used with that language.
|
|
1923
|
+
|
|
1924
|
+
See the "Tab files" section at http://compling.hss.ntu.edu.sg/omw/ for
|
|
1925
|
+
documentation on the Multilingual WordNet tab file format.
|
|
1926
|
+
|
|
1927
|
+
:param tab_file: Tab file as a file or file-like object
|
|
1928
|
+
:type lang str
|
|
1929
|
+
:param lang ISO 639-3 code of the language of the tab file
|
|
1930
|
+
"""
|
|
1931
|
+
if len(lang) != 3:
|
|
1932
|
+
raise ValueError('lang should be a (3 character) ISO 639-3 code')
|
|
1933
|
+
self._lang_data[lang] = [defaultdict(list), defaultdict(list)]
|
|
1934
|
+
for l in tab_file.readlines():
|
|
1935
|
+
if isinstance(l, bytes):
|
|
1936
|
+
# Support byte-stream files (e.g. as returned by Python 2's
|
|
1937
|
+
# open() function) as well as text-stream ones
|
|
1938
|
+
l = l.decode('utf-8')
|
|
1939
|
+
l = l.replace('\n', '')
|
|
1940
|
+
l = l.replace(' ', '_')
|
|
1941
|
+
if l[0] != '#':
|
|
1942
|
+
word = l.split('\t')
|
|
1943
|
+
self._lang_data[lang][0][word[0]].append(word[2])
|
|
1944
|
+
self._lang_data[lang][1][word[2].lower()].append(word[0])
|
|
1945
|
+
|
|
1946
|
+
|
|
1947
|
+
######################################################################
|
|
1948
|
+
# WordNet Information Content Corpus Reader
|
|
1949
|
+
######################################################################
|
|
1950
|
+
|
|
1951
|
+
class WordNetICCorpusReader(CorpusReader):
|
|
1952
|
+
"""
|
|
1953
|
+
A corpus reader for the WordNet information content corpus.
|
|
1954
|
+
"""
|
|
1955
|
+
|
|
1956
|
+
def __init__(self, root, fileids):
|
|
1957
|
+
CorpusReader.__init__(self, root, fileids, encoding='utf8')
|
|
1958
|
+
|
|
1959
|
+
# this load function would be more efficient if the data was pickled
|
|
1960
|
+
# Note that we can't use NLTK's frequency distributions because
|
|
1961
|
+
# synsets are overlapping (each instance of a synset also counts
|
|
1962
|
+
# as an instance of its hypernyms)
|
|
1963
|
+
def ic(self, icfile):
|
|
1964
|
+
"""
|
|
1965
|
+
Load an information content file from the wordnet_ic corpus
|
|
1966
|
+
and return a dictionary. This dictionary has just two keys,
|
|
1967
|
+
NOUN and VERB, whose values are dictionaries that map from
|
|
1968
|
+
synsets to information content values.
|
|
1969
|
+
|
|
1970
|
+
:type icfile: str
|
|
1971
|
+
:param icfile: The name of the wordnet_ic file (e.g. "ic-brown.dat")
|
|
1972
|
+
:return: An information content dictionary
|
|
1973
|
+
"""
|
|
1974
|
+
ic = {}
|
|
1975
|
+
ic[NOUN] = defaultdict(float)
|
|
1976
|
+
ic[VERB] = defaultdict(float)
|
|
1977
|
+
for num, line in enumerate(self.open(icfile)):
|
|
1978
|
+
if num == 0: # skip the header
|
|
1979
|
+
continue
|
|
1980
|
+
fields = line.split()
|
|
1981
|
+
offset = int(fields[0][:-1])
|
|
1982
|
+
value = float(fields[1])
|
|
1983
|
+
pos = _get_pos(fields[0])
|
|
1984
|
+
if len(fields) == 3 and fields[2] == "ROOT":
|
|
1985
|
+
# Store root count.
|
|
1986
|
+
ic[pos][0] += value
|
|
1987
|
+
if value != 0:
|
|
1988
|
+
ic[pos][offset] = value
|
|
1989
|
+
return ic
|
|
1990
|
+
|
|
1991
|
+
|
|
1992
|
+
######################################################################
|
|
1993
|
+
# Similarity metrics
|
|
1994
|
+
######################################################################
|
|
1995
|
+
|
|
1996
|
+
# TODO: Add in the option to manually add a new root node; this will be
|
|
1997
|
+
# useful for verb similarity as there exist multiple verb taxonomies.
|
|
1998
|
+
|
|
1999
|
+
# More information about the metrics is available at
|
|
2000
|
+
# http://marimba.d.umn.edu/similarity/measures.html
|
|
2001
|
+
|
|
2002
|
+
def path_similarity(synset1, synset2, verbose=False, simulate_root=True):
|
|
2003
|
+
return synset1.path_similarity(synset2, verbose, simulate_root)
|
|
2004
|
+
|
|
2005
|
+
|
|
2006
|
+
def lch_similarity(synset1, synset2, verbose=False, simulate_root=True):
|
|
2007
|
+
return synset1.lch_similarity(synset2, verbose, simulate_root)
|
|
2008
|
+
|
|
2009
|
+
|
|
2010
|
+
def wup_similarity(synset1, synset2, verbose=False, simulate_root=True):
|
|
2011
|
+
return synset1.wup_similarity(synset2, verbose, simulate_root)
|
|
2012
|
+
|
|
2013
|
+
|
|
2014
|
+
def res_similarity(synset1, synset2, ic, verbose=False):
|
|
2015
|
+
return synset1.res_similarity(synset2, verbose)
|
|
2016
|
+
|
|
2017
|
+
|
|
2018
|
+
def jcn_similarity(synset1, synset2, ic, verbose=False):
|
|
2019
|
+
return synset1.jcn_similarity(synset2, verbose)
|
|
2020
|
+
|
|
2021
|
+
|
|
2022
|
+
def lin_similarity(synset1, synset2, ic, verbose=False):
|
|
2023
|
+
return synset1.lin_similarity(synset2, verbose)
|
|
2024
|
+
|
|
2025
|
+
|
|
2026
|
+
path_similarity.__doc__ = Synset.path_similarity.__doc__
|
|
2027
|
+
lch_similarity.__doc__ = Synset.lch_similarity.__doc__
|
|
2028
|
+
wup_similarity.__doc__ = Synset.wup_similarity.__doc__
|
|
2029
|
+
res_similarity.__doc__ = Synset.res_similarity.__doc__
|
|
2030
|
+
jcn_similarity.__doc__ = Synset.jcn_similarity.__doc__
|
|
2031
|
+
lin_similarity.__doc__ = Synset.lin_similarity.__doc__
|
|
2032
|
+
|
|
2033
|
+
|
|
2034
|
+
def _lcs_ic(synset1, synset2, ic, verbose=False):
|
|
2035
|
+
"""
|
|
2036
|
+
Get the information content of the least common subsumer that has
|
|
2037
|
+
the highest information content value. If two nodes have no
|
|
2038
|
+
explicit common subsumer, assume that they share an artificial
|
|
2039
|
+
root node that is the hypernym of all explicit roots.
|
|
2040
|
+
|
|
2041
|
+
:type synset1: Synset
|
|
2042
|
+
:param synset1: First input synset.
|
|
2043
|
+
:type synset2: Synset
|
|
2044
|
+
:param synset2: Second input synset. Must be the same part of
|
|
2045
|
+
speech as the first synset.
|
|
2046
|
+
:type ic: dict
|
|
2047
|
+
:param ic: an information content object (as returned by ``load_ic()``).
|
|
2048
|
+
:return: The information content of the two synsets and their most
|
|
2049
|
+
informative subsumer
|
|
2050
|
+
"""
|
|
2051
|
+
if synset1._pos != synset2._pos:
|
|
2052
|
+
raise WordNetError(
|
|
2053
|
+
'Computing the least common subsumer requires '
|
|
2054
|
+
'%s and %s to have the same part of speech.' %
|
|
2055
|
+
(synset1, synset2)
|
|
2056
|
+
)
|
|
2057
|
+
|
|
2058
|
+
ic1 = information_content(synset1, ic)
|
|
2059
|
+
ic2 = information_content(synset2, ic)
|
|
2060
|
+
subsumers = synset1.common_hypernyms(synset2)
|
|
2061
|
+
if len(subsumers) == 0:
|
|
2062
|
+
subsumer_ic = 0
|
|
2063
|
+
else:
|
|
2064
|
+
subsumer_ic = max(information_content(s, ic) for s in subsumers)
|
|
2065
|
+
|
|
2066
|
+
if verbose:
|
|
2067
|
+
print("> LCS Subsumer by content:", subsumer_ic)
|
|
2068
|
+
|
|
2069
|
+
return ic1, ic2, subsumer_ic
|
|
2070
|
+
|
|
2071
|
+
|
|
2072
|
+
# Utility functions
|
|
2073
|
+
|
|
2074
|
+
def information_content(synset, ic):
|
|
2075
|
+
try:
|
|
2076
|
+
icpos = ic[synset._pos]
|
|
2077
|
+
except KeyError:
|
|
2078
|
+
msg = 'Information content file has no entries for part-of-speech: %s'
|
|
2079
|
+
raise WordNetError(msg % synset._pos)
|
|
2080
|
+
|
|
2081
|
+
counts = icpos[synset._offset]
|
|
2082
|
+
if counts == 0:
|
|
2083
|
+
return _INF
|
|
2084
|
+
else:
|
|
2085
|
+
return -math.log(counts / icpos[0])
|
|
2086
|
+
|
|
2087
|
+
|
|
2088
|
+
# get the part of speech (NOUN or VERB) from the information content record
|
|
2089
|
+
# (each identifier has a 'n' or 'v' suffix)
|
|
2090
|
+
|
|
2091
|
+
def _get_pos(field):
|
|
2092
|
+
if field[-1] == 'n':
|
|
2093
|
+
return NOUN
|
|
2094
|
+
elif field[-1] == 'v':
|
|
2095
|
+
return VERB
|
|
2096
|
+
else:
|
|
2097
|
+
msg = (
|
|
2098
|
+
"Unidentified part of speech in WordNet Information Content file "
|
|
2099
|
+
"for field %s" % field
|
|
2100
|
+
)
|
|
2101
|
+
raise ValueError(msg)
|
|
2102
|
+
|
|
2103
|
+
|
|
2104
|
+
# unload corpus after tests
|
|
2105
|
+
def teardown_module(module=None):
|
|
2106
|
+
from nltk.corpus import wordnet
|
|
2107
|
+
wordnet._unload()
|
|
2108
|
+
|