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.
Files changed (406) hide show
  1. {nltk-3.2 → nltk-3.3}/INSTALL.txt +6 -6
  2. {nltk-3.2 → nltk-3.3}/LICENSE.txt +13 -13
  3. {nltk-3.2 → nltk-3.3}/MANIFEST.in +6 -6
  4. {nltk-3.2/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
  5. nltk-3.2/README.txt → nltk-3.3/README.md +49 -48
  6. nltk-3.3/nltk/VERSION +1 -0
  7. {nltk-3.2 → nltk-3.3}/nltk/__init__.py +185 -185
  8. {nltk-3.2 → nltk-3.3}/nltk/app/__init__.py +52 -53
  9. {nltk-3.2 → nltk-3.3}/nltk/app/chartparser_app.py +2276 -2276
  10. {nltk-3.2 → nltk-3.3}/nltk/app/chunkparser_app.py +1262 -1264
  11. {nltk-3.2 → nltk-3.3}/nltk/app/collocations_app.py +347 -350
  12. {nltk-3.2 → nltk-3.3}/nltk/app/concordance_app.py +568 -570
  13. {nltk-3.2 → nltk-3.3}/nltk/app/nemo_app.py +156 -155
  14. {nltk-3.2 → nltk-3.3}/nltk/app/rdparser_app.py +892 -894
  15. {nltk-3.2 → nltk-3.3}/nltk/app/srparser_app.py +809 -809
  16. {nltk-3.2 → nltk-3.3}/nltk/app/wordfreq_app.py +32 -32
  17. {nltk-3.2 → nltk-3.3}/nltk/app/wordnet_app.py +968 -968
  18. {nltk-3.2 → nltk-3.3}/nltk/book.py +91 -90
  19. {nltk-3.2 → nltk-3.3}/nltk/ccg/__init__.py +22 -22
  20. {nltk-3.2 → nltk-3.3}/nltk/ccg/api.py +359 -335
  21. {nltk-3.2 → nltk-3.3}/nltk/ccg/chart.py +394 -361
  22. {nltk-3.2 → nltk-3.3}/nltk/ccg/combinator.py +343 -312
  23. {nltk-3.2 → nltk-3.3}/nltk/ccg/lexicon.py +328 -290
  24. nltk-3.3/nltk/ccg/logic.py +46 -0
  25. {nltk-3.2 → nltk-3.3}/nltk/chat/__init__.py +49 -49
  26. {nltk-3.2 → nltk-3.3}/nltk/chat/eliza.py +244 -244
  27. {nltk-3.2 → nltk-3.3}/nltk/chat/iesha.py +140 -140
  28. {nltk-3.2 → nltk-3.3}/nltk/chat/rude.py +92 -92
  29. {nltk-3.2 → nltk-3.3}/nltk/chat/suntsu.py +117 -117
  30. {nltk-3.2 → nltk-3.3}/nltk/chat/util.py +122 -120
  31. {nltk-3.2 → nltk-3.3}/nltk/chat/zen.py +282 -282
  32. {nltk-3.2 → nltk-3.3}/nltk/chunk/__init__.py +190 -190
  33. {nltk-3.2 → nltk-3.3}/nltk/chunk/api.py +51 -51
  34. {nltk-3.2 → nltk-3.3}/nltk/chunk/named_entity.py +331 -331
  35. {nltk-3.2 → nltk-3.3}/nltk/chunk/regexp.py +1390 -1384
  36. {nltk-3.2 → nltk-3.3}/nltk/chunk/util.py +600 -600
  37. {nltk-3.2 → nltk-3.3}/nltk/classify/__init__.py +98 -98
  38. {nltk-3.2 → nltk-3.3}/nltk/classify/api.py +193 -193
  39. {nltk-3.2 → nltk-3.3}/nltk/classify/decisiontree.py +295 -295
  40. {nltk-3.2 → nltk-3.3}/nltk/classify/maxent.py +1510 -1492
  41. {nltk-3.2 → nltk-3.3}/nltk/classify/megam.py +179 -178
  42. {nltk-3.2 → nltk-3.3}/nltk/classify/naivebayes.py +245 -242
  43. {nltk-3.2 → nltk-3.3}/nltk/classify/positivenaivebayes.py +170 -170
  44. {nltk-3.2 → nltk-3.3}/nltk/classify/rte_classify.py +160 -191
  45. {nltk-3.2 → nltk-3.3}/nltk/classify/scikitlearn.py +153 -151
  46. {nltk-3.2 → nltk-3.3}/nltk/classify/senna.py +183 -181
  47. {nltk-3.2 → nltk-3.3}/nltk/classify/svm.py +15 -15
  48. {nltk-3.2 → nltk-3.3}/nltk/classify/tadm.py +113 -112
  49. {nltk-3.2 → nltk-3.3}/nltk/classify/textcat.py +193 -193
  50. {nltk-3.2 → nltk-3.3}/nltk/classify/util.py +324 -312
  51. {nltk-3.2 → nltk-3.3}/nltk/classify/weka.py +346 -345
  52. {nltk-3.2 → nltk-3.3}/nltk/cluster/__init__.py +86 -86
  53. {nltk-3.2 → nltk-3.3}/nltk/cluster/api.py +74 -70
  54. {nltk-3.2 → nltk-3.3}/nltk/cluster/em.py +247 -247
  55. {nltk-3.2 → nltk-3.3}/nltk/cluster/gaac.py +168 -168
  56. {nltk-3.2 → nltk-3.3}/nltk/cluster/kmeans.py +221 -221
  57. {nltk-3.2 → nltk-3.3}/nltk/cluster/util.py +304 -289
  58. nltk-3.3/nltk/collections.py +640 -0
  59. {nltk-3.2 → nltk-3.3}/nltk/collocations.py +388 -388
  60. nltk-3.3/nltk/compat.py +365 -0
  61. {nltk-3.2 → nltk-3.3}/nltk/corpus/__init__.py +341 -320
  62. {nltk-3.2 → nltk-3.3}/nltk/corpus/europarl_raw.py +44 -44
  63. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/__init__.py +147 -145
  64. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/aligned.py +115 -114
  65. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/api.py +448 -446
  66. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bnc.py +252 -252
  67. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +227 -227
  68. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +179 -178
  69. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chasen.py +140 -139
  70. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/childes.py +522 -494
  71. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chunked.py +212 -212
  72. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/cmudict.py +97 -95
  73. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +280 -278
  74. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/conll.py +528 -521
  75. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/crubadan.py +116 -116
  76. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/dependency.py +101 -101
  77. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/framenet.py +3059 -2093
  78. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ieer.py +112 -111
  79. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/indian.py +85 -86
  80. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ipipan.py +332 -331
  81. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/knbc.py +187 -187
  82. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/lin.py +156 -156
  83. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/mte.py +311 -310
  84. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nkjp.py +429 -428
  85. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nombank.py +421 -421
  86. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +73 -73
  87. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +115 -115
  88. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +165 -165
  89. nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
  90. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/plaintext.py +232 -233
  91. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ppattach.py +96 -95
  92. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/propbank.py +479 -481
  93. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +128 -126
  94. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/reviews.py +330 -328
  95. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/rte.py +144 -146
  96. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/semcor.py +256 -256
  97. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/senseval.py +203 -201
  98. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +137 -137
  99. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +75 -75
  100. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/string_category.py +60 -59
  101. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/switchboard.py +119 -119
  102. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/tagged.py +295 -294
  103. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/timit.py +452 -450
  104. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/toolbox.py +68 -68
  105. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/twitter.py +155 -157
  106. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/udhr.py +80 -80
  107. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/util.py +804 -800
  108. nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
  109. nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
  110. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/wordnet.py +2108 -2036
  111. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +392 -387
  112. {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ycoe.py +243 -242
  113. {nltk-3.2 → nltk-3.3}/nltk/corpus/util.py +144 -127
  114. {nltk-3.2 → nltk-3.3}/nltk/data.py +1487 -1451
  115. {nltk-3.2 → nltk-3.3}/nltk/decorators.py +219 -215
  116. {nltk-3.2 → nltk-3.3}/nltk/downloader.py +2278 -2274
  117. {nltk-3.2 → nltk-3.3}/nltk/draw/__init__.py +27 -27
  118. {nltk-3.2 → nltk-3.3}/nltk/draw/cfg.py +774 -777
  119. {nltk-3.2 → nltk-3.3}/nltk/draw/dispersion.py +58 -58
  120. {nltk-3.2 → nltk-3.3}/nltk/draw/table.py +1098 -1098
  121. {nltk-3.2 → nltk-3.3}/nltk/draw/tree.py +963 -966
  122. {nltk-3.2 → nltk-3.3}/nltk/draw/util.py +2356 -2356
  123. {nltk-3.2 → nltk-3.3}/nltk/featstruct.py +2617 -2500
  124. {nltk-3.2 → nltk-3.3}/nltk/grammar.py +1559 -1516
  125. {nltk-3.2 → nltk-3.3}/nltk/help.py +56 -56
  126. {nltk-3.2 → nltk-3.3}/nltk/inference/__init__.py +20 -20
  127. {nltk-3.2 → nltk-3.3}/nltk/inference/api.py +597 -589
  128. {nltk-3.2 → nltk-3.3}/nltk/inference/discourse.py +612 -608
  129. {nltk-3.2 → nltk-3.3}/nltk/inference/mace.py +311 -311
  130. {nltk-3.2 → nltk-3.3}/nltk/inference/nonmonotonic.py +509 -509
  131. {nltk-3.2 → nltk-3.3}/nltk/inference/prover9.py +431 -431
  132. {nltk-3.2 → nltk-3.3}/nltk/inference/resolution.py +687 -687
  133. {nltk-3.2 → nltk-3.3}/nltk/inference/tableau.py +607 -607
  134. {nltk-3.2 → nltk-3.3}/nltk/internals.py +982 -982
  135. {nltk-3.2 → nltk-3.3}/nltk/jsontags.py +63 -63
  136. {nltk-3.2 → nltk-3.3}/nltk/lazyimport.py +142 -142
  137. {nltk-3.2 → nltk-3.3}/nltk/metrics/__init__.py +30 -29
  138. {nltk-3.2 → nltk-3.3}/nltk/metrics/agreement.py +421 -401
  139. nltk-3.3/nltk/metrics/aline.py +607 -0
  140. {nltk-3.2 → nltk-3.3}/nltk/metrics/association.py +414 -410
  141. {nltk-3.2 → nltk-3.3}/nltk/metrics/confusionmatrix.py +206 -206
  142. {nltk-3.2 → nltk-3.3}/nltk/metrics/distance.py +207 -202
  143. {nltk-3.2 → nltk-3.3}/nltk/metrics/paice.py +381 -381
  144. {nltk-3.2 → nltk-3.3}/nltk/metrics/scores.py +228 -228
  145. {nltk-3.2 → nltk-3.3}/nltk/metrics/segmentation.py +231 -232
  146. {nltk-3.2 → nltk-3.3}/nltk/metrics/spearman.py +69 -69
  147. {nltk-3.2 → nltk-3.3}/nltk/misc/__init__.py +11 -11
  148. {nltk-3.2 → nltk-3.3}/nltk/misc/babelfish.py +10 -10
  149. {nltk-3.2 → nltk-3.3}/nltk/misc/chomsky.py +135 -133
  150. {nltk-3.2 → nltk-3.3}/nltk/misc/minimalset.py +83 -83
  151. {nltk-3.2 → nltk-3.3}/nltk/misc/sort.py +157 -157
  152. {nltk-3.2 → nltk-3.3}/nltk/misc/wordfinder.py +129 -129
  153. {nltk-3.2 → nltk-3.3}/nltk/parse/__init__.py +81 -80
  154. {nltk-3.2 → nltk-3.3}/nltk/parse/api.py +66 -66
  155. {nltk-3.2 → nltk-3.3}/nltk/parse/bllip.py +282 -282
  156. {nltk-3.2 → nltk-3.3}/nltk/parse/chart.py +1682 -1681
  157. nltk-3.3/nltk/parse/corenlp.py +780 -0
  158. {nltk-3.2 → nltk-3.3}/nltk/parse/dependencygraph.py +760 -758
  159. {nltk-3.2 → nltk-3.3}/nltk/parse/earleychart.py +452 -451
  160. {nltk-3.2 → nltk-3.3}/nltk/parse/evaluate.py +129 -129
  161. {nltk-3.2 → nltk-3.3}/nltk/parse/featurechart.py +580 -578
  162. {nltk-3.2 → nltk-3.3}/nltk/parse/generate.py +87 -76
  163. {nltk-3.2 → nltk-3.3}/nltk/parse/malt.py +356 -356
  164. {nltk-3.2 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +783 -783
  165. {nltk-3.2 → nltk-3.3}/nltk/parse/pchart.py +522 -522
  166. {nltk-3.2 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +579 -578
  167. {nltk-3.2 → nltk-3.3}/nltk/parse/recursivedescent.py +655 -656
  168. {nltk-3.2 → nltk-3.3}/nltk/parse/shiftreduce.py +458 -459
  169. {nltk-3.2 → nltk-3.3}/nltk/parse/stanford.py +431 -406
  170. {nltk-3.2 → nltk-3.3}/nltk/parse/transitionparser.py +774 -772
  171. {nltk-3.2 → nltk-3.3}/nltk/parse/util.py +231 -231
  172. {nltk-3.2 → nltk-3.3}/nltk/parse/viterbi.py +401 -401
  173. {nltk-3.2 → nltk-3.3}/nltk/probability.py +2410 -2355
  174. {nltk-3.2 → nltk-3.3}/nltk/sem/__init__.py +61 -61
  175. {nltk-3.2 → nltk-3.3}/nltk/sem/boxer.py +1261 -1261
  176. {nltk-3.2 → nltk-3.3}/nltk/sem/chat80.py +782 -782
  177. {nltk-3.2 → nltk-3.3}/nltk/sem/cooper_storage.py +118 -118
  178. {nltk-3.2 → nltk-3.3}/nltk/sem/drt.py +1258 -1257
  179. {nltk-3.2 → nltk-3.3}/nltk/sem/drt_glue_demo.py +485 -489
  180. {nltk-3.2 → nltk-3.3}/nltk/sem/evaluate.py +790 -784
  181. {nltk-3.2 → nltk-3.3}/nltk/sem/glue.py +696 -694
  182. {nltk-3.2 → nltk-3.3}/nltk/sem/hole.py +386 -384
  183. {nltk-3.2 → nltk-3.3}/nltk/sem/lfg.py +210 -208
  184. {nltk-3.2 → nltk-3.3}/nltk/sem/linearlogic.py +451 -449
  185. {nltk-3.2 → nltk-3.3}/nltk/sem/logic.py +1910 -1910
  186. {nltk-3.2 → nltk-3.3}/nltk/sem/relextract.py +476 -483
  187. {nltk-3.2 → nltk-3.3}/nltk/sem/skolemize.py +101 -101
  188. {nltk-3.2 → nltk-3.3}/nltk/sem/util.py +249 -249
  189. {nltk-3.2 → nltk-3.3}/nltk/sentiment/__init__.py +14 -14
  190. {nltk-3.2 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +229 -229
  191. {nltk-3.2 → nltk-3.3}/nltk/sentiment/util.py +762 -752
  192. {nltk-3.2 → nltk-3.3}/nltk/sentiment/vader.py +443 -445
  193. {nltk-3.2 → nltk-3.3}/nltk/stem/__init__.py +31 -33
  194. {nltk-3.2 → nltk-3.3}/nltk/stem/api.py +28 -25
  195. nltk-3.3/nltk/stem/arlstem.py +369 -0
  196. {nltk-3.2 → nltk-3.3}/nltk/stem/isri.py +345 -345
  197. {nltk-3.2 → nltk-3.3}/nltk/stem/lancaster.py +337 -310
  198. nltk-3.3/nltk/stem/porter.py +710 -0
  199. {nltk-3.2 → nltk-3.3}/nltk/stem/regexp.py +61 -61
  200. {nltk-3.2 → nltk-3.3}/nltk/stem/rslp.py +142 -142
  201. {nltk-3.2 → nltk-3.3}/nltk/stem/snowball.py +4236 -3712
  202. {nltk-3.2 → nltk-3.3}/nltk/stem/util.py +22 -12
  203. {nltk-3.2 → nltk-3.3}/nltk/stem/wordnet.py +51 -51
  204. {nltk-3.2 → nltk-3.3}/nltk/tag/__init__.py +152 -127
  205. {nltk-3.2 → nltk-3.3}/nltk/tag/api.py +86 -81
  206. {nltk-3.2 → nltk-3.3}/nltk/tag/brill.py +424 -426
  207. {nltk-3.2 → nltk-3.3}/nltk/tag/brill_trainer.py +608 -608
  208. {nltk-3.2 → nltk-3.3}/nltk/tag/crf.py +204 -200
  209. {nltk-3.2 → nltk-3.3}/nltk/tag/hmm.py +1277 -1277
  210. {nltk-3.2 → nltk-3.3}/nltk/tag/hunpos.py +132 -132
  211. {nltk-3.2 → nltk-3.3}/nltk/tag/mapping.py +101 -101
  212. {nltk-3.2 → nltk-3.3}/nltk/tag/perceptron.py +329 -314
  213. {nltk-3.2 → nltk-3.3}/nltk/tag/senna.py +147 -145
  214. {nltk-3.2 → nltk-3.3}/nltk/tag/sequential.py +740 -736
  215. {nltk-3.2 → nltk-3.3}/nltk/tag/stanford.py +219 -196
  216. {nltk-3.2 → nltk-3.3}/nltk/tag/tnt.py +595 -604
  217. {nltk-3.2 → nltk-3.3}/nltk/tag/util.py +72 -72
  218. {nltk-3.2 → nltk-3.3}/nltk/tbl/__init__.py +28 -28
  219. {nltk-3.2 → nltk-3.3}/nltk/tbl/api.py +1 -1
  220. {nltk-3.2 → nltk-3.3}/nltk/tbl/demo.py +366 -366
  221. {nltk-3.2 → nltk-3.3}/nltk/tbl/erroranalysis.py +39 -39
  222. {nltk-3.2 → nltk-3.3}/nltk/tbl/feature.py +259 -261
  223. {nltk-3.2 → nltk-3.3}/nltk/tbl/rule.py +321 -321
  224. {nltk-3.2 → nltk-3.3}/nltk/tbl/template.py +303 -308
  225. {nltk-3.2 → nltk-3.3}/nltk/test/__init__.py +18 -18
  226. {nltk-3.2 → nltk-3.3}/nltk/test/all.py +24 -23
  227. {nltk-3.2 → nltk-3.3}/nltk/test/bleu.doctest +14 -14
  228. {nltk-3.2 → nltk-3.3}/nltk/test/bnc.doctest +60 -60
  229. {nltk-3.2 → nltk-3.3}/nltk/test/ccg.doctest +376 -395
  230. nltk-3.3/nltk/test/ccg_semantics.doctest +553 -0
  231. {nltk-3.2 → nltk-3.3}/nltk/test/chat80.doctest +234 -234
  232. {nltk-3.2 → nltk-3.3}/nltk/test/childes.doctest +184 -184
  233. {nltk-3.2 → nltk-3.3}/nltk/test/childes_fixt.py +14 -13
  234. {nltk-3.2 → nltk-3.3}/nltk/test/chunk.doctest +373 -373
  235. {nltk-3.2 → nltk-3.3}/nltk/test/classify.doctest +185 -185
  236. {nltk-3.2 → nltk-3.3}/nltk/test/classify_fixt.py +11 -10
  237. nltk-3.3/nltk/test/collections.doctest +20 -0
  238. {nltk-3.2 → nltk-3.3}/nltk/test/collocations.doctest +276 -276
  239. {nltk-3.2 → nltk-3.3}/nltk/test/compat.doctest +134 -138
  240. {nltk-3.2 → nltk-3.3}/nltk/test/compat_fixt.py +9 -8
  241. nltk-3.3/nltk/test/concordance.doctest +55 -0
  242. {nltk-3.2 → nltk-3.3}/nltk/test/corpus.doctest +2200 -2212
  243. {nltk-3.2 → nltk-3.3}/nltk/test/corpus_fixt.py +3 -3
  244. {nltk-3.2 → nltk-3.3}/nltk/test/crubadan.doctest +65 -65
  245. {nltk-3.2 → nltk-3.3}/nltk/test/data.doctest +379 -379
  246. {nltk-3.2 → nltk-3.3}/nltk/test/dependency.doctest +241 -241
  247. {nltk-3.2 → nltk-3.3}/nltk/test/discourse.doctest +546 -546
  248. {nltk-3.2 → nltk-3.3}/nltk/test/discourse_fixt.py +14 -13
  249. {nltk-3.2 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +159 -156
  250. {nltk-3.2 → nltk-3.3}/nltk/test/drt.doctest +517 -517
  251. {nltk-3.2 → nltk-3.3}/nltk/test/featgram.doctest +607 -607
  252. {nltk-3.2 → nltk-3.3}/nltk/test/featstruct.doctest +1229 -1230
  253. {nltk-3.2 → nltk-3.3}/nltk/test/framenet.doctest +288 -239
  254. {nltk-3.2 → nltk-3.3}/nltk/test/generate.doctest +67 -67
  255. {nltk-3.2 → nltk-3.3}/nltk/test/gensim.doctest +140 -141
  256. {nltk-3.2 → nltk-3.3}/nltk/test/gensim_fixt.py +10 -9
  257. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics.doctest +384 -386
  258. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +68 -68
  259. {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +12 -11
  260. {nltk-3.2 → nltk-3.3}/nltk/test/grammar.doctest +48 -48
  261. {nltk-3.2 → nltk-3.3}/nltk/test/grammartestsuites.doctest +109 -109
  262. {nltk-3.2 → nltk-3.3}/nltk/test/index.doctest +100 -100
  263. {nltk-3.2 → nltk-3.3}/nltk/test/inference.doctest +534 -534
  264. {nltk-3.2 → nltk-3.3}/nltk/test/inference_fixt.py +12 -11
  265. {nltk-3.2 → nltk-3.3}/nltk/test/internals.doctest +140 -140
  266. {nltk-3.2 → nltk-3.3}/nltk/test/japanese.doctest +48 -48
  267. {nltk-3.2 → nltk-3.3}/nltk/test/logic.doctest +1098 -1098
  268. {nltk-3.2 → nltk-3.3}/nltk/test/metrics.doctest +270 -270
  269. {nltk-3.2 → nltk-3.3}/nltk/test/misc.doctest +118 -118
  270. {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic.doctest +286 -286
  271. {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +12 -11
  272. {nltk-3.2 → nltk-3.3}/nltk/test/paice.doctest +35 -35
  273. {nltk-3.2 → nltk-3.3}/nltk/test/parse.doctest +884 -884
  274. {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en.doctest +565 -565
  275. {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +16 -16
  276. {nltk-3.2 → nltk-3.3}/nltk/test/probability.doctest +304 -304
  277. {nltk-3.2 → nltk-3.3}/nltk/test/probability_fixt.py +13 -12
  278. {nltk-3.2 → nltk-3.3}/nltk/test/propbank.doctest +176 -176
  279. {nltk-3.2 → nltk-3.3}/nltk/test/relextract.doctest +263 -263
  280. {nltk-3.2 → nltk-3.3}/nltk/test/resolution.doctest +221 -221
  281. {nltk-3.2 → nltk-3.3}/nltk/test/runtests.py +86 -64
  282. {nltk-3.2 → nltk-3.3}/nltk/test/segmentation_fixt.py +10 -10
  283. {nltk-3.2 → nltk-3.3}/nltk/test/semantics.doctest +665 -665
  284. {nltk-3.2 → nltk-3.3}/nltk/test/semantics_fixt.py +7 -7
  285. {nltk-3.2 → nltk-3.3}/nltk/test/sentiment.doctest +233 -233
  286. {nltk-3.2 → nltk-3.3}/nltk/test/sentiwordnet.doctest +41 -41
  287. {nltk-3.2 → nltk-3.3}/nltk/test/simple.doctest +85 -85
  288. {nltk-3.2 → nltk-3.3}/nltk/test/stem.doctest +78 -78
  289. {nltk-3.2 → nltk-3.3}/nltk/test/tag.doctest +33 -33
  290. {nltk-3.2 → nltk-3.3}/nltk/test/tokenize.doctest +273 -166
  291. {nltk-3.2 → nltk-3.3}/nltk/test/toolbox.doctest +307 -307
  292. {nltk-3.2 → nltk-3.3}/nltk/test/translate.doctest +242 -242
  293. {nltk-3.2 → nltk-3.3}/nltk/test/translate_fixt.py +3 -3
  294. {nltk-3.2 → nltk-3.3}/nltk/test/tree.doctest +1101 -1101
  295. {nltk-3.2 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +127 -127
  296. {nltk-3.2 → nltk-3.3}/nltk/test/treetransforms.doctest +156 -156
  297. nltk-3.3/nltk/test/unit/test_2x_compat.py +63 -0
  298. nltk-3.3/nltk/test/unit/test_aline.py +52 -0
  299. nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
  300. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_classify.py +55 -53
  301. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_collocations.py +88 -79
  302. nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
  303. nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
  304. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpora.py +200 -183
  305. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +45 -45
  306. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_hmm.py +88 -88
  307. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +188 -187
  308. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +26 -26
  309. nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
  310. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +124 -124
  311. nltk-3.3/nltk/test/unit/test_senna.py +74 -0
  312. nltk-3.3/nltk/test/unit/test_stem.py +121 -0
  313. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tag.py +20 -20
  314. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tgrep.py +628 -626
  315. nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
  316. {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +185 -185
  317. nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
  318. nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
  319. nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
  320. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +75 -75
  321. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +87 -87
  322. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +105 -105
  323. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +126 -126
  324. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +166 -166
  325. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +270 -270
  326. nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
  327. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +300 -300
  328. {nltk-3.2 → nltk-3.3}/nltk/test/unit/utils.py +41 -41
  329. {nltk-3.2 → nltk-3.3}/nltk/test/util.doctest +48 -48
  330. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet.doctest +595 -581
  331. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_fixt.py +7 -6
  332. {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_lch.doctest +53 -53
  333. {nltk-3.2 → nltk-3.3}/nltk/test/wsd.doctest +68 -68
  334. {nltk-3.2 → nltk-3.3}/nltk/text.py +663 -610
  335. {nltk-3.2 → nltk-3.3}/nltk/tgrep.py +938 -937
  336. {nltk-3.2 → nltk-3.3}/nltk/tokenize/__init__.py +130 -107
  337. {nltk-3.2 → nltk-3.3}/nltk/tokenize/api.py +77 -78
  338. {nltk-3.2 → nltk-3.3}/nltk/tokenize/casual.py +343 -342
  339. {nltk-3.2 → nltk-3.3}/nltk/tokenize/mwe.py +120 -120
  340. nltk-3.3/nltk/tokenize/nist.py +173 -0
  341. {nltk-3.2 → nltk-3.3}/nltk/tokenize/punkt.py +1620 -1601
  342. {nltk-3.2 → nltk-3.3}/nltk/tokenize/regexp.py +208 -202
  343. nltk-3.3/nltk/tokenize/repp.py +151 -0
  344. {nltk-3.2 → nltk-3.3}/nltk/tokenize/sexpr.py +140 -142
  345. {nltk-3.2 → nltk-3.3}/nltk/tokenize/simple.py +138 -136
  346. {nltk-3.2 → nltk-3.3}/nltk/tokenize/stanford.py +117 -113
  347. nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
  348. {nltk-3.2 → nltk-3.3}/nltk/tokenize/texttiling.py +458 -460
  349. nltk-3.3/nltk/tokenize/toktok.py +155 -0
  350. nltk-3.3/nltk/tokenize/treebank.py +363 -0
  351. nltk-3.3/nltk/tokenize/util.py +261 -0
  352. {nltk-3.2 → nltk-3.3}/nltk/toolbox.py +499 -497
  353. {nltk-3.2 → nltk-3.3}/nltk/translate/__init__.py +24 -24
  354. {nltk-3.2 → nltk-3.3}/nltk/translate/api.py +331 -321
  355. {nltk-3.2 → nltk-3.3}/nltk/translate/bleu_score.py +615 -556
  356. nltk-3.3/nltk/translate/chrf_score.py +137 -0
  357. {nltk-3.2 → nltk-3.3}/nltk/translate/gale_church.py +248 -235
  358. {nltk-3.2 → nltk-3.3}/nltk/translate/gdfa.py +135 -131
  359. nltk-3.3/nltk/translate/gleu_score.py +193 -0
  360. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm1.py +250 -241
  361. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm2.py +308 -308
  362. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm3.py +337 -337
  363. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm4.py +467 -467
  364. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm5.py +639 -639
  365. {nltk-3.2 → nltk-3.3}/nltk/translate/ibm_model.py +536 -533
  366. {nltk-3.2 → nltk-3.3}/nltk/translate/metrics.py +40 -40
  367. nltk-3.3/nltk/translate/nist_score.py +178 -0
  368. {nltk-3.2 → nltk-3.3}/nltk/translate/phrase_based.py +175 -175
  369. {nltk-3.2 → nltk-3.3}/nltk/translate/ribes_score.py +325 -325
  370. {nltk-3.2 → nltk-3.3}/nltk/translate/stack_decoder.py +499 -495
  371. {nltk-3.2 → nltk-3.3}/nltk/tree.py +1605 -1603
  372. {nltk-3.2 → nltk-3.3}/nltk/treeprettyprinter.py +564 -564
  373. {nltk-3.2 → nltk-3.3}/nltk/treetransforms.py +309 -309
  374. {nltk-3.2 → nltk-3.3}/nltk/twitter/__init__.py +28 -28
  375. {nltk-3.2 → nltk-3.3}/nltk/twitter/api.py +141 -136
  376. {nltk-3.2 → nltk-3.3}/nltk/twitter/common.py +264 -258
  377. {nltk-3.2 → nltk-3.3}/nltk/twitter/twitter_demo.py +288 -288
  378. {nltk-3.2 → nltk-3.3}/nltk/twitter/twitterclient.py +530 -530
  379. {nltk-3.2 → nltk-3.3}/nltk/twitter/util.py +147 -146
  380. nltk-3.3/nltk/util.py +751 -0
  381. {nltk-3.2 → nltk-3.3}/nltk/wsd.py +53 -53
  382. {nltk-3.2 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
  383. {nltk-3.2 → nltk-3.3}/nltk.egg-info/SOURCES.txt +26 -3
  384. nltk-3.3/nltk.egg-info/requires.txt +31 -0
  385. {nltk-3.2 → nltk-3.3}/setup.cfg +0 -1
  386. {nltk-3.2 → nltk-3.3}/setup.py +102 -75
  387. nltk-3.2/nltk/VERSION +0 -1
  388. nltk-3.2/nltk/compat.py +0 -680
  389. nltk-3.2/nltk/corpus/reader/pl196x.py +0 -278
  390. nltk-3.2/nltk/corpus/reader/verbnet.py +0 -408
  391. nltk-3.2/nltk/corpus/reader/wordlist.py +0 -37
  392. nltk-3.2/nltk/sentiment/vader_lexicon.txt +0 -7517
  393. nltk-3.2/nltk/six.py +0 -868
  394. nltk-3.2/nltk/stem/porter.py +0 -692
  395. nltk-3.2/nltk/test/unit/test_2x_compat.py +0 -26
  396. nltk-3.2/nltk/test/unit/test_stem.py +0 -36
  397. nltk-3.2/nltk/test/unit/test_tokenize.py +0 -23
  398. nltk-3.2/nltk/test/unit/translate/test_bleu.py +0 -84
  399. nltk-3.2/nltk/tokenize/treebank.py +0 -124
  400. nltk-3.2/nltk/tokenize/util.py +0 -90
  401. nltk-3.2/nltk/util.py +0 -1364
  402. {nltk-3.2 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
  403. {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
  404. {nltk-3.2 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
  405. {nltk-3.2 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
  406. {nltk-3.2 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
@@ -1,783 +1,783 @@
1
- # Natural Language Toolkit: Dependency Grammars
2
- #
3
- # Copyright (C) 2001-2015 NLTK Project
4
- # Author: Jason Narad <jason.narad@gmail.com>
5
- #
6
- # URL: <http://nltk.org/>
7
- # For license information, see LICENSE.TXT
8
- #
9
- from __future__ import print_function
10
-
11
- import math
12
- import logging
13
-
14
- from nltk.compat import xrange
15
-
16
- from nltk.parse.dependencygraph import DependencyGraph
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
- #################################################################
21
- # DependencyScorerI - Interface for Graph-Edge Weight Calculation
22
- #################################################################
23
-
24
-
25
- class DependencyScorerI(object):
26
- """
27
- A scorer for calculated the weights on the edges of a weighted
28
- dependency graph. This is used by a
29
- ``ProbabilisticNonprojectiveParser`` to initialize the edge
30
- weights of a ``DependencyGraph``. While typically this would be done
31
- by training a binary classifier, any class that can return a
32
- multidimensional list representation of the edge weights can
33
- implement this interface. As such, it has no necessary
34
- fields.
35
- """
36
-
37
- def __init__(self):
38
- if self.__class__ == DependencyScorerI:
39
- raise TypeError('DependencyScorerI is an abstract interface')
40
-
41
- def train(self, graphs):
42
- """
43
- :type graphs: list(DependencyGraph)
44
- :param graphs: A list of dependency graphs to train the scorer.
45
- Typically the edges present in the graphs can be used as
46
- positive training examples, and the edges not present as negative
47
- examples.
48
- """
49
- raise NotImplementedError()
50
-
51
- def score(self, graph):
52
- """
53
- :type graph: DependencyGraph
54
- :param graph: A dependency graph whose set of edges need to be
55
- scored.
56
- :rtype: A three-dimensional list of numbers.
57
- :return: The score is returned in a multidimensional(3) list, such
58
- that the outer-dimension refers to the head, and the
59
- inner-dimension refers to the dependencies. For instance,
60
- scores[0][1] would reference the list of scores corresponding to
61
- arcs from node 0 to node 1. The node's 'address' field can be used
62
- to determine its number identification.
63
-
64
- For further illustration, a score list corresponding to Fig.2 of
65
- Keith Hall's 'K-best Spanning Tree Parsing' paper:
66
- scores = [[[], [5], [1], [1]],
67
- [[], [], [11], [4]],
68
- [[], [10], [], [5]],
69
- [[], [8], [8], []]]
70
- When used in conjunction with a MaxEntClassifier, each score would
71
- correspond to the confidence of a particular edge being classified
72
- with the positive training examples.
73
- """
74
- raise NotImplementedError()
75
-
76
- #################################################################
77
- # NaiveBayesDependencyScorer
78
- #################################################################
79
-
80
-
81
- class NaiveBayesDependencyScorer(DependencyScorerI):
82
- """
83
- A dependency scorer built around a MaxEnt classifier. In this
84
- particular class that classifier is a ``NaiveBayesClassifier``.
85
- It uses head-word, head-tag, child-word, and child-tag features
86
- for classification.
87
-
88
- >>> from nltk.parse.dependencygraph import DependencyGraph, conll_data2
89
-
90
- >>> graphs = [DependencyGraph(entry) for entry in conll_data2.split('\\n\\n') if entry]
91
- >>> npp = ProbabilisticNonprojectiveParser()
92
- >>> npp.train(graphs, NaiveBayesDependencyScorer())
93
- >>> parses = npp.parse(['Cathy', 'zag', 'hen', 'zwaaien', '.'], ['N', 'V', 'Pron', 'Adj', 'N', 'Punc'])
94
- >>> len(list(parses))
95
- 1
96
-
97
- """
98
-
99
- def __init__(self):
100
- pass # Do nothing without throwing error
101
-
102
- def train(self, graphs):
103
- """
104
- Trains a ``NaiveBayesClassifier`` using the edges present in
105
- graphs list as positive examples, the edges not present as
106
- negative examples. Uses a feature vector of head-word,
107
- head-tag, child-word, and child-tag.
108
-
109
- :type graphs: list(DependencyGraph)
110
- :param graphs: A list of dependency graphs to train the scorer.
111
- """
112
-
113
- from nltk.classify import NaiveBayesClassifier
114
-
115
- # Create training labeled training examples
116
- labeled_examples = []
117
- for graph in graphs:
118
- for head_node in graph.nodes.values():
119
- for child_index, child_node in graph.nodes.items():
120
- if child_index in head_node['deps']:
121
- label = "T"
122
- else:
123
- label = "F"
124
- labeled_examples.append(
125
- (
126
- dict(
127
- a=head_node['word'],
128
- b=head_node['tag'],
129
- c=child_node['word'],
130
- d=child_node['tag'],
131
- ),
132
- label,
133
- )
134
- )
135
-
136
- self.classifier = NaiveBayesClassifier.train(labeled_examples)
137
-
138
- def score(self, graph):
139
- """
140
- Converts the graph into a feature-based representation of
141
- each edge, and then assigns a score to each based on the
142
- confidence of the classifier in assigning it to the
143
- positive label. Scores are returned in a multidimensional list.
144
-
145
- :type graph: DependencyGraph
146
- :param graph: A dependency graph to score.
147
- :rtype: 3 dimensional list
148
- :return: Edge scores for the graph parameter.
149
- """
150
- # Convert graph to feature representation
151
- edges = []
152
- for head_node in graph.nodes.values():
153
- for child_node in graph.nodes.values():
154
- edges.append(
155
- (
156
- dict(
157
- a=head_node['word'],
158
- b=head_node['tag'],
159
- c=child_node['word'],
160
- d=child_node['tag'],
161
- )
162
- )
163
- )
164
-
165
- # Score edges
166
- edge_scores = []
167
- row = []
168
- count = 0
169
- for pdist in self.classifier.prob_classify_many(edges):
170
- logger.debug('%.4f %.4f', pdist.prob('T'), pdist.prob('F'))
171
- # smoothing in case the probability = 0
172
- row.append([math.log(pdist.prob("T")+0.00000000001)])
173
- count += 1
174
- if count == len(graph.nodes):
175
- edge_scores.append(row)
176
- row = []
177
- count = 0
178
- return edge_scores
179
-
180
-
181
- #################################################################
182
- # A Scorer for Demo Purposes
183
- #################################################################
184
- # A short class necessary to show parsing example from paper
185
- class DemoScorer(DependencyScorerI):
186
- def train(self, graphs):
187
- print('Training...')
188
-
189
- def score(self, graph):
190
- # scores for Keith Hall 'K-best Spanning Tree Parsing' paper
191
- return [[[], [5], [1], [1]],
192
- [[], [], [11], [4]],
193
- [[], [10], [], [5]],
194
- [[], [8], [8], []]]
195
-
196
- #################################################################
197
- # Non-Projective Probabilistic Parsing
198
- #################################################################
199
-
200
-
201
- class ProbabilisticNonprojectiveParser(object):
202
- """A probabilistic non-projective dependency parser.
203
-
204
- Nonprojective dependencies allows for "crossing branches" in the parse tree
205
- which is necessary for representing particular linguistic phenomena, or even
206
- typical parses in some languages. This parser follows the MST parsing
207
- algorithm, outlined in McDonald(2005), which likens the search for the best
208
- non-projective parse to finding the maximum spanning tree in a weighted
209
- directed graph.
210
-
211
- >>> class Scorer(DependencyScorerI):
212
- ... def train(self, graphs):
213
- ... pass
214
- ...
215
- ... def score(self, graph):
216
- ... return [
217
- ... [[], [5], [1], [1]],
218
- ... [[], [], [11], [4]],
219
- ... [[], [10], [], [5]],
220
- ... [[], [8], [8], []],
221
- ... ]
222
-
223
-
224
- >>> npp = ProbabilisticNonprojectiveParser()
225
- >>> npp.train([], Scorer())
226
-
227
- >>> parses = npp.parse(['v1', 'v2', 'v3'], [None, None, None])
228
- >>> len(list(parses))
229
- 1
230
-
231
- Rule based example
232
- ------------------
233
-
234
- >>> from nltk.grammar import DependencyGrammar
235
-
236
- >>> grammar = DependencyGrammar.fromstring('''
237
- ... 'taught' -> 'play' | 'man'
238
- ... 'man' -> 'the' | 'in'
239
- ... 'in' -> 'corner'
240
- ... 'corner' -> 'the'
241
- ... 'play' -> 'golf' | 'dachshund' | 'to'
242
- ... 'dachshund' -> 'his'
243
- ... ''')
244
-
245
- >>> ndp = NonprojectiveDependencyParser(grammar)
246
- >>> parses = ndp.parse(['the', 'man', 'in', 'the', 'corner', 'taught', 'his', 'dachshund', 'to', 'play', 'golf'])
247
- >>> len(list(parses))
248
- 4
249
-
250
- """
251
- def __init__(self):
252
- """
253
- Creates a new non-projective parser.
254
- """
255
- logging.debug('initializing prob. nonprojective...')
256
-
257
- def train(self, graphs, dependency_scorer):
258
- """
259
- Trains a ``DependencyScorerI`` from a set of ``DependencyGraph`` objects,
260
- and establishes this as the parser's scorer. This is used to
261
- initialize the scores on a ``DependencyGraph`` during the parsing
262
- procedure.
263
-
264
- :type graphs: list(DependencyGraph)
265
- :param graphs: A list of dependency graphs to train the scorer.
266
- :type dependency_scorer: DependencyScorerI
267
- :param dependency_scorer: A scorer which implements the
268
- ``DependencyScorerI`` interface.
269
- """
270
- self._scorer = dependency_scorer
271
- self._scorer.train(graphs)
272
-
273
- def initialize_edge_scores(self, graph):
274
- """
275
- Assigns a score to every edge in the ``DependencyGraph`` graph.
276
- These scores are generated via the parser's scorer which
277
- was assigned during the training process.
278
-
279
- :type graph: DependencyGraph
280
- :param graph: A dependency graph to assign scores to.
281
- """
282
- self.scores = self._scorer.score(graph)
283
-
284
- def collapse_nodes(self, new_node, cycle_path, g_graph, b_graph, c_graph):
285
- """
286
- Takes a list of nodes that have been identified to belong to a cycle,
287
- and collapses them into on larger node. The arcs of all nodes in
288
- the graph must be updated to account for this.
289
-
290
- :type new_node: Node.
291
- :param new_node: A Node (Dictionary) to collapse the cycle nodes into.
292
- :type cycle_path: A list of integers.
293
- :param cycle_path: A list of node addresses, each of which is in the cycle.
294
- :type g_graph, b_graph, c_graph: DependencyGraph
295
- :param g_graph, b_graph, c_graph: Graphs which need to be updated.
296
- """
297
- logger.debug('Collapsing nodes...')
298
- # Collapse all cycle nodes into v_n+1 in G_Graph
299
- for cycle_node_index in cycle_path:
300
- g_graph.remove_by_address(cycle_node_index)
301
- g_graph.add_node(new_node)
302
- g_graph.redirect_arcs(cycle_path, new_node['address'])
303
-
304
- def update_edge_scores(self, new_node, cycle_path):
305
- """
306
- Updates the edge scores to reflect a collapse operation into
307
- new_node.
308
-
309
- :type new_node: A Node.
310
- :param new_node: The node which cycle nodes are collapsed into.
311
- :type cycle_path: A list of integers.
312
- :param cycle_path: A list of node addresses that belong to the cycle.
313
- """
314
- logger.debug('cycle %s', cycle_path)
315
-
316
- cycle_path = self.compute_original_indexes(cycle_path)
317
-
318
- logger.debug('old cycle %s', cycle_path)
319
- logger.debug('Prior to update: %s', self.scores)
320
-
321
- for i, row in enumerate(self.scores):
322
- for j, column in enumerate(self.scores[i]):
323
- logger.debug(self.scores[i][j])
324
- if (
325
- j in cycle_path
326
- and i not in cycle_path
327
- and self.scores[i][j]
328
- ):
329
- subtract_val = self.compute_max_subtract_score(j, cycle_path)
330
-
331
- logger.debug('%s - %s', self.scores[i][j], subtract_val)
332
-
333
- new_vals = []
334
- for cur_val in self.scores[i][j]:
335
- new_vals.append(cur_val - subtract_val)
336
-
337
- self.scores[i][j] = new_vals
338
-
339
- for i, row in enumerate(self.scores):
340
- for j, cell in enumerate(self.scores[i]):
341
- if i in cycle_path and j in cycle_path:
342
- self.scores[i][j] = []
343
-
344
- logger.debug('After update: %s', self.scores)
345
-
346
- def compute_original_indexes(self, new_indexes):
347
- """
348
- As nodes are collapsed into others, they are replaced
349
- by the new node in the graph, but it's still necessary
350
- to keep track of what these original nodes were. This
351
- takes a list of node addresses and replaces any collapsed
352
- node addresses with their original addresses.
353
-
354
- :type new_indexes: A list of integers.
355
- :param new_indexes: A list of node addresses to check for
356
- subsumed nodes.
357
- """
358
- swapped = True
359
- while swapped:
360
- originals = []
361
- swapped = False
362
- for new_index in new_indexes:
363
- if new_index in self.inner_nodes:
364
- for old_val in self.inner_nodes[new_index]:
365
- if old_val not in originals:
366
- originals.append(old_val)
367
- swapped = True
368
- else:
369
- originals.append(new_index)
370
- new_indexes = originals
371
- return new_indexes
372
-
373
- def compute_max_subtract_score(self, column_index, cycle_indexes):
374
- """
375
- When updating scores the score of the highest-weighted incoming
376
- arc is subtracted upon collapse. This returns the correct
377
- amount to subtract from that edge.
378
-
379
- :type column_index: integer.
380
- :param column_index: A index representing the column of incoming arcs
381
- to a particular node being updated
382
- :type cycle_indexes: A list of integers.
383
- :param cycle_indexes: Only arcs from cycle nodes are considered. This
384
- is a list of such nodes addresses.
385
- """
386
- max_score = -100000
387
- for row_index in cycle_indexes:
388
- for subtract_val in self.scores[row_index][column_index]:
389
- if subtract_val > max_score:
390
- max_score = subtract_val
391
- return max_score
392
-
393
- def best_incoming_arc(self, node_index):
394
- """
395
- Returns the source of the best incoming arc to the
396
- node with address: node_index
397
-
398
- :type node_index: integer.
399
- :param node_index: The address of the 'destination' node,
400
- the node that is arced to.
401
- """
402
- originals = self.compute_original_indexes([node_index])
403
- logger.debug('originals: %s', originals)
404
-
405
- max_arc = None
406
- max_score = None
407
- for row_index in range(len(self.scores)):
408
- for col_index in range(len(self.scores[row_index])):
409
- # print self.scores[row_index][col_index]
410
- if col_index in originals and (max_score is None or self.scores[row_index][col_index] > max_score):
411
- max_score = self.scores[row_index][col_index]
412
- max_arc = row_index
413
- logger.debug('%s, %s', row_index, col_index)
414
-
415
- logger.debug(max_score)
416
-
417
- for key in self.inner_nodes:
418
- replaced_nodes = self.inner_nodes[key]
419
- if max_arc in replaced_nodes:
420
- return key
421
-
422
- return max_arc
423
-
424
- def original_best_arc(self, node_index):
425
- originals = self.compute_original_indexes([node_index])
426
- max_arc = None
427
- max_score = None
428
- max_orig = None
429
- for row_index in range(len(self.scores)):
430
- for col_index in range(len(self.scores[row_index])):
431
- if col_index in originals and (max_score is None or self.scores[row_index][col_index] > max_score):
432
- max_score = self.scores[row_index][col_index]
433
- max_arc = row_index
434
- max_orig = col_index
435
- return [max_arc, max_orig]
436
-
437
- def parse(self, tokens, tags):
438
- """
439
- Parses a list of tokens in accordance to the MST parsing algorithm
440
- for non-projective dependency parses. Assumes that the tokens to
441
- be parsed have already been tagged and those tags are provided. Various
442
- scoring methods can be used by implementing the ``DependencyScorerI``
443
- interface and passing it to the training algorithm.
444
-
445
- :type tokens: list(str)
446
- :param tokens: A list of words or punctuation to be parsed.
447
- :type tags: list(str)
448
- :param tags: A list of tags corresponding by index to the words in the tokens list.
449
- :return: An iterator of non-projective parses.
450
- :rtype: iter(DependencyGraph)
451
- """
452
- self.inner_nodes = {}
453
-
454
- # Initialize g_graph
455
- g_graph = DependencyGraph()
456
- for index, token in enumerate(tokens):
457
- g_graph.nodes[index + 1].update(
458
- {
459
- 'word': token,
460
- 'tag': tags[index],
461
- 'rel': 'NTOP',
462
- 'address': index + 1,
463
- }
464
- )
465
- #print (g_graph.nodes)
466
-
467
-
468
- # Fully connect non-root nodes in g_graph
469
- g_graph.connect_graph()
470
- original_graph = DependencyGraph()
471
- for index, token in enumerate(tokens):
472
- original_graph.nodes[index + 1].update(
473
- {
474
- 'word': token,
475
- 'tag': tags[index],
476
- 'rel': 'NTOP',
477
- 'address': index+1,
478
- }
479
- )
480
-
481
- b_graph = DependencyGraph()
482
- c_graph = DependencyGraph()
483
-
484
- for index, token in enumerate(tokens):
485
- c_graph.nodes[index + 1].update(
486
- {
487
- 'word': token,
488
- 'tag': tags[index],
489
- 'rel': 'NTOP',
490
- 'address': index + 1,
491
- }
492
- )
493
-
494
- # Assign initial scores to g_graph edges
495
- self.initialize_edge_scores(g_graph)
496
- logger.debug(self.scores)
497
- # Initialize a list of unvisited vertices (by node address)
498
- unvisited_vertices = [
499
- vertex['address'] for vertex in c_graph.nodes.values()
500
- ]
501
- # Iterate over unvisited vertices
502
- nr_vertices = len(tokens)
503
- betas = {}
504
- while unvisited_vertices:
505
- # Mark current node as visited
506
- current_vertex = unvisited_vertices.pop(0)
507
- logger.debug('current_vertex: %s', current_vertex)
508
- # Get corresponding node n_i to vertex v_i
509
- current_node = g_graph.get_by_address(current_vertex)
510
- logger.debug('current_node: %s', current_node)
511
- # Get best in-edge node b for current node
512
- best_in_edge = self.best_incoming_arc(current_vertex)
513
- betas[current_vertex] = self.original_best_arc(current_vertex)
514
- logger.debug('best in arc: %s --> %s', best_in_edge, current_vertex)
515
- # b_graph = Union(b_graph, b)
516
- for new_vertex in [current_vertex, best_in_edge]:
517
- b_graph.nodes[new_vertex].update(
518
- {
519
- 'word': 'TEMP',
520
- 'rel': 'NTOP',
521
- 'address': new_vertex,
522
- }
523
- )
524
- b_graph.add_arc(best_in_edge, current_vertex)
525
- # Beta(current node) = b - stored for parse recovery
526
- # If b_graph contains a cycle, collapse it
527
- cycle_path = b_graph.contains_cycle()
528
- if cycle_path:
529
- # Create a new node v_n+1 with address = len(nodes) + 1
530
- new_node = {
531
- 'word': 'NONE',
532
- 'rel': 'NTOP',
533
- 'address': nr_vertices + 1,
534
- }
535
- # c_graph = Union(c_graph, v_n+1)
536
- c_graph.add_node(new_node)
537
- # Collapse all nodes in cycle C into v_n+1
538
- self.update_edge_scores(new_node, cycle_path)
539
- self.collapse_nodes(new_node, cycle_path, g_graph, b_graph, c_graph)
540
- for cycle_index in cycle_path:
541
- c_graph.add_arc(new_node['address'], cycle_index)
542
- # self.replaced_by[cycle_index] = new_node['address']
543
-
544
- self.inner_nodes[new_node['address']] = cycle_path
545
-
546
- # Add v_n+1 to list of unvisited vertices
547
- unvisited_vertices.insert(0, nr_vertices + 1)
548
-
549
- # increment # of nodes counter
550
- nr_vertices += 1
551
-
552
- # Remove cycle nodes from b_graph; B = B - cycle c
553
- for cycle_node_address in cycle_path:
554
- b_graph.remove_by_address(cycle_node_address)
555
-
556
- logger.debug('g_graph: %s', g_graph)
557
- logger.debug('b_graph: %s', b_graph)
558
- logger.debug('c_graph: %s', c_graph)
559
- logger.debug('Betas: %s', betas)
560
- logger.debug('replaced nodes %s', self.inner_nodes)
561
-
562
- # Recover parse tree
563
- logger.debug('Final scores: %s', self.scores)
564
-
565
- logger.debug('Recovering parse...')
566
- for i in range(len(tokens) + 1, nr_vertices + 1):
567
- betas[betas[i][1]] = betas[i]
568
-
569
- logger.debug('Betas: %s', betas)
570
- for node in original_graph.nodes.values():
571
- # TODO: It's dangerous to assume that deps it a dictionary
572
- # because it's a default dictionary. Ideally, here we should not
573
- # be concerned how dependencies are stored inside of a dependency
574
- # graph.
575
- node['deps'] = {}
576
- for i in range(1, len(tokens) + 1):
577
- original_graph.add_arc(betas[i][0], betas[i][1])
578
-
579
- logger.debug('Done.')
580
- yield original_graph
581
-
582
- #################################################################
583
- # Rule-based Non-Projective Parser
584
- #################################################################
585
-
586
-
587
- class NonprojectiveDependencyParser(object):
588
- """
589
- A non-projective, rule-based, dependency parser. This parser
590
- will return the set of all possible non-projective parses based on
591
- the word-to-word relations defined in the parser's dependency
592
- grammar, and will allow the branches of the parse tree to cross
593
- in order to capture a variety of linguistic phenomena that a
594
- projective parser will not.
595
- """
596
-
597
- def __init__(self, dependency_grammar):
598
- """
599
- Creates a new ``NonprojectiveDependencyParser``.
600
-
601
- :param dependency_grammar: a grammar of word-to-word relations.
602
- :type dependency_grammar: DependencyGrammar
603
- """
604
- self._grammar = dependency_grammar
605
-
606
- def parse(self, tokens):
607
- """
608
- Parses the input tokens with respect to the parser's grammar. Parsing
609
- is accomplished by representing the search-space of possible parses as
610
- a fully-connected directed graph. Arcs that would lead to ungrammatical
611
- parses are removed and a lattice is constructed of length n, where n is
612
- the number of input tokens, to represent all possible grammatical
613
- traversals. All possible paths through the lattice are then enumerated
614
- to produce the set of non-projective parses.
615
-
616
- param tokens: A list of tokens to parse.
617
- type tokens: list(str)
618
- return: An iterator of non-projective parses.
619
- rtype: iter(DependencyGraph)
620
- """
621
- # Create graph representation of tokens
622
- self._graph = DependencyGraph()
623
-
624
- for index, token in enumerate(tokens):
625
- self._graph.nodes[index] = {
626
- 'word': token,
627
- 'deps': [],
628
- 'rel': 'NTOP',
629
- 'address': index,
630
- }
631
-
632
- for head_node in self._graph.nodes.values():
633
- deps = []
634
- for dep_node in self._graph.nodes.values() :
635
- if (
636
- self._grammar.contains(head_node['word'], dep_node['word'])
637
- and head_node['word'] != dep_node['word']
638
- ):
639
- deps.append(dep_node['address'])
640
- head_node['deps'] = deps
641
-
642
- # Create lattice of possible heads
643
- roots = []
644
- possible_heads = []
645
- for i, word in enumerate(tokens):
646
- heads = []
647
- for j, head in enumerate(tokens):
648
- if (i != j) and self._grammar.contains(head, word):
649
- heads.append(j)
650
- if len(heads) == 0:
651
- roots.append(i)
652
- possible_heads.append(heads)
653
-
654
- # Set roots to attempt
655
- if len(roots) < 2:
656
- if len(roots) == 0:
657
- for i in range(len(tokens)):
658
- roots.append(i)
659
-
660
- # Traverse lattice
661
- analyses = []
662
- for root in roots:
663
- stack = []
664
- analysis = [[] for i in range(len(possible_heads))]
665
- i = 0
666
- forward = True
667
- while i >= 0:
668
- if forward:
669
- if len(possible_heads[i]) == 1:
670
- analysis[i] = possible_heads[i][0]
671
- elif len(possible_heads[i]) == 0:
672
- analysis[i] = -1
673
- else:
674
- head = possible_heads[i].pop()
675
- analysis[i] = head
676
- stack.append([i, head])
677
- if not forward:
678
- index_on_stack = False
679
- for stack_item in stack:
680
- if stack_item[0] == i:
681
- index_on_stack = True
682
- orig_length = len(possible_heads[i])
683
-
684
- if index_on_stack and orig_length == 0:
685
- for j in xrange(len(stack) - 1, -1, -1):
686
- stack_item = stack[j]
687
- if stack_item[0] == i:
688
- possible_heads[i].append(stack.pop(j)[1])
689
-
690
- elif index_on_stack and orig_length > 0:
691
- head = possible_heads[i].pop()
692
- analysis[i] = head
693
- stack.append([i, head])
694
- forward = True
695
-
696
- if i + 1 == len(possible_heads):
697
- analyses.append(analysis[:])
698
- forward = False
699
- if forward:
700
- i += 1
701
- else:
702
- i -= 1
703
-
704
- # Filter parses
705
- # ensure 1 root, every thing has 1 head
706
- for analysis in analyses:
707
- if analysis.count(-1) > 1:
708
- # there are several root elements!
709
- continue
710
-
711
- graph = DependencyGraph()
712
- graph.root = graph.nodes[analysis.index(-1) + 1]
713
-
714
- for address, (token, head_index) in enumerate(zip(tokens, analysis), start=1):
715
- head_address = head_index + 1
716
-
717
- node = graph.nodes[address]
718
- node.update(
719
- {
720
- 'word': token,
721
- 'address': address,
722
- }
723
- )
724
-
725
- if head_address == 0:
726
- rel = 'ROOT'
727
- else:
728
- rel = ''
729
- graph.nodes[head_index + 1]['deps'][rel].append(address)
730
-
731
- # TODO: check for cycles
732
- yield graph
733
-
734
-
735
- #################################################################
736
- # Demos
737
- #################################################################
738
-
739
- def demo():
740
- # hall_demo()
741
- nonprojective_conll_parse_demo()
742
- rule_based_demo()
743
-
744
-
745
- def hall_demo():
746
- npp = ProbabilisticNonprojectiveParser()
747
- npp.train([], DemoScorer())
748
- for parse_graph in npp.parse(['v1', 'v2', 'v3'], [None, None, None]):
749
- print(parse_graph)
750
-
751
-
752
- def nonprojective_conll_parse_demo():
753
- from nltk.parse.dependencygraph import conll_data2
754
-
755
- graphs = [
756
- DependencyGraph(entry) for entry in conll_data2.split('\n\n') if entry
757
- ]
758
- npp = ProbabilisticNonprojectiveParser()
759
- npp.train(graphs, NaiveBayesDependencyScorer())
760
- for parse_graph in npp.parse(['Cathy', 'zag', 'hen', 'zwaaien', '.'], ['N', 'V', 'Pron', 'Adj', 'N', 'Punc']):
761
- print(parse_graph)
762
-
763
-
764
- def rule_based_demo():
765
- from nltk.grammar import DependencyGrammar
766
-
767
- grammar = DependencyGrammar.fromstring("""
768
- 'taught' -> 'play' | 'man'
769
- 'man' -> 'the' | 'in'
770
- 'in' -> 'corner'
771
- 'corner' -> 'the'
772
- 'play' -> 'golf' | 'dachshund' | 'to'
773
- 'dachshund' -> 'his'
774
- """)
775
- print(grammar)
776
- ndp = NonprojectiveDependencyParser(grammar)
777
- graphs = ndp.parse(['the', 'man', 'in', 'the', 'corner', 'taught', 'his', 'dachshund', 'to', 'play', 'golf'])
778
- print('Graphs:')
779
- for graph in graphs:
780
- print(graph)
781
-
782
- if __name__ == '__main__':
783
- demo()
1
+ # Natural Language Toolkit: Dependency Grammars
2
+ #
3
+ # Copyright (C) 2001-2018 NLTK Project
4
+ # Author: Jason Narad <jason.narad@gmail.com>
5
+ #
6
+ # URL: <http://nltk.org/>
7
+ # For license information, see LICENSE.TXT
8
+ #
9
+ from __future__ import print_function
10
+
11
+ import math
12
+ import logging
13
+
14
+ from six.moves import range
15
+
16
+ from nltk.parse.dependencygraph import DependencyGraph
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ #################################################################
21
+ # DependencyScorerI - Interface for Graph-Edge Weight Calculation
22
+ #################################################################
23
+
24
+
25
+ class DependencyScorerI(object):
26
+ """
27
+ A scorer for calculated the weights on the edges of a weighted
28
+ dependency graph. This is used by a
29
+ ``ProbabilisticNonprojectiveParser`` to initialize the edge
30
+ weights of a ``DependencyGraph``. While typically this would be done
31
+ by training a binary classifier, any class that can return a
32
+ multidimensional list representation of the edge weights can
33
+ implement this interface. As such, it has no necessary
34
+ fields.
35
+ """
36
+
37
+ def __init__(self):
38
+ if self.__class__ == DependencyScorerI:
39
+ raise TypeError('DependencyScorerI is an abstract interface')
40
+
41
+ def train(self, graphs):
42
+ """
43
+ :type graphs: list(DependencyGraph)
44
+ :param graphs: A list of dependency graphs to train the scorer.
45
+ Typically the edges present in the graphs can be used as
46
+ positive training examples, and the edges not present as negative
47
+ examples.
48
+ """
49
+ raise NotImplementedError()
50
+
51
+ def score(self, graph):
52
+ """
53
+ :type graph: DependencyGraph
54
+ :param graph: A dependency graph whose set of edges need to be
55
+ scored.
56
+ :rtype: A three-dimensional list of numbers.
57
+ :return: The score is returned in a multidimensional(3) list, such
58
+ that the outer-dimension refers to the head, and the
59
+ inner-dimension refers to the dependencies. For instance,
60
+ scores[0][1] would reference the list of scores corresponding to
61
+ arcs from node 0 to node 1. The node's 'address' field can be used
62
+ to determine its number identification.
63
+
64
+ For further illustration, a score list corresponding to Fig.2 of
65
+ Keith Hall's 'K-best Spanning Tree Parsing' paper:
66
+ scores = [[[], [5], [1], [1]],
67
+ [[], [], [11], [4]],
68
+ [[], [10], [], [5]],
69
+ [[], [8], [8], []]]
70
+ When used in conjunction with a MaxEntClassifier, each score would
71
+ correspond to the confidence of a particular edge being classified
72
+ with the positive training examples.
73
+ """
74
+ raise NotImplementedError()
75
+
76
+ #################################################################
77
+ # NaiveBayesDependencyScorer
78
+ #################################################################
79
+
80
+
81
+ class NaiveBayesDependencyScorer(DependencyScorerI):
82
+ """
83
+ A dependency scorer built around a MaxEnt classifier. In this
84
+ particular class that classifier is a ``NaiveBayesClassifier``.
85
+ It uses head-word, head-tag, child-word, and child-tag features
86
+ for classification.
87
+
88
+ >>> from nltk.parse.dependencygraph import DependencyGraph, conll_data2
89
+
90
+ >>> graphs = [DependencyGraph(entry) for entry in conll_data2.split('\\n\\n') if entry]
91
+ >>> npp = ProbabilisticNonprojectiveParser()
92
+ >>> npp.train(graphs, NaiveBayesDependencyScorer())
93
+ >>> parses = npp.parse(['Cathy', 'zag', 'hen', 'zwaaien', '.'], ['N', 'V', 'Pron', 'Adj', 'N', 'Punc'])
94
+ >>> len(list(parses))
95
+ 1
96
+
97
+ """
98
+
99
+ def __init__(self):
100
+ pass # Do nothing without throwing error
101
+
102
+ def train(self, graphs):
103
+ """
104
+ Trains a ``NaiveBayesClassifier`` using the edges present in
105
+ graphs list as positive examples, the edges not present as
106
+ negative examples. Uses a feature vector of head-word,
107
+ head-tag, child-word, and child-tag.
108
+
109
+ :type graphs: list(DependencyGraph)
110
+ :param graphs: A list of dependency graphs to train the scorer.
111
+ """
112
+
113
+ from nltk.classify import NaiveBayesClassifier
114
+
115
+ # Create training labeled training examples
116
+ labeled_examples = []
117
+ for graph in graphs:
118
+ for head_node in graph.nodes.values():
119
+ for child_index, child_node in graph.nodes.items():
120
+ if child_index in head_node['deps']:
121
+ label = "T"
122
+ else:
123
+ label = "F"
124
+ labeled_examples.append(
125
+ (
126
+ dict(
127
+ a=head_node['word'],
128
+ b=head_node['tag'],
129
+ c=child_node['word'],
130
+ d=child_node['tag'],
131
+ ),
132
+ label,
133
+ )
134
+ )
135
+
136
+ self.classifier = NaiveBayesClassifier.train(labeled_examples)
137
+
138
+ def score(self, graph):
139
+ """
140
+ Converts the graph into a feature-based representation of
141
+ each edge, and then assigns a score to each based on the
142
+ confidence of the classifier in assigning it to the
143
+ positive label. Scores are returned in a multidimensional list.
144
+
145
+ :type graph: DependencyGraph
146
+ :param graph: A dependency graph to score.
147
+ :rtype: 3 dimensional list
148
+ :return: Edge scores for the graph parameter.
149
+ """
150
+ # Convert graph to feature representation
151
+ edges = []
152
+ for head_node in graph.nodes.values():
153
+ for child_node in graph.nodes.values():
154
+ edges.append(
155
+ (
156
+ dict(
157
+ a=head_node['word'],
158
+ b=head_node['tag'],
159
+ c=child_node['word'],
160
+ d=child_node['tag'],
161
+ )
162
+ )
163
+ )
164
+
165
+ # Score edges
166
+ edge_scores = []
167
+ row = []
168
+ count = 0
169
+ for pdist in self.classifier.prob_classify_many(edges):
170
+ logger.debug('%.4f %.4f', pdist.prob('T'), pdist.prob('F'))
171
+ # smoothing in case the probability = 0
172
+ row.append([math.log(pdist.prob("T")+0.00000000001)])
173
+ count += 1
174
+ if count == len(graph.nodes):
175
+ edge_scores.append(row)
176
+ row = []
177
+ count = 0
178
+ return edge_scores
179
+
180
+
181
+ #################################################################
182
+ # A Scorer for Demo Purposes
183
+ #################################################################
184
+ # A short class necessary to show parsing example from paper
185
+ class DemoScorer(DependencyScorerI):
186
+ def train(self, graphs):
187
+ print('Training...')
188
+
189
+ def score(self, graph):
190
+ # scores for Keith Hall 'K-best Spanning Tree Parsing' paper
191
+ return [[[], [5], [1], [1]],
192
+ [[], [], [11], [4]],
193
+ [[], [10], [], [5]],
194
+ [[], [8], [8], []]]
195
+
196
+ #################################################################
197
+ # Non-Projective Probabilistic Parsing
198
+ #################################################################
199
+
200
+
201
+ class ProbabilisticNonprojectiveParser(object):
202
+ """A probabilistic non-projective dependency parser.
203
+
204
+ Nonprojective dependencies allows for "crossing branches" in the parse tree
205
+ which is necessary for representing particular linguistic phenomena, or even
206
+ typical parses in some languages. This parser follows the MST parsing
207
+ algorithm, outlined in McDonald(2005), which likens the search for the best
208
+ non-projective parse to finding the maximum spanning tree in a weighted
209
+ directed graph.
210
+
211
+ >>> class Scorer(DependencyScorerI):
212
+ ... def train(self, graphs):
213
+ ... pass
214
+ ...
215
+ ... def score(self, graph):
216
+ ... return [
217
+ ... [[], [5], [1], [1]],
218
+ ... [[], [], [11], [4]],
219
+ ... [[], [10], [], [5]],
220
+ ... [[], [8], [8], []],
221
+ ... ]
222
+
223
+
224
+ >>> npp = ProbabilisticNonprojectiveParser()
225
+ >>> npp.train([], Scorer())
226
+
227
+ >>> parses = npp.parse(['v1', 'v2', 'v3'], [None, None, None])
228
+ >>> len(list(parses))
229
+ 1
230
+
231
+ Rule based example
232
+ ------------------
233
+
234
+ >>> from nltk.grammar import DependencyGrammar
235
+
236
+ >>> grammar = DependencyGrammar.fromstring('''
237
+ ... 'taught' -> 'play' | 'man'
238
+ ... 'man' -> 'the' | 'in'
239
+ ... 'in' -> 'corner'
240
+ ... 'corner' -> 'the'
241
+ ... 'play' -> 'golf' | 'dachshund' | 'to'
242
+ ... 'dachshund' -> 'his'
243
+ ... ''')
244
+
245
+ >>> ndp = NonprojectiveDependencyParser(grammar)
246
+ >>> parses = ndp.parse(['the', 'man', 'in', 'the', 'corner', 'taught', 'his', 'dachshund', 'to', 'play', 'golf'])
247
+ >>> len(list(parses))
248
+ 4
249
+
250
+ """
251
+ def __init__(self):
252
+ """
253
+ Creates a new non-projective parser.
254
+ """
255
+ logging.debug('initializing prob. nonprojective...')
256
+
257
+ def train(self, graphs, dependency_scorer):
258
+ """
259
+ Trains a ``DependencyScorerI`` from a set of ``DependencyGraph`` objects,
260
+ and establishes this as the parser's scorer. This is used to
261
+ initialize the scores on a ``DependencyGraph`` during the parsing
262
+ procedure.
263
+
264
+ :type graphs: list(DependencyGraph)
265
+ :param graphs: A list of dependency graphs to train the scorer.
266
+ :type dependency_scorer: DependencyScorerI
267
+ :param dependency_scorer: A scorer which implements the
268
+ ``DependencyScorerI`` interface.
269
+ """
270
+ self._scorer = dependency_scorer
271
+ self._scorer.train(graphs)
272
+
273
+ def initialize_edge_scores(self, graph):
274
+ """
275
+ Assigns a score to every edge in the ``DependencyGraph`` graph.
276
+ These scores are generated via the parser's scorer which
277
+ was assigned during the training process.
278
+
279
+ :type graph: DependencyGraph
280
+ :param graph: A dependency graph to assign scores to.
281
+ """
282
+ self.scores = self._scorer.score(graph)
283
+
284
+ def collapse_nodes(self, new_node, cycle_path, g_graph, b_graph, c_graph):
285
+ """
286
+ Takes a list of nodes that have been identified to belong to a cycle,
287
+ and collapses them into on larger node. The arcs of all nodes in
288
+ the graph must be updated to account for this.
289
+
290
+ :type new_node: Node.
291
+ :param new_node: A Node (Dictionary) to collapse the cycle nodes into.
292
+ :type cycle_path: A list of integers.
293
+ :param cycle_path: A list of node addresses, each of which is in the cycle.
294
+ :type g_graph, b_graph, c_graph: DependencyGraph
295
+ :param g_graph, b_graph, c_graph: Graphs which need to be updated.
296
+ """
297
+ logger.debug('Collapsing nodes...')
298
+ # Collapse all cycle nodes into v_n+1 in G_Graph
299
+ for cycle_node_index in cycle_path:
300
+ g_graph.remove_by_address(cycle_node_index)
301
+ g_graph.add_node(new_node)
302
+ g_graph.redirect_arcs(cycle_path, new_node['address'])
303
+
304
+ def update_edge_scores(self, new_node, cycle_path):
305
+ """
306
+ Updates the edge scores to reflect a collapse operation into
307
+ new_node.
308
+
309
+ :type new_node: A Node.
310
+ :param new_node: The node which cycle nodes are collapsed into.
311
+ :type cycle_path: A list of integers.
312
+ :param cycle_path: A list of node addresses that belong to the cycle.
313
+ """
314
+ logger.debug('cycle %s', cycle_path)
315
+
316
+ cycle_path = self.compute_original_indexes(cycle_path)
317
+
318
+ logger.debug('old cycle %s', cycle_path)
319
+ logger.debug('Prior to update: %s', self.scores)
320
+
321
+ for i, row in enumerate(self.scores):
322
+ for j, column in enumerate(self.scores[i]):
323
+ logger.debug(self.scores[i][j])
324
+ if (
325
+ j in cycle_path
326
+ and i not in cycle_path
327
+ and self.scores[i][j]
328
+ ):
329
+ subtract_val = self.compute_max_subtract_score(j, cycle_path)
330
+
331
+ logger.debug('%s - %s', self.scores[i][j], subtract_val)
332
+
333
+ new_vals = []
334
+ for cur_val in self.scores[i][j]:
335
+ new_vals.append(cur_val - subtract_val)
336
+
337
+ self.scores[i][j] = new_vals
338
+
339
+ for i, row in enumerate(self.scores):
340
+ for j, cell in enumerate(self.scores[i]):
341
+ if i in cycle_path and j in cycle_path:
342
+ self.scores[i][j] = []
343
+
344
+ logger.debug('After update: %s', self.scores)
345
+
346
+ def compute_original_indexes(self, new_indexes):
347
+ """
348
+ As nodes are collapsed into others, they are replaced
349
+ by the new node in the graph, but it's still necessary
350
+ to keep track of what these original nodes were. This
351
+ takes a list of node addresses and replaces any collapsed
352
+ node addresses with their original addresses.
353
+
354
+ :type new_indexes: A list of integers.
355
+ :param new_indexes: A list of node addresses to check for
356
+ subsumed nodes.
357
+ """
358
+ swapped = True
359
+ while swapped:
360
+ originals = []
361
+ swapped = False
362
+ for new_index in new_indexes:
363
+ if new_index in self.inner_nodes:
364
+ for old_val in self.inner_nodes[new_index]:
365
+ if old_val not in originals:
366
+ originals.append(old_val)
367
+ swapped = True
368
+ else:
369
+ originals.append(new_index)
370
+ new_indexes = originals
371
+ return new_indexes
372
+
373
+ def compute_max_subtract_score(self, column_index, cycle_indexes):
374
+ """
375
+ When updating scores the score of the highest-weighted incoming
376
+ arc is subtracted upon collapse. This returns the correct
377
+ amount to subtract from that edge.
378
+
379
+ :type column_index: integer.
380
+ :param column_index: A index representing the column of incoming arcs
381
+ to a particular node being updated
382
+ :type cycle_indexes: A list of integers.
383
+ :param cycle_indexes: Only arcs from cycle nodes are considered. This
384
+ is a list of such nodes addresses.
385
+ """
386
+ max_score = -100000
387
+ for row_index in cycle_indexes:
388
+ for subtract_val in self.scores[row_index][column_index]:
389
+ if subtract_val > max_score:
390
+ max_score = subtract_val
391
+ return max_score
392
+
393
+ def best_incoming_arc(self, node_index):
394
+ """
395
+ Returns the source of the best incoming arc to the
396
+ node with address: node_index
397
+
398
+ :type node_index: integer.
399
+ :param node_index: The address of the 'destination' node,
400
+ the node that is arced to.
401
+ """
402
+ originals = self.compute_original_indexes([node_index])
403
+ logger.debug('originals: %s', originals)
404
+
405
+ max_arc = None
406
+ max_score = None
407
+ for row_index in range(len(self.scores)):
408
+ for col_index in range(len(self.scores[row_index])):
409
+ # print self.scores[row_index][col_index]
410
+ if col_index in originals and (max_score is None or self.scores[row_index][col_index] > max_score):
411
+ max_score = self.scores[row_index][col_index]
412
+ max_arc = row_index
413
+ logger.debug('%s, %s', row_index, col_index)
414
+
415
+ logger.debug(max_score)
416
+
417
+ for key in self.inner_nodes:
418
+ replaced_nodes = self.inner_nodes[key]
419
+ if max_arc in replaced_nodes:
420
+ return key
421
+
422
+ return max_arc
423
+
424
+ def original_best_arc(self, node_index):
425
+ originals = self.compute_original_indexes([node_index])
426
+ max_arc = None
427
+ max_score = None
428
+ max_orig = None
429
+ for row_index in range(len(self.scores)):
430
+ for col_index in range(len(self.scores[row_index])):
431
+ if col_index in originals and (max_score is None or self.scores[row_index][col_index] > max_score):
432
+ max_score = self.scores[row_index][col_index]
433
+ max_arc = row_index
434
+ max_orig = col_index
435
+ return [max_arc, max_orig]
436
+
437
+ def parse(self, tokens, tags):
438
+ """
439
+ Parses a list of tokens in accordance to the MST parsing algorithm
440
+ for non-projective dependency parses. Assumes that the tokens to
441
+ be parsed have already been tagged and those tags are provided. Various
442
+ scoring methods can be used by implementing the ``DependencyScorerI``
443
+ interface and passing it to the training algorithm.
444
+
445
+ :type tokens: list(str)
446
+ :param tokens: A list of words or punctuation to be parsed.
447
+ :type tags: list(str)
448
+ :param tags: A list of tags corresponding by index to the words in the tokens list.
449
+ :return: An iterator of non-projective parses.
450
+ :rtype: iter(DependencyGraph)
451
+ """
452
+ self.inner_nodes = {}
453
+
454
+ # Initialize g_graph
455
+ g_graph = DependencyGraph()
456
+ for index, token in enumerate(tokens):
457
+ g_graph.nodes[index + 1].update(
458
+ {
459
+ 'word': token,
460
+ 'tag': tags[index],
461
+ 'rel': 'NTOP',
462
+ 'address': index + 1,
463
+ }
464
+ )
465
+ #print (g_graph.nodes)
466
+
467
+
468
+ # Fully connect non-root nodes in g_graph
469
+ g_graph.connect_graph()
470
+ original_graph = DependencyGraph()
471
+ for index, token in enumerate(tokens):
472
+ original_graph.nodes[index + 1].update(
473
+ {
474
+ 'word': token,
475
+ 'tag': tags[index],
476
+ 'rel': 'NTOP',
477
+ 'address': index+1,
478
+ }
479
+ )
480
+
481
+ b_graph = DependencyGraph()
482
+ c_graph = DependencyGraph()
483
+
484
+ for index, token in enumerate(tokens):
485
+ c_graph.nodes[index + 1].update(
486
+ {
487
+ 'word': token,
488
+ 'tag': tags[index],
489
+ 'rel': 'NTOP',
490
+ 'address': index + 1,
491
+ }
492
+ )
493
+
494
+ # Assign initial scores to g_graph edges
495
+ self.initialize_edge_scores(g_graph)
496
+ logger.debug(self.scores)
497
+ # Initialize a list of unvisited vertices (by node address)
498
+ unvisited_vertices = [
499
+ vertex['address'] for vertex in c_graph.nodes.values()
500
+ ]
501
+ # Iterate over unvisited vertices
502
+ nr_vertices = len(tokens)
503
+ betas = {}
504
+ while unvisited_vertices:
505
+ # Mark current node as visited
506
+ current_vertex = unvisited_vertices.pop(0)
507
+ logger.debug('current_vertex: %s', current_vertex)
508
+ # Get corresponding node n_i to vertex v_i
509
+ current_node = g_graph.get_by_address(current_vertex)
510
+ logger.debug('current_node: %s', current_node)
511
+ # Get best in-edge node b for current node
512
+ best_in_edge = self.best_incoming_arc(current_vertex)
513
+ betas[current_vertex] = self.original_best_arc(current_vertex)
514
+ logger.debug('best in arc: %s --> %s', best_in_edge, current_vertex)
515
+ # b_graph = Union(b_graph, b)
516
+ for new_vertex in [current_vertex, best_in_edge]:
517
+ b_graph.nodes[new_vertex].update(
518
+ {
519
+ 'word': 'TEMP',
520
+ 'rel': 'NTOP',
521
+ 'address': new_vertex,
522
+ }
523
+ )
524
+ b_graph.add_arc(best_in_edge, current_vertex)
525
+ # Beta(current node) = b - stored for parse recovery
526
+ # If b_graph contains a cycle, collapse it
527
+ cycle_path = b_graph.contains_cycle()
528
+ if cycle_path:
529
+ # Create a new node v_n+1 with address = len(nodes) + 1
530
+ new_node = {
531
+ 'word': 'NONE',
532
+ 'rel': 'NTOP',
533
+ 'address': nr_vertices + 1,
534
+ }
535
+ # c_graph = Union(c_graph, v_n+1)
536
+ c_graph.add_node(new_node)
537
+ # Collapse all nodes in cycle C into v_n+1
538
+ self.update_edge_scores(new_node, cycle_path)
539
+ self.collapse_nodes(new_node, cycle_path, g_graph, b_graph, c_graph)
540
+ for cycle_index in cycle_path:
541
+ c_graph.add_arc(new_node['address'], cycle_index)
542
+ # self.replaced_by[cycle_index] = new_node['address']
543
+
544
+ self.inner_nodes[new_node['address']] = cycle_path
545
+
546
+ # Add v_n+1 to list of unvisited vertices
547
+ unvisited_vertices.insert(0, nr_vertices + 1)
548
+
549
+ # increment # of nodes counter
550
+ nr_vertices += 1
551
+
552
+ # Remove cycle nodes from b_graph; B = B - cycle c
553
+ for cycle_node_address in cycle_path:
554
+ b_graph.remove_by_address(cycle_node_address)
555
+
556
+ logger.debug('g_graph: %s', g_graph)
557
+ logger.debug('b_graph: %s', b_graph)
558
+ logger.debug('c_graph: %s', c_graph)
559
+ logger.debug('Betas: %s', betas)
560
+ logger.debug('replaced nodes %s', self.inner_nodes)
561
+
562
+ # Recover parse tree
563
+ logger.debug('Final scores: %s', self.scores)
564
+
565
+ logger.debug('Recovering parse...')
566
+ for i in range(len(tokens) + 1, nr_vertices + 1):
567
+ betas[betas[i][1]] = betas[i]
568
+
569
+ logger.debug('Betas: %s', betas)
570
+ for node in original_graph.nodes.values():
571
+ # TODO: It's dangerous to assume that deps it a dictionary
572
+ # because it's a default dictionary. Ideally, here we should not
573
+ # be concerned how dependencies are stored inside of a dependency
574
+ # graph.
575
+ node['deps'] = {}
576
+ for i in range(1, len(tokens) + 1):
577
+ original_graph.add_arc(betas[i][0], betas[i][1])
578
+
579
+ logger.debug('Done.')
580
+ yield original_graph
581
+
582
+ #################################################################
583
+ # Rule-based Non-Projective Parser
584
+ #################################################################
585
+
586
+
587
+ class NonprojectiveDependencyParser(object):
588
+ """
589
+ A non-projective, rule-based, dependency parser. This parser
590
+ will return the set of all possible non-projective parses based on
591
+ the word-to-word relations defined in the parser's dependency
592
+ grammar, and will allow the branches of the parse tree to cross
593
+ in order to capture a variety of linguistic phenomena that a
594
+ projective parser will not.
595
+ """
596
+
597
+ def __init__(self, dependency_grammar):
598
+ """
599
+ Creates a new ``NonprojectiveDependencyParser``.
600
+
601
+ :param dependency_grammar: a grammar of word-to-word relations.
602
+ :type dependency_grammar: DependencyGrammar
603
+ """
604
+ self._grammar = dependency_grammar
605
+
606
+ def parse(self, tokens):
607
+ """
608
+ Parses the input tokens with respect to the parser's grammar. Parsing
609
+ is accomplished by representing the search-space of possible parses as
610
+ a fully-connected directed graph. Arcs that would lead to ungrammatical
611
+ parses are removed and a lattice is constructed of length n, where n is
612
+ the number of input tokens, to represent all possible grammatical
613
+ traversals. All possible paths through the lattice are then enumerated
614
+ to produce the set of non-projective parses.
615
+
616
+ param tokens: A list of tokens to parse.
617
+ type tokens: list(str)
618
+ return: An iterator of non-projective parses.
619
+ rtype: iter(DependencyGraph)
620
+ """
621
+ # Create graph representation of tokens
622
+ self._graph = DependencyGraph()
623
+
624
+ for index, token in enumerate(tokens):
625
+ self._graph.nodes[index] = {
626
+ 'word': token,
627
+ 'deps': [],
628
+ 'rel': 'NTOP',
629
+ 'address': index,
630
+ }
631
+
632
+ for head_node in self._graph.nodes.values():
633
+ deps = []
634
+ for dep_node in self._graph.nodes.values() :
635
+ if (
636
+ self._grammar.contains(head_node['word'], dep_node['word'])
637
+ and head_node['word'] != dep_node['word']
638
+ ):
639
+ deps.append(dep_node['address'])
640
+ head_node['deps'] = deps
641
+
642
+ # Create lattice of possible heads
643
+ roots = []
644
+ possible_heads = []
645
+ for i, word in enumerate(tokens):
646
+ heads = []
647
+ for j, head in enumerate(tokens):
648
+ if (i != j) and self._grammar.contains(head, word):
649
+ heads.append(j)
650
+ if len(heads) == 0:
651
+ roots.append(i)
652
+ possible_heads.append(heads)
653
+
654
+ # Set roots to attempt
655
+ if len(roots) < 2:
656
+ if len(roots) == 0:
657
+ for i in range(len(tokens)):
658
+ roots.append(i)
659
+
660
+ # Traverse lattice
661
+ analyses = []
662
+ for root in roots:
663
+ stack = []
664
+ analysis = [[] for i in range(len(possible_heads))]
665
+ i = 0
666
+ forward = True
667
+ while i >= 0:
668
+ if forward:
669
+ if len(possible_heads[i]) == 1:
670
+ analysis[i] = possible_heads[i][0]
671
+ elif len(possible_heads[i]) == 0:
672
+ analysis[i] = -1
673
+ else:
674
+ head = possible_heads[i].pop()
675
+ analysis[i] = head
676
+ stack.append([i, head])
677
+ if not forward:
678
+ index_on_stack = False
679
+ for stack_item in stack:
680
+ if stack_item[0] == i:
681
+ index_on_stack = True
682
+ orig_length = len(possible_heads[i])
683
+
684
+ if index_on_stack and orig_length == 0:
685
+ for j in range(len(stack) - 1, -1, -1):
686
+ stack_item = stack[j]
687
+ if stack_item[0] == i:
688
+ possible_heads[i].append(stack.pop(j)[1])
689
+
690
+ elif index_on_stack and orig_length > 0:
691
+ head = possible_heads[i].pop()
692
+ analysis[i] = head
693
+ stack.append([i, head])
694
+ forward = True
695
+
696
+ if i + 1 == len(possible_heads):
697
+ analyses.append(analysis[:])
698
+ forward = False
699
+ if forward:
700
+ i += 1
701
+ else:
702
+ i -= 1
703
+
704
+ # Filter parses
705
+ # ensure 1 root, every thing has 1 head
706
+ for analysis in analyses:
707
+ if analysis.count(-1) > 1:
708
+ # there are several root elements!
709
+ continue
710
+
711
+ graph = DependencyGraph()
712
+ graph.root = graph.nodes[analysis.index(-1) + 1]
713
+
714
+ for address, (token, head_index) in enumerate(zip(tokens, analysis), start=1):
715
+ head_address = head_index + 1
716
+
717
+ node = graph.nodes[address]
718
+ node.update(
719
+ {
720
+ 'word': token,
721
+ 'address': address,
722
+ }
723
+ )
724
+
725
+ if head_address == 0:
726
+ rel = 'ROOT'
727
+ else:
728
+ rel = ''
729
+ graph.nodes[head_index + 1]['deps'][rel].append(address)
730
+
731
+ # TODO: check for cycles
732
+ yield graph
733
+
734
+
735
+ #################################################################
736
+ # Demos
737
+ #################################################################
738
+
739
+ def demo():
740
+ # hall_demo()
741
+ nonprojective_conll_parse_demo()
742
+ rule_based_demo()
743
+
744
+
745
+ def hall_demo():
746
+ npp = ProbabilisticNonprojectiveParser()
747
+ npp.train([], DemoScorer())
748
+ for parse_graph in npp.parse(['v1', 'v2', 'v3'], [None, None, None]):
749
+ print(parse_graph)
750
+
751
+
752
+ def nonprojective_conll_parse_demo():
753
+ from nltk.parse.dependencygraph import conll_data2
754
+
755
+ graphs = [
756
+ DependencyGraph(entry) for entry in conll_data2.split('\n\n') if entry
757
+ ]
758
+ npp = ProbabilisticNonprojectiveParser()
759
+ npp.train(graphs, NaiveBayesDependencyScorer())
760
+ for parse_graph in npp.parse(['Cathy', 'zag', 'hen', 'zwaaien', '.'], ['N', 'V', 'Pron', 'Adj', 'N', 'Punc']):
761
+ print(parse_graph)
762
+
763
+
764
+ def rule_based_demo():
765
+ from nltk.grammar import DependencyGrammar
766
+
767
+ grammar = DependencyGrammar.fromstring("""
768
+ 'taught' -> 'play' | 'man'
769
+ 'man' -> 'the' | 'in'
770
+ 'in' -> 'corner'
771
+ 'corner' -> 'the'
772
+ 'play' -> 'golf' | 'dachshund' | 'to'
773
+ 'dachshund' -> 'his'
774
+ """)
775
+ print(grammar)
776
+ ndp = NonprojectiveDependencyParser(grammar)
777
+ graphs = ndp.parse(['the', 'man', 'in', 'the', 'corner', 'taught', 'his', 'dachshund', 'to', 'play', 'golf'])
778
+ print('Graphs:')
779
+ for graph in graphs:
780
+ print(graph)
781
+
782
+ if __name__ == '__main__':
783
+ demo()