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,467 +1,467 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# Natural Language Toolkit: IBM Model 4
|
|
3
|
-
#
|
|
4
|
-
# Copyright (C) 2001-
|
|
5
|
-
# Author: Tah Wei Hoon <hoon.tw@gmail.com>
|
|
6
|
-
# URL: <http://nltk.org/>
|
|
7
|
-
# For license information, see LICENSE.TXT
|
|
8
|
-
|
|
9
|
-
"""
|
|
10
|
-
Translation model that reorders output words based on their type and
|
|
11
|
-
distance from other related words in the output sentence.
|
|
12
|
-
|
|
13
|
-
IBM Model 4 improves the distortion model of Model 3, motivated by the
|
|
14
|
-
observation that certain words tend to be re-ordered in a predictable
|
|
15
|
-
way relative to one another. For example, <adjective><noun> in English
|
|
16
|
-
usually has its order flipped as <noun><adjective> in French.
|
|
17
|
-
|
|
18
|
-
Model 4 requires words in the source and target vocabularies to be
|
|
19
|
-
categorized into classes. This can be linguistically driven, like parts
|
|
20
|
-
of speech (adjective, nouns, prepositions, etc). Word classes can also
|
|
21
|
-
be obtained by statistical methods. The original IBM Model 4 uses an
|
|
22
|
-
information theoretic approach to group words into 50 classes for each
|
|
23
|
-
vocabulary.
|
|
24
|
-
|
|
25
|
-
Terminology:
|
|
26
|
-
Cept:
|
|
27
|
-
A source word with non-zero fertility i.e. aligned to one or more
|
|
28
|
-
target words.
|
|
29
|
-
Tablet:
|
|
30
|
-
The set of target word(s) aligned to a cept.
|
|
31
|
-
Head of cept:
|
|
32
|
-
The first word of the tablet of that cept.
|
|
33
|
-
Center of cept:
|
|
34
|
-
The average position of the words in that cept's tablet. If the
|
|
35
|
-
value is not an integer, the ceiling is taken.
|
|
36
|
-
For example, for a tablet with words in positions 2, 5, 6 in the
|
|
37
|
-
target sentence, the center of the corresponding cept is
|
|
38
|
-
ceil((2 + 5 + 6) / 3) = 5
|
|
39
|
-
Displacement:
|
|
40
|
-
For a head word, defined as (position of head word - position of
|
|
41
|
-
previous cept's center). Can be positive or negative.
|
|
42
|
-
For a non-head word, defined as (position of non-head word -
|
|
43
|
-
position of previous word in the same tablet). Always positive,
|
|
44
|
-
because successive words in a tablet are assumed to appear to the
|
|
45
|
-
right of the previous word.
|
|
46
|
-
|
|
47
|
-
In contrast to Model 3 which reorders words in a tablet independently of
|
|
48
|
-
other words, Model 4 distinguishes between three cases.
|
|
49
|
-
(1) Words generated by NULL are distributed uniformly.
|
|
50
|
-
(2) For a head word t, its position is modeled by the probability
|
|
51
|
-
d_head(displacement | word_class_s(s),word_class_t(t)),
|
|
52
|
-
where s is the previous cept, and word_class_s and word_class_t maps
|
|
53
|
-
s and t to a source and target language word class respectively.
|
|
54
|
-
(3) For a non-head word t, its position is modeled by the probability
|
|
55
|
-
d_non_head(displacement | word_class_t(t))
|
|
56
|
-
|
|
57
|
-
The EM algorithm used in Model 4 is:
|
|
58
|
-
E step - In the training data, collect counts, weighted by prior
|
|
59
|
-
probabilities.
|
|
60
|
-
(a) count how many times a source language word is translated
|
|
61
|
-
into a target language word
|
|
62
|
-
(b) for a particular word class, count how many times a head
|
|
63
|
-
word is located at a particular displacement from the
|
|
64
|
-
previous cept's center
|
|
65
|
-
(c) for a particular word class, count how many times a
|
|
66
|
-
non-head word is located at a particular displacement from
|
|
67
|
-
the previous target word
|
|
68
|
-
(d) count how many times a source word is aligned to phi number
|
|
69
|
-
of target words
|
|
70
|
-
(e) count how many times NULL is aligned to a target word
|
|
71
|
-
|
|
72
|
-
M step - Estimate new probabilities based on the counts from the E step
|
|
73
|
-
|
|
74
|
-
Like Model 3, there are too many possible alignments to consider. Thus,
|
|
75
|
-
a hill climbing approach is used to sample good candidates.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
Notations:
|
|
79
|
-
i: Position in the source sentence
|
|
80
|
-
Valid values are 0 (for NULL), 1, 2, ..., length of source sentence
|
|
81
|
-
j: Position in the target sentence
|
|
82
|
-
Valid values are 1, 2, ..., length of target sentence
|
|
83
|
-
l: Number of words in the source sentence, excluding NULL
|
|
84
|
-
m: Number of words in the target sentence
|
|
85
|
-
s: A word in the source language
|
|
86
|
-
t: A word in the target language
|
|
87
|
-
phi: Fertility, the number of target words produced by a source word
|
|
88
|
-
p1: Probability that a target word produced by a source word is
|
|
89
|
-
accompanied by another target word that is aligned to NULL
|
|
90
|
-
p0: 1 - p1
|
|
91
|
-
dj: Displacement, Δj
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
References:
|
|
95
|
-
Philipp Koehn. 2010. Statistical Machine Translation.
|
|
96
|
-
Cambridge University Press, New York.
|
|
97
|
-
|
|
98
|
-
Peter E Brown, Stephen A. Della Pietra, Vincent J. Della Pietra, and
|
|
99
|
-
Robert L. Mercer. 1993. The Mathematics of Statistical Machine
|
|
100
|
-
Translation: Parameter Estimation. Computational Linguistics, 19 (2),
|
|
101
|
-
263-311.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
from __future__ import division
|
|
105
|
-
from collections import defaultdict
|
|
106
|
-
from math import factorial
|
|
107
|
-
from nltk.translate import AlignedSent
|
|
108
|
-
from nltk.translate import Alignment
|
|
109
|
-
from nltk.translate import IBMModel
|
|
110
|
-
from nltk.translate import IBMModel3
|
|
111
|
-
from nltk.translate.ibm_model import Counts
|
|
112
|
-
from nltk.translate.ibm_model import longest_target_sentence_length
|
|
113
|
-
import warnings
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
class IBMModel4(IBMModel):
|
|
117
|
-
"""
|
|
118
|
-
Translation model that reorders output words based on their type and
|
|
119
|
-
their distance from other related words in the output sentence
|
|
120
|
-
|
|
121
|
-
>>> bitext = []
|
|
122
|
-
>>> bitext.append(AlignedSent(['klein', 'ist', 'das', 'haus'], ['the', 'house', 'is', 'small']))
|
|
123
|
-
>>> bitext.append(AlignedSent(['das', 'haus', 'war', 'ja', 'groß'], ['the', 'house', 'was', 'big']))
|
|
124
|
-
>>> bitext.append(AlignedSent(['das', 'buch', 'ist', 'ja', 'klein'], ['the', 'book', 'is', 'small']))
|
|
125
|
-
>>> bitext.append(AlignedSent(['ein', 'haus', 'ist', 'klein'], ['a', 'house', 'is', 'small']))
|
|
126
|
-
>>> bitext.append(AlignedSent(['das', 'haus'], ['the', 'house']))
|
|
127
|
-
>>> bitext.append(AlignedSent(['das', 'buch'], ['the', 'book']))
|
|
128
|
-
>>> bitext.append(AlignedSent(['ein', 'buch'], ['a', 'book']))
|
|
129
|
-
>>> bitext.append(AlignedSent(['ich', 'fasse', 'das', 'buch', 'zusammen'], ['i', 'summarize', 'the', 'book']))
|
|
130
|
-
>>> bitext.append(AlignedSent(['fasse', 'zusammen'], ['summarize']))
|
|
131
|
-
>>> src_classes = {'the': 0, 'a': 0, 'small': 1, 'big': 1, 'house': 2, 'book': 2, 'is': 3, 'was': 3, 'i': 4, 'summarize': 5 }
|
|
132
|
-
>>> trg_classes = {'das': 0, 'ein': 0, 'haus': 1, 'buch': 1, 'klein': 2, 'groß': 2, 'ist': 3, 'war': 3, 'ja': 4, 'ich': 5, 'fasse': 6, 'zusammen': 6 }
|
|
133
|
-
|
|
134
|
-
>>> ibm4 = IBMModel4(bitext, 5, src_classes, trg_classes)
|
|
135
|
-
|
|
136
|
-
>>> print(round(ibm4.translation_table['buch']['book'], 3))
|
|
137
|
-
1.0
|
|
138
|
-
>>> print(round(ibm4.translation_table['das']['book'], 3))
|
|
139
|
-
0.0
|
|
140
|
-
>>> print(round(ibm4.translation_table['ja'][None], 3))
|
|
141
|
-
1.0
|
|
142
|
-
|
|
143
|
-
>>> print(round(ibm4.head_distortion_table[1][0][1], 3))
|
|
144
|
-
1.0
|
|
145
|
-
>>> print(round(ibm4.head_distortion_table[2][0][1], 3))
|
|
146
|
-
0.0
|
|
147
|
-
>>> print(round(ibm4.non_head_distortion_table[3][6], 3))
|
|
148
|
-
0.5
|
|
149
|
-
|
|
150
|
-
>>> print(round(ibm4.fertility_table[2]['summarize'], 3))
|
|
151
|
-
1.0
|
|
152
|
-
>>> print(round(ibm4.fertility_table[1]['book'], 3))
|
|
153
|
-
1.0
|
|
154
|
-
|
|
155
|
-
>>> print(ibm4.p1)
|
|
156
|
-
0.033...
|
|
157
|
-
|
|
158
|
-
>>> test_sentence = bitext[2]
|
|
159
|
-
>>> test_sentence.words
|
|
160
|
-
['das', 'buch', 'ist', 'ja', 'klein']
|
|
161
|
-
>>> test_sentence.mots
|
|
162
|
-
['the', 'book', 'is', 'small']
|
|
163
|
-
>>> test_sentence.alignment
|
|
164
|
-
Alignment([(0, 0), (1, 1), (2, 2), (3, None), (4, 3)])
|
|
165
|
-
|
|
166
|
-
"""
|
|
167
|
-
|
|
168
|
-
def __init__(self, sentence_aligned_corpus, iterations,
|
|
169
|
-
source_word_classes, target_word_classes,
|
|
170
|
-
probability_tables=None):
|
|
171
|
-
"""
|
|
172
|
-
Train on ``sentence_aligned_corpus`` and create a lexical
|
|
173
|
-
translation model, distortion models, a fertility model, and a
|
|
174
|
-
model for generating NULL-aligned words.
|
|
175
|
-
|
|
176
|
-
Translation direction is from ``AlignedSent.mots`` to
|
|
177
|
-
``AlignedSent.words``.
|
|
178
|
-
|
|
179
|
-
:param sentence_aligned_corpus: Sentence-aligned parallel corpus
|
|
180
|
-
:type sentence_aligned_corpus: list(AlignedSent)
|
|
181
|
-
|
|
182
|
-
:param iterations: Number of iterations to run training algorithm
|
|
183
|
-
:type iterations: int
|
|
184
|
-
|
|
185
|
-
:param source_word_classes: Lookup table that maps a source word
|
|
186
|
-
to its word class, the latter represented by an integer id
|
|
187
|
-
:type source_word_classes: dict[str]: int
|
|
188
|
-
|
|
189
|
-
:param target_word_classes: Lookup table that maps a target word
|
|
190
|
-
to its word class, the latter represented by an integer id
|
|
191
|
-
:type target_word_classes: dict[str]: int
|
|
192
|
-
|
|
193
|
-
:param probability_tables: Optional. Use this to pass in custom
|
|
194
|
-
probability values. If not specified, probabilities will be
|
|
195
|
-
set to a uniform distribution, or some other sensible value.
|
|
196
|
-
If specified, all the following entries must be present:
|
|
197
|
-
``translation_table``, ``alignment_table``,
|
|
198
|
-
``fertility_table``, ``p1``, ``head_distortion_table``,
|
|
199
|
-
``non_head_distortion_table``. See ``IBMModel`` and
|
|
200
|
-
``IBMModel4`` for the type and purpose of these tables.
|
|
201
|
-
:type probability_tables: dict[str]: object
|
|
202
|
-
"""
|
|
203
|
-
super(IBMModel4, self).__init__(sentence_aligned_corpus)
|
|
204
|
-
self.reset_probabilities()
|
|
205
|
-
self.src_classes = source_word_classes
|
|
206
|
-
self.trg_classes = target_word_classes
|
|
207
|
-
|
|
208
|
-
if probability_tables is None:
|
|
209
|
-
# Get probabilities from IBM model 3
|
|
210
|
-
ibm3 = IBMModel3(sentence_aligned_corpus, iterations)
|
|
211
|
-
self.translation_table = ibm3.translation_table
|
|
212
|
-
self.alignment_table = ibm3.alignment_table
|
|
213
|
-
self.fertility_table = ibm3.fertility_table
|
|
214
|
-
self.p1 = ibm3.p1
|
|
215
|
-
self.set_uniform_probabilities(sentence_aligned_corpus)
|
|
216
|
-
else:
|
|
217
|
-
# Set user-defined probabilities
|
|
218
|
-
self.translation_table = probability_tables['translation_table']
|
|
219
|
-
self.alignment_table = probability_tables['alignment_table']
|
|
220
|
-
self.fertility_table = probability_tables['fertility_table']
|
|
221
|
-
self.p1 = probability_tables['p1']
|
|
222
|
-
self.head_distortion_table = probability_tables[
|
|
223
|
-
'head_distortion_table']
|
|
224
|
-
self.non_head_distortion_table = probability_tables[
|
|
225
|
-
'non_head_distortion_table']
|
|
226
|
-
|
|
227
|
-
for n in range(0, iterations):
|
|
228
|
-
self.train(sentence_aligned_corpus)
|
|
229
|
-
|
|
230
|
-
def reset_probabilities(self):
|
|
231
|
-
super(IBMModel4, self).reset_probabilities()
|
|
232
|
-
self.head_distortion_table = defaultdict(
|
|
233
|
-
lambda: defaultdict(lambda: defaultdict(lambda: self.MIN_PROB)))
|
|
234
|
-
"""
|
|
235
|
-
dict[int][int][int]: float. Probability(displacement of head
|
|
236
|
-
word | word class of previous cept,target word class).
|
|
237
|
-
Values accessed as ``distortion_table[dj][src_class][trg_class]``.
|
|
238
|
-
"""
|
|
239
|
-
|
|
240
|
-
self.non_head_distortion_table = defaultdict(
|
|
241
|
-
lambda: defaultdict(lambda: self.MIN_PROB))
|
|
242
|
-
"""
|
|
243
|
-
dict[int][int]: float. Probability(displacement of non-head
|
|
244
|
-
word | target word class).
|
|
245
|
-
Values accessed as ``distortion_table[dj][trg_class]``.
|
|
246
|
-
"""
|
|
247
|
-
|
|
248
|
-
def set_uniform_probabilities(self, sentence_aligned_corpus):
|
|
249
|
-
"""
|
|
250
|
-
Set distortion probabilities uniformly to
|
|
251
|
-
1 / cardinality of displacement values
|
|
252
|
-
"""
|
|
253
|
-
max_m = longest_target_sentence_length(sentence_aligned_corpus)
|
|
254
|
-
|
|
255
|
-
# The maximum displacement is m-1, when a word is in the last
|
|
256
|
-
# position m of the target sentence and the previously placed
|
|
257
|
-
# word is in the first position.
|
|
258
|
-
# Conversely, the minimum displacement is -(m-1).
|
|
259
|
-
# Thus, the displacement range is (m-1) - (-(m-1)). Note that
|
|
260
|
-
# displacement cannot be zero and is not included in the range.
|
|
261
|
-
if max_m <= 1:
|
|
262
|
-
initial_prob = IBMModel.MIN_PROB
|
|
263
|
-
else:
|
|
264
|
-
initial_prob = 1 / (2 * (max_m - 1))
|
|
265
|
-
if initial_prob < IBMModel.MIN_PROB:
|
|
266
|
-
warnings.warn("A target sentence is too long (" + str(max_m) +
|
|
267
|
-
" words). Results may be less accurate.")
|
|
268
|
-
|
|
269
|
-
for dj in range(1, max_m):
|
|
270
|
-
self.head_distortion_table[dj] = defaultdict(
|
|
271
|
-
lambda: defaultdict(lambda: initial_prob))
|
|
272
|
-
self.head_distortion_table[-dj] = defaultdict(
|
|
273
|
-
lambda: defaultdict(lambda: initial_prob))
|
|
274
|
-
self.non_head_distortion_table[dj] = defaultdict(
|
|
275
|
-
lambda: initial_prob)
|
|
276
|
-
self.non_head_distortion_table[-dj] = defaultdict(
|
|
277
|
-
lambda: initial_prob)
|
|
278
|
-
|
|
279
|
-
def train(self, parallel_corpus):
|
|
280
|
-
counts = Model4Counts()
|
|
281
|
-
for aligned_sentence in parallel_corpus:
|
|
282
|
-
m = len(aligned_sentence.words)
|
|
283
|
-
|
|
284
|
-
# Sample the alignment space
|
|
285
|
-
sampled_alignments, best_alignment = self.sample(aligned_sentence)
|
|
286
|
-
# Record the most probable alignment
|
|
287
|
-
aligned_sentence.alignment = Alignment(
|
|
288
|
-
best_alignment.zero_indexed_alignment())
|
|
289
|
-
|
|
290
|
-
# E step (a): Compute normalization factors to weigh counts
|
|
291
|
-
total_count = self.prob_of_alignments(sampled_alignments)
|
|
292
|
-
|
|
293
|
-
# E step (b): Collect counts
|
|
294
|
-
for alignment_info in sampled_alignments:
|
|
295
|
-
count = self.prob_t_a_given_s(alignment_info)
|
|
296
|
-
normalized_count = count / total_count
|
|
297
|
-
|
|
298
|
-
for j in range(1, m + 1):
|
|
299
|
-
counts.update_lexical_translation(
|
|
300
|
-
normalized_count, alignment_info, j)
|
|
301
|
-
counts.update_distortion(
|
|
302
|
-
normalized_count, alignment_info, j,
|
|
303
|
-
self.src_classes, self.trg_classes)
|
|
304
|
-
|
|
305
|
-
counts.update_null_generation(normalized_count, alignment_info)
|
|
306
|
-
counts.update_fertility(normalized_count, alignment_info)
|
|
307
|
-
|
|
308
|
-
# M step: Update probabilities with maximum likelihood estimates
|
|
309
|
-
# If any probability is less than MIN_PROB, clamp it to MIN_PROB
|
|
310
|
-
existing_alignment_table = self.alignment_table
|
|
311
|
-
self.reset_probabilities()
|
|
312
|
-
self.alignment_table = existing_alignment_table # don't retrain
|
|
313
|
-
|
|
314
|
-
self.maximize_lexical_translation_probabilities(counts)
|
|
315
|
-
self.maximize_distortion_probabilities(counts)
|
|
316
|
-
self.maximize_fertility_probabilities(counts)
|
|
317
|
-
self.maximize_null_generation_probabilities(counts)
|
|
318
|
-
|
|
319
|
-
def maximize_distortion_probabilities(self, counts):
|
|
320
|
-
head_d_table = self.head_distortion_table
|
|
321
|
-
for dj, src_classes in counts.head_distortion.items():
|
|
322
|
-
for s_cls, trg_classes in src_classes.items():
|
|
323
|
-
for t_cls in trg_classes:
|
|
324
|
-
estimate = (counts.head_distortion[dj][s_cls][t_cls] /
|
|
325
|
-
counts.head_distortion_for_any_dj[s_cls][t_cls])
|
|
326
|
-
head_d_table[dj][s_cls][t_cls] = max(estimate,
|
|
327
|
-
IBMModel.MIN_PROB)
|
|
328
|
-
|
|
329
|
-
non_head_d_table = self.non_head_distortion_table
|
|
330
|
-
for dj, trg_classes in counts.non_head_distortion.items():
|
|
331
|
-
for t_cls in trg_classes:
|
|
332
|
-
estimate = (counts.non_head_distortion[dj][t_cls] /
|
|
333
|
-
counts.non_head_distortion_for_any_dj[t_cls])
|
|
334
|
-
non_head_d_table[dj][t_cls] = max(estimate, IBMModel.MIN_PROB)
|
|
335
|
-
|
|
336
|
-
def prob_t_a_given_s(self, alignment_info):
|
|
337
|
-
"""
|
|
338
|
-
Probability of target sentence and an alignment given the
|
|
339
|
-
source sentence
|
|
340
|
-
"""
|
|
341
|
-
return IBMModel4.model4_prob_t_a_given_s(alignment_info, self)
|
|
342
|
-
|
|
343
|
-
@staticmethod # exposed for Model 5 to use
|
|
344
|
-
def model4_prob_t_a_given_s(alignment_info, ibm_model):
|
|
345
|
-
probability = 1.0
|
|
346
|
-
MIN_PROB = IBMModel.MIN_PROB
|
|
347
|
-
|
|
348
|
-
def null_generation_term():
|
|
349
|
-
# Binomial distribution: B(m - null_fertility, p1)
|
|
350
|
-
value = 1.0
|
|
351
|
-
p1 = ibm_model.p1
|
|
352
|
-
p0 = 1 - p1
|
|
353
|
-
null_fertility = alignment_info.fertility_of_i(0)
|
|
354
|
-
m = len(alignment_info.trg_sentence) - 1
|
|
355
|
-
value *= (pow(p1, null_fertility) * pow(p0, m - 2 * null_fertility))
|
|
356
|
-
if value < MIN_PROB:
|
|
357
|
-
return MIN_PROB
|
|
358
|
-
|
|
359
|
-
# Combination: (m - null_fertility) choose null_fertility
|
|
360
|
-
for i in range(1, null_fertility + 1):
|
|
361
|
-
value *= (m - null_fertility - i + 1) / i
|
|
362
|
-
return value
|
|
363
|
-
|
|
364
|
-
def fertility_term():
|
|
365
|
-
value = 1.0
|
|
366
|
-
src_sentence = alignment_info.src_sentence
|
|
367
|
-
for i in range(1, len(src_sentence)):
|
|
368
|
-
fertility = alignment_info.fertility_of_i(i)
|
|
369
|
-
value *= (factorial(fertility) *
|
|
370
|
-
ibm_model.fertility_table[fertility][src_sentence[i]])
|
|
371
|
-
if value < MIN_PROB:
|
|
372
|
-
return MIN_PROB
|
|
373
|
-
return value
|
|
374
|
-
|
|
375
|
-
def lexical_translation_term(j):
|
|
376
|
-
t = alignment_info.trg_sentence[j]
|
|
377
|
-
i = alignment_info.alignment[j]
|
|
378
|
-
s = alignment_info.src_sentence[i]
|
|
379
|
-
return ibm_model.translation_table[t][s]
|
|
380
|
-
|
|
381
|
-
def distortion_term(j):
|
|
382
|
-
t = alignment_info.trg_sentence[j]
|
|
383
|
-
i = alignment_info.alignment[j]
|
|
384
|
-
if i == 0:
|
|
385
|
-
# case 1: t is aligned to NULL
|
|
386
|
-
return 1.0
|
|
387
|
-
if alignment_info.is_head_word(j):
|
|
388
|
-
# case 2: t is the first word of a tablet
|
|
389
|
-
previous_cept = alignment_info.previous_cept(j)
|
|
390
|
-
src_class = None
|
|
391
|
-
if previous_cept is not None:
|
|
392
|
-
previous_s = alignment_info.src_sentence[previous_cept]
|
|
393
|
-
src_class = ibm_model.src_classes[previous_s]
|
|
394
|
-
trg_class = ibm_model.trg_classes[t]
|
|
395
|
-
dj = j - alignment_info.center_of_cept(previous_cept)
|
|
396
|
-
return ibm_model.head_distortion_table[dj][src_class][trg_class]
|
|
397
|
-
|
|
398
|
-
# case 3: t is a subsequent word of a tablet
|
|
399
|
-
previous_position = alignment_info.previous_in_tablet(j)
|
|
400
|
-
trg_class = ibm_model.trg_classes[t]
|
|
401
|
-
dj = j - previous_position
|
|
402
|
-
return ibm_model.non_head_distortion_table[dj][trg_class]
|
|
403
|
-
# end nested functions
|
|
404
|
-
|
|
405
|
-
# Abort computation whenever probability falls below MIN_PROB at
|
|
406
|
-
# any point, since MIN_PROB can be considered as zero
|
|
407
|
-
probability *= null_generation_term()
|
|
408
|
-
if probability < MIN_PROB:
|
|
409
|
-
return MIN_PROB
|
|
410
|
-
|
|
411
|
-
probability *= fertility_term()
|
|
412
|
-
if probability < MIN_PROB:
|
|
413
|
-
return MIN_PROB
|
|
414
|
-
|
|
415
|
-
for j in range(1, len(alignment_info.trg_sentence)):
|
|
416
|
-
probability *= lexical_translation_term(j)
|
|
417
|
-
if probability < MIN_PROB:
|
|
418
|
-
return MIN_PROB
|
|
419
|
-
|
|
420
|
-
probability *= distortion_term(j)
|
|
421
|
-
if probability < MIN_PROB:
|
|
422
|
-
return MIN_PROB
|
|
423
|
-
|
|
424
|
-
return probability
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
class Model4Counts(Counts):
|
|
428
|
-
"""
|
|
429
|
-
Data object to store counts of various parameters during training.
|
|
430
|
-
Includes counts for distortion.
|
|
431
|
-
"""
|
|
432
|
-
def __init__(self):
|
|
433
|
-
super(Model4Counts, self).__init__()
|
|
434
|
-
self.head_distortion = defaultdict(
|
|
435
|
-
lambda: defaultdict(lambda: defaultdict(lambda: 0.0)))
|
|
436
|
-
self.head_distortion_for_any_dj = defaultdict(
|
|
437
|
-
lambda: defaultdict(lambda: 0.0))
|
|
438
|
-
self.non_head_distortion = defaultdict(
|
|
439
|
-
lambda: defaultdict(lambda: 0.0))
|
|
440
|
-
self.non_head_distortion_for_any_dj = defaultdict(lambda: 0.0)
|
|
441
|
-
|
|
442
|
-
def update_distortion(self, count, alignment_info, j,
|
|
443
|
-
src_classes, trg_classes):
|
|
444
|
-
i = alignment_info.alignment[j]
|
|
445
|
-
t = alignment_info.trg_sentence[j]
|
|
446
|
-
if i == 0:
|
|
447
|
-
# case 1: t is aligned to NULL
|
|
448
|
-
pass
|
|
449
|
-
elif alignment_info.is_head_word(j):
|
|
450
|
-
# case 2: t is the first word of a tablet
|
|
451
|
-
previous_cept = alignment_info.previous_cept(j)
|
|
452
|
-
if previous_cept is not None:
|
|
453
|
-
previous_src_word = alignment_info.src_sentence[previous_cept]
|
|
454
|
-
src_class = src_classes[previous_src_word]
|
|
455
|
-
else:
|
|
456
|
-
src_class = None
|
|
457
|
-
trg_class = trg_classes[t]
|
|
458
|
-
dj = j - alignment_info.center_of_cept(previous_cept)
|
|
459
|
-
self.head_distortion[dj][src_class][trg_class] += count
|
|
460
|
-
self.head_distortion_for_any_dj[src_class][trg_class] += count
|
|
461
|
-
else:
|
|
462
|
-
# case 3: t is a subsequent word of a tablet
|
|
463
|
-
previous_j = alignment_info.previous_in_tablet(j)
|
|
464
|
-
trg_class = trg_classes[t]
|
|
465
|
-
dj = j - previous_j
|
|
466
|
-
self.non_head_distortion[dj][trg_class] += count
|
|
467
|
-
self.non_head_distortion_for_any_dj[trg_class] += count
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Natural Language Toolkit: IBM Model 4
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
5
|
+
# Author: Tah Wei Hoon <hoon.tw@gmail.com>
|
|
6
|
+
# URL: <http://nltk.org/>
|
|
7
|
+
# For license information, see LICENSE.TXT
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Translation model that reorders output words based on their type and
|
|
11
|
+
distance from other related words in the output sentence.
|
|
12
|
+
|
|
13
|
+
IBM Model 4 improves the distortion model of Model 3, motivated by the
|
|
14
|
+
observation that certain words tend to be re-ordered in a predictable
|
|
15
|
+
way relative to one another. For example, <adjective><noun> in English
|
|
16
|
+
usually has its order flipped as <noun><adjective> in French.
|
|
17
|
+
|
|
18
|
+
Model 4 requires words in the source and target vocabularies to be
|
|
19
|
+
categorized into classes. This can be linguistically driven, like parts
|
|
20
|
+
of speech (adjective, nouns, prepositions, etc). Word classes can also
|
|
21
|
+
be obtained by statistical methods. The original IBM Model 4 uses an
|
|
22
|
+
information theoretic approach to group words into 50 classes for each
|
|
23
|
+
vocabulary.
|
|
24
|
+
|
|
25
|
+
Terminology:
|
|
26
|
+
Cept:
|
|
27
|
+
A source word with non-zero fertility i.e. aligned to one or more
|
|
28
|
+
target words.
|
|
29
|
+
Tablet:
|
|
30
|
+
The set of target word(s) aligned to a cept.
|
|
31
|
+
Head of cept:
|
|
32
|
+
The first word of the tablet of that cept.
|
|
33
|
+
Center of cept:
|
|
34
|
+
The average position of the words in that cept's tablet. If the
|
|
35
|
+
value is not an integer, the ceiling is taken.
|
|
36
|
+
For example, for a tablet with words in positions 2, 5, 6 in the
|
|
37
|
+
target sentence, the center of the corresponding cept is
|
|
38
|
+
ceil((2 + 5 + 6) / 3) = 5
|
|
39
|
+
Displacement:
|
|
40
|
+
For a head word, defined as (position of head word - position of
|
|
41
|
+
previous cept's center). Can be positive or negative.
|
|
42
|
+
For a non-head word, defined as (position of non-head word -
|
|
43
|
+
position of previous word in the same tablet). Always positive,
|
|
44
|
+
because successive words in a tablet are assumed to appear to the
|
|
45
|
+
right of the previous word.
|
|
46
|
+
|
|
47
|
+
In contrast to Model 3 which reorders words in a tablet independently of
|
|
48
|
+
other words, Model 4 distinguishes between three cases.
|
|
49
|
+
(1) Words generated by NULL are distributed uniformly.
|
|
50
|
+
(2) For a head word t, its position is modeled by the probability
|
|
51
|
+
d_head(displacement | word_class_s(s),word_class_t(t)),
|
|
52
|
+
where s is the previous cept, and word_class_s and word_class_t maps
|
|
53
|
+
s and t to a source and target language word class respectively.
|
|
54
|
+
(3) For a non-head word t, its position is modeled by the probability
|
|
55
|
+
d_non_head(displacement | word_class_t(t))
|
|
56
|
+
|
|
57
|
+
The EM algorithm used in Model 4 is:
|
|
58
|
+
E step - In the training data, collect counts, weighted by prior
|
|
59
|
+
probabilities.
|
|
60
|
+
(a) count how many times a source language word is translated
|
|
61
|
+
into a target language word
|
|
62
|
+
(b) for a particular word class, count how many times a head
|
|
63
|
+
word is located at a particular displacement from the
|
|
64
|
+
previous cept's center
|
|
65
|
+
(c) for a particular word class, count how many times a
|
|
66
|
+
non-head word is located at a particular displacement from
|
|
67
|
+
the previous target word
|
|
68
|
+
(d) count how many times a source word is aligned to phi number
|
|
69
|
+
of target words
|
|
70
|
+
(e) count how many times NULL is aligned to a target word
|
|
71
|
+
|
|
72
|
+
M step - Estimate new probabilities based on the counts from the E step
|
|
73
|
+
|
|
74
|
+
Like Model 3, there are too many possible alignments to consider. Thus,
|
|
75
|
+
a hill climbing approach is used to sample good candidates.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
Notations:
|
|
79
|
+
i: Position in the source sentence
|
|
80
|
+
Valid values are 0 (for NULL), 1, 2, ..., length of source sentence
|
|
81
|
+
j: Position in the target sentence
|
|
82
|
+
Valid values are 1, 2, ..., length of target sentence
|
|
83
|
+
l: Number of words in the source sentence, excluding NULL
|
|
84
|
+
m: Number of words in the target sentence
|
|
85
|
+
s: A word in the source language
|
|
86
|
+
t: A word in the target language
|
|
87
|
+
phi: Fertility, the number of target words produced by a source word
|
|
88
|
+
p1: Probability that a target word produced by a source word is
|
|
89
|
+
accompanied by another target word that is aligned to NULL
|
|
90
|
+
p0: 1 - p1
|
|
91
|
+
dj: Displacement, Δj
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
References:
|
|
95
|
+
Philipp Koehn. 2010. Statistical Machine Translation.
|
|
96
|
+
Cambridge University Press, New York.
|
|
97
|
+
|
|
98
|
+
Peter E Brown, Stephen A. Della Pietra, Vincent J. Della Pietra, and
|
|
99
|
+
Robert L. Mercer. 1993. The Mathematics of Statistical Machine
|
|
100
|
+
Translation: Parameter Estimation. Computational Linguistics, 19 (2),
|
|
101
|
+
263-311.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
from __future__ import division
|
|
105
|
+
from collections import defaultdict
|
|
106
|
+
from math import factorial
|
|
107
|
+
from nltk.translate import AlignedSent
|
|
108
|
+
from nltk.translate import Alignment
|
|
109
|
+
from nltk.translate import IBMModel
|
|
110
|
+
from nltk.translate import IBMModel3
|
|
111
|
+
from nltk.translate.ibm_model import Counts
|
|
112
|
+
from nltk.translate.ibm_model import longest_target_sentence_length
|
|
113
|
+
import warnings
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class IBMModel4(IBMModel):
|
|
117
|
+
"""
|
|
118
|
+
Translation model that reorders output words based on their type and
|
|
119
|
+
their distance from other related words in the output sentence
|
|
120
|
+
|
|
121
|
+
>>> bitext = []
|
|
122
|
+
>>> bitext.append(AlignedSent(['klein', 'ist', 'das', 'haus'], ['the', 'house', 'is', 'small']))
|
|
123
|
+
>>> bitext.append(AlignedSent(['das', 'haus', 'war', 'ja', 'groß'], ['the', 'house', 'was', 'big']))
|
|
124
|
+
>>> bitext.append(AlignedSent(['das', 'buch', 'ist', 'ja', 'klein'], ['the', 'book', 'is', 'small']))
|
|
125
|
+
>>> bitext.append(AlignedSent(['ein', 'haus', 'ist', 'klein'], ['a', 'house', 'is', 'small']))
|
|
126
|
+
>>> bitext.append(AlignedSent(['das', 'haus'], ['the', 'house']))
|
|
127
|
+
>>> bitext.append(AlignedSent(['das', 'buch'], ['the', 'book']))
|
|
128
|
+
>>> bitext.append(AlignedSent(['ein', 'buch'], ['a', 'book']))
|
|
129
|
+
>>> bitext.append(AlignedSent(['ich', 'fasse', 'das', 'buch', 'zusammen'], ['i', 'summarize', 'the', 'book']))
|
|
130
|
+
>>> bitext.append(AlignedSent(['fasse', 'zusammen'], ['summarize']))
|
|
131
|
+
>>> src_classes = {'the': 0, 'a': 0, 'small': 1, 'big': 1, 'house': 2, 'book': 2, 'is': 3, 'was': 3, 'i': 4, 'summarize': 5 }
|
|
132
|
+
>>> trg_classes = {'das': 0, 'ein': 0, 'haus': 1, 'buch': 1, 'klein': 2, 'groß': 2, 'ist': 3, 'war': 3, 'ja': 4, 'ich': 5, 'fasse': 6, 'zusammen': 6 }
|
|
133
|
+
|
|
134
|
+
>>> ibm4 = IBMModel4(bitext, 5, src_classes, trg_classes)
|
|
135
|
+
|
|
136
|
+
>>> print(round(ibm4.translation_table['buch']['book'], 3))
|
|
137
|
+
1.0
|
|
138
|
+
>>> print(round(ibm4.translation_table['das']['book'], 3))
|
|
139
|
+
0.0
|
|
140
|
+
>>> print(round(ibm4.translation_table['ja'][None], 3))
|
|
141
|
+
1.0
|
|
142
|
+
|
|
143
|
+
>>> print(round(ibm4.head_distortion_table[1][0][1], 3))
|
|
144
|
+
1.0
|
|
145
|
+
>>> print(round(ibm4.head_distortion_table[2][0][1], 3))
|
|
146
|
+
0.0
|
|
147
|
+
>>> print(round(ibm4.non_head_distortion_table[3][6], 3))
|
|
148
|
+
0.5
|
|
149
|
+
|
|
150
|
+
>>> print(round(ibm4.fertility_table[2]['summarize'], 3))
|
|
151
|
+
1.0
|
|
152
|
+
>>> print(round(ibm4.fertility_table[1]['book'], 3))
|
|
153
|
+
1.0
|
|
154
|
+
|
|
155
|
+
>>> print(ibm4.p1)
|
|
156
|
+
0.033...
|
|
157
|
+
|
|
158
|
+
>>> test_sentence = bitext[2]
|
|
159
|
+
>>> test_sentence.words
|
|
160
|
+
['das', 'buch', 'ist', 'ja', 'klein']
|
|
161
|
+
>>> test_sentence.mots
|
|
162
|
+
['the', 'book', 'is', 'small']
|
|
163
|
+
>>> test_sentence.alignment
|
|
164
|
+
Alignment([(0, 0), (1, 1), (2, 2), (3, None), (4, 3)])
|
|
165
|
+
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def __init__(self, sentence_aligned_corpus, iterations,
|
|
169
|
+
source_word_classes, target_word_classes,
|
|
170
|
+
probability_tables=None):
|
|
171
|
+
"""
|
|
172
|
+
Train on ``sentence_aligned_corpus`` and create a lexical
|
|
173
|
+
translation model, distortion models, a fertility model, and a
|
|
174
|
+
model for generating NULL-aligned words.
|
|
175
|
+
|
|
176
|
+
Translation direction is from ``AlignedSent.mots`` to
|
|
177
|
+
``AlignedSent.words``.
|
|
178
|
+
|
|
179
|
+
:param sentence_aligned_corpus: Sentence-aligned parallel corpus
|
|
180
|
+
:type sentence_aligned_corpus: list(AlignedSent)
|
|
181
|
+
|
|
182
|
+
:param iterations: Number of iterations to run training algorithm
|
|
183
|
+
:type iterations: int
|
|
184
|
+
|
|
185
|
+
:param source_word_classes: Lookup table that maps a source word
|
|
186
|
+
to its word class, the latter represented by an integer id
|
|
187
|
+
:type source_word_classes: dict[str]: int
|
|
188
|
+
|
|
189
|
+
:param target_word_classes: Lookup table that maps a target word
|
|
190
|
+
to its word class, the latter represented by an integer id
|
|
191
|
+
:type target_word_classes: dict[str]: int
|
|
192
|
+
|
|
193
|
+
:param probability_tables: Optional. Use this to pass in custom
|
|
194
|
+
probability values. If not specified, probabilities will be
|
|
195
|
+
set to a uniform distribution, or some other sensible value.
|
|
196
|
+
If specified, all the following entries must be present:
|
|
197
|
+
``translation_table``, ``alignment_table``,
|
|
198
|
+
``fertility_table``, ``p1``, ``head_distortion_table``,
|
|
199
|
+
``non_head_distortion_table``. See ``IBMModel`` and
|
|
200
|
+
``IBMModel4`` for the type and purpose of these tables.
|
|
201
|
+
:type probability_tables: dict[str]: object
|
|
202
|
+
"""
|
|
203
|
+
super(IBMModel4, self).__init__(sentence_aligned_corpus)
|
|
204
|
+
self.reset_probabilities()
|
|
205
|
+
self.src_classes = source_word_classes
|
|
206
|
+
self.trg_classes = target_word_classes
|
|
207
|
+
|
|
208
|
+
if probability_tables is None:
|
|
209
|
+
# Get probabilities from IBM model 3
|
|
210
|
+
ibm3 = IBMModel3(sentence_aligned_corpus, iterations)
|
|
211
|
+
self.translation_table = ibm3.translation_table
|
|
212
|
+
self.alignment_table = ibm3.alignment_table
|
|
213
|
+
self.fertility_table = ibm3.fertility_table
|
|
214
|
+
self.p1 = ibm3.p1
|
|
215
|
+
self.set_uniform_probabilities(sentence_aligned_corpus)
|
|
216
|
+
else:
|
|
217
|
+
# Set user-defined probabilities
|
|
218
|
+
self.translation_table = probability_tables['translation_table']
|
|
219
|
+
self.alignment_table = probability_tables['alignment_table']
|
|
220
|
+
self.fertility_table = probability_tables['fertility_table']
|
|
221
|
+
self.p1 = probability_tables['p1']
|
|
222
|
+
self.head_distortion_table = probability_tables[
|
|
223
|
+
'head_distortion_table']
|
|
224
|
+
self.non_head_distortion_table = probability_tables[
|
|
225
|
+
'non_head_distortion_table']
|
|
226
|
+
|
|
227
|
+
for n in range(0, iterations):
|
|
228
|
+
self.train(sentence_aligned_corpus)
|
|
229
|
+
|
|
230
|
+
def reset_probabilities(self):
|
|
231
|
+
super(IBMModel4, self).reset_probabilities()
|
|
232
|
+
self.head_distortion_table = defaultdict(
|
|
233
|
+
lambda: defaultdict(lambda: defaultdict(lambda: self.MIN_PROB)))
|
|
234
|
+
"""
|
|
235
|
+
dict[int][int][int]: float. Probability(displacement of head
|
|
236
|
+
word | word class of previous cept,target word class).
|
|
237
|
+
Values accessed as ``distortion_table[dj][src_class][trg_class]``.
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
self.non_head_distortion_table = defaultdict(
|
|
241
|
+
lambda: defaultdict(lambda: self.MIN_PROB))
|
|
242
|
+
"""
|
|
243
|
+
dict[int][int]: float. Probability(displacement of non-head
|
|
244
|
+
word | target word class).
|
|
245
|
+
Values accessed as ``distortion_table[dj][trg_class]``.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
def set_uniform_probabilities(self, sentence_aligned_corpus):
|
|
249
|
+
"""
|
|
250
|
+
Set distortion probabilities uniformly to
|
|
251
|
+
1 / cardinality of displacement values
|
|
252
|
+
"""
|
|
253
|
+
max_m = longest_target_sentence_length(sentence_aligned_corpus)
|
|
254
|
+
|
|
255
|
+
# The maximum displacement is m-1, when a word is in the last
|
|
256
|
+
# position m of the target sentence and the previously placed
|
|
257
|
+
# word is in the first position.
|
|
258
|
+
# Conversely, the minimum displacement is -(m-1).
|
|
259
|
+
# Thus, the displacement range is (m-1) - (-(m-1)). Note that
|
|
260
|
+
# displacement cannot be zero and is not included in the range.
|
|
261
|
+
if max_m <= 1:
|
|
262
|
+
initial_prob = IBMModel.MIN_PROB
|
|
263
|
+
else:
|
|
264
|
+
initial_prob = 1 / (2 * (max_m - 1))
|
|
265
|
+
if initial_prob < IBMModel.MIN_PROB:
|
|
266
|
+
warnings.warn("A target sentence is too long (" + str(max_m) +
|
|
267
|
+
" words). Results may be less accurate.")
|
|
268
|
+
|
|
269
|
+
for dj in range(1, max_m):
|
|
270
|
+
self.head_distortion_table[dj] = defaultdict(
|
|
271
|
+
lambda: defaultdict(lambda: initial_prob))
|
|
272
|
+
self.head_distortion_table[-dj] = defaultdict(
|
|
273
|
+
lambda: defaultdict(lambda: initial_prob))
|
|
274
|
+
self.non_head_distortion_table[dj] = defaultdict(
|
|
275
|
+
lambda: initial_prob)
|
|
276
|
+
self.non_head_distortion_table[-dj] = defaultdict(
|
|
277
|
+
lambda: initial_prob)
|
|
278
|
+
|
|
279
|
+
def train(self, parallel_corpus):
|
|
280
|
+
counts = Model4Counts()
|
|
281
|
+
for aligned_sentence in parallel_corpus:
|
|
282
|
+
m = len(aligned_sentence.words)
|
|
283
|
+
|
|
284
|
+
# Sample the alignment space
|
|
285
|
+
sampled_alignments, best_alignment = self.sample(aligned_sentence)
|
|
286
|
+
# Record the most probable alignment
|
|
287
|
+
aligned_sentence.alignment = Alignment(
|
|
288
|
+
best_alignment.zero_indexed_alignment())
|
|
289
|
+
|
|
290
|
+
# E step (a): Compute normalization factors to weigh counts
|
|
291
|
+
total_count = self.prob_of_alignments(sampled_alignments)
|
|
292
|
+
|
|
293
|
+
# E step (b): Collect counts
|
|
294
|
+
for alignment_info in sampled_alignments:
|
|
295
|
+
count = self.prob_t_a_given_s(alignment_info)
|
|
296
|
+
normalized_count = count / total_count
|
|
297
|
+
|
|
298
|
+
for j in range(1, m + 1):
|
|
299
|
+
counts.update_lexical_translation(
|
|
300
|
+
normalized_count, alignment_info, j)
|
|
301
|
+
counts.update_distortion(
|
|
302
|
+
normalized_count, alignment_info, j,
|
|
303
|
+
self.src_classes, self.trg_classes)
|
|
304
|
+
|
|
305
|
+
counts.update_null_generation(normalized_count, alignment_info)
|
|
306
|
+
counts.update_fertility(normalized_count, alignment_info)
|
|
307
|
+
|
|
308
|
+
# M step: Update probabilities with maximum likelihood estimates
|
|
309
|
+
# If any probability is less than MIN_PROB, clamp it to MIN_PROB
|
|
310
|
+
existing_alignment_table = self.alignment_table
|
|
311
|
+
self.reset_probabilities()
|
|
312
|
+
self.alignment_table = existing_alignment_table # don't retrain
|
|
313
|
+
|
|
314
|
+
self.maximize_lexical_translation_probabilities(counts)
|
|
315
|
+
self.maximize_distortion_probabilities(counts)
|
|
316
|
+
self.maximize_fertility_probabilities(counts)
|
|
317
|
+
self.maximize_null_generation_probabilities(counts)
|
|
318
|
+
|
|
319
|
+
def maximize_distortion_probabilities(self, counts):
|
|
320
|
+
head_d_table = self.head_distortion_table
|
|
321
|
+
for dj, src_classes in counts.head_distortion.items():
|
|
322
|
+
for s_cls, trg_classes in src_classes.items():
|
|
323
|
+
for t_cls in trg_classes:
|
|
324
|
+
estimate = (counts.head_distortion[dj][s_cls][t_cls] /
|
|
325
|
+
counts.head_distortion_for_any_dj[s_cls][t_cls])
|
|
326
|
+
head_d_table[dj][s_cls][t_cls] = max(estimate,
|
|
327
|
+
IBMModel.MIN_PROB)
|
|
328
|
+
|
|
329
|
+
non_head_d_table = self.non_head_distortion_table
|
|
330
|
+
for dj, trg_classes in counts.non_head_distortion.items():
|
|
331
|
+
for t_cls in trg_classes:
|
|
332
|
+
estimate = (counts.non_head_distortion[dj][t_cls] /
|
|
333
|
+
counts.non_head_distortion_for_any_dj[t_cls])
|
|
334
|
+
non_head_d_table[dj][t_cls] = max(estimate, IBMModel.MIN_PROB)
|
|
335
|
+
|
|
336
|
+
def prob_t_a_given_s(self, alignment_info):
|
|
337
|
+
"""
|
|
338
|
+
Probability of target sentence and an alignment given the
|
|
339
|
+
source sentence
|
|
340
|
+
"""
|
|
341
|
+
return IBMModel4.model4_prob_t_a_given_s(alignment_info, self)
|
|
342
|
+
|
|
343
|
+
@staticmethod # exposed for Model 5 to use
|
|
344
|
+
def model4_prob_t_a_given_s(alignment_info, ibm_model):
|
|
345
|
+
probability = 1.0
|
|
346
|
+
MIN_PROB = IBMModel.MIN_PROB
|
|
347
|
+
|
|
348
|
+
def null_generation_term():
|
|
349
|
+
# Binomial distribution: B(m - null_fertility, p1)
|
|
350
|
+
value = 1.0
|
|
351
|
+
p1 = ibm_model.p1
|
|
352
|
+
p0 = 1 - p1
|
|
353
|
+
null_fertility = alignment_info.fertility_of_i(0)
|
|
354
|
+
m = len(alignment_info.trg_sentence) - 1
|
|
355
|
+
value *= (pow(p1, null_fertility) * pow(p0, m - 2 * null_fertility))
|
|
356
|
+
if value < MIN_PROB:
|
|
357
|
+
return MIN_PROB
|
|
358
|
+
|
|
359
|
+
# Combination: (m - null_fertility) choose null_fertility
|
|
360
|
+
for i in range(1, null_fertility + 1):
|
|
361
|
+
value *= (m - null_fertility - i + 1) / i
|
|
362
|
+
return value
|
|
363
|
+
|
|
364
|
+
def fertility_term():
|
|
365
|
+
value = 1.0
|
|
366
|
+
src_sentence = alignment_info.src_sentence
|
|
367
|
+
for i in range(1, len(src_sentence)):
|
|
368
|
+
fertility = alignment_info.fertility_of_i(i)
|
|
369
|
+
value *= (factorial(fertility) *
|
|
370
|
+
ibm_model.fertility_table[fertility][src_sentence[i]])
|
|
371
|
+
if value < MIN_PROB:
|
|
372
|
+
return MIN_PROB
|
|
373
|
+
return value
|
|
374
|
+
|
|
375
|
+
def lexical_translation_term(j):
|
|
376
|
+
t = alignment_info.trg_sentence[j]
|
|
377
|
+
i = alignment_info.alignment[j]
|
|
378
|
+
s = alignment_info.src_sentence[i]
|
|
379
|
+
return ibm_model.translation_table[t][s]
|
|
380
|
+
|
|
381
|
+
def distortion_term(j):
|
|
382
|
+
t = alignment_info.trg_sentence[j]
|
|
383
|
+
i = alignment_info.alignment[j]
|
|
384
|
+
if i == 0:
|
|
385
|
+
# case 1: t is aligned to NULL
|
|
386
|
+
return 1.0
|
|
387
|
+
if alignment_info.is_head_word(j):
|
|
388
|
+
# case 2: t is the first word of a tablet
|
|
389
|
+
previous_cept = alignment_info.previous_cept(j)
|
|
390
|
+
src_class = None
|
|
391
|
+
if previous_cept is not None:
|
|
392
|
+
previous_s = alignment_info.src_sentence[previous_cept]
|
|
393
|
+
src_class = ibm_model.src_classes[previous_s]
|
|
394
|
+
trg_class = ibm_model.trg_classes[t]
|
|
395
|
+
dj = j - alignment_info.center_of_cept(previous_cept)
|
|
396
|
+
return ibm_model.head_distortion_table[dj][src_class][trg_class]
|
|
397
|
+
|
|
398
|
+
# case 3: t is a subsequent word of a tablet
|
|
399
|
+
previous_position = alignment_info.previous_in_tablet(j)
|
|
400
|
+
trg_class = ibm_model.trg_classes[t]
|
|
401
|
+
dj = j - previous_position
|
|
402
|
+
return ibm_model.non_head_distortion_table[dj][trg_class]
|
|
403
|
+
# end nested functions
|
|
404
|
+
|
|
405
|
+
# Abort computation whenever probability falls below MIN_PROB at
|
|
406
|
+
# any point, since MIN_PROB can be considered as zero
|
|
407
|
+
probability *= null_generation_term()
|
|
408
|
+
if probability < MIN_PROB:
|
|
409
|
+
return MIN_PROB
|
|
410
|
+
|
|
411
|
+
probability *= fertility_term()
|
|
412
|
+
if probability < MIN_PROB:
|
|
413
|
+
return MIN_PROB
|
|
414
|
+
|
|
415
|
+
for j in range(1, len(alignment_info.trg_sentence)):
|
|
416
|
+
probability *= lexical_translation_term(j)
|
|
417
|
+
if probability < MIN_PROB:
|
|
418
|
+
return MIN_PROB
|
|
419
|
+
|
|
420
|
+
probability *= distortion_term(j)
|
|
421
|
+
if probability < MIN_PROB:
|
|
422
|
+
return MIN_PROB
|
|
423
|
+
|
|
424
|
+
return probability
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class Model4Counts(Counts):
|
|
428
|
+
"""
|
|
429
|
+
Data object to store counts of various parameters during training.
|
|
430
|
+
Includes counts for distortion.
|
|
431
|
+
"""
|
|
432
|
+
def __init__(self):
|
|
433
|
+
super(Model4Counts, self).__init__()
|
|
434
|
+
self.head_distortion = defaultdict(
|
|
435
|
+
lambda: defaultdict(lambda: defaultdict(lambda: 0.0)))
|
|
436
|
+
self.head_distortion_for_any_dj = defaultdict(
|
|
437
|
+
lambda: defaultdict(lambda: 0.0))
|
|
438
|
+
self.non_head_distortion = defaultdict(
|
|
439
|
+
lambda: defaultdict(lambda: 0.0))
|
|
440
|
+
self.non_head_distortion_for_any_dj = defaultdict(lambda: 0.0)
|
|
441
|
+
|
|
442
|
+
def update_distortion(self, count, alignment_info, j,
|
|
443
|
+
src_classes, trg_classes):
|
|
444
|
+
i = alignment_info.alignment[j]
|
|
445
|
+
t = alignment_info.trg_sentence[j]
|
|
446
|
+
if i == 0:
|
|
447
|
+
# case 1: t is aligned to NULL
|
|
448
|
+
pass
|
|
449
|
+
elif alignment_info.is_head_word(j):
|
|
450
|
+
# case 2: t is the first word of a tablet
|
|
451
|
+
previous_cept = alignment_info.previous_cept(j)
|
|
452
|
+
if previous_cept is not None:
|
|
453
|
+
previous_src_word = alignment_info.src_sentence[previous_cept]
|
|
454
|
+
src_class = src_classes[previous_src_word]
|
|
455
|
+
else:
|
|
456
|
+
src_class = None
|
|
457
|
+
trg_class = trg_classes[t]
|
|
458
|
+
dj = j - alignment_info.center_of_cept(previous_cept)
|
|
459
|
+
self.head_distortion[dj][src_class][trg_class] += count
|
|
460
|
+
self.head_distortion_for_any_dj[src_class][trg_class] += count
|
|
461
|
+
else:
|
|
462
|
+
# case 3: t is a subsequent word of a tablet
|
|
463
|
+
previous_j = alignment_info.previous_in_tablet(j)
|
|
464
|
+
trg_class = trg_classes[t]
|
|
465
|
+
dj = j - previous_j
|
|
466
|
+
self.non_head_distortion[dj][trg_class] += count
|
|
467
|
+
self.non_head_distortion_for_any_dj[trg_class] += count
|