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,758 +1,760 @@
1
- # Natural Language Toolkit: Dependency Grammars
2
- #
3
- # Copyright (C) 2001-2015 NLTK Project
4
- # Author: Jason Narad <jason.narad@gmail.com>
5
- # Steven Bird <stevenbird1@gmail.com> (modifications)
6
- #
7
- # URL: <http://nltk.org/>
8
- # For license information, see LICENSE.TXT
9
- #
10
-
11
- """
12
- Tools for reading and writing dependency trees.
13
- The input is assumed to be in Malt-TAB format
14
- (http://stp.lingfil.uu.se/~nivre/research/MaltXML.html).
15
- """
16
- from __future__ import print_function, unicode_literals
17
-
18
- from collections import defaultdict
19
- from itertools import chain
20
- from pprint import pformat
21
- import subprocess
22
- import warnings
23
-
24
- from nltk.tree import Tree
25
- from nltk.compat import python_2_unicode_compatible, string_types
26
-
27
-
28
- #################################################################
29
- # DependencyGraph Class
30
- #################################################################
31
-
32
-
33
- @python_2_unicode_compatible
34
- class DependencyGraph(object):
35
- """
36
- A container for the nodes and labelled edges of a dependency structure.
37
- """
38
-
39
- def __init__(self, tree_str=None, cell_extractor=None, zero_based=False, cell_separator=None, top_relation_label='ROOT'):
40
- """Dependency graph.
41
-
42
- We place a dummy `TOP` node with the index 0, since the root node is
43
- often assigned 0 as its head. This also means that the indexing of the
44
- nodes corresponds directly to the Malt-TAB format, which starts at 1.
45
-
46
- If zero-based is True, then Malt-TAB-like input with node numbers
47
- starting at 0 and the root node assigned -1 (as produced by, e.g.,
48
- zpar).
49
-
50
- :param str cell_separator: the cell separator. If not provided, cells
51
- are split by whitespace.
52
-
53
- :param str top_relation_label: the label by which the top relation is
54
- identified, for examlple, `ROOT`, `null` or `TOP`.
55
-
56
- """
57
- self.nodes = defaultdict(lambda: {'address': None,
58
- 'word': None,
59
- 'lemma': None,
60
- 'ctag': None,
61
- 'tag': None,
62
- 'feats': None,
63
- 'head': None,
64
- 'deps': defaultdict(list),
65
- 'rel': None,
66
- })
67
-
68
- self.nodes[0].update(
69
- {
70
- 'ctag': 'TOP',
71
- 'tag': 'TOP',
72
- 'address': 0,
73
- }
74
- )
75
-
76
- self.root = None
77
-
78
- if tree_str:
79
- self._parse(
80
- tree_str,
81
- cell_extractor=cell_extractor,
82
- zero_based=zero_based,
83
- cell_separator=cell_separator,
84
- top_relation_label=top_relation_label,
85
- )
86
-
87
- def remove_by_address(self, address):
88
- """
89
- Removes the node with the given address. References
90
- to this node in others will still exist.
91
- """
92
- del self.nodes[address]
93
-
94
- def redirect_arcs(self, originals, redirect):
95
- """
96
- Redirects arcs to any of the nodes in the originals list
97
- to the redirect node address.
98
- """
99
- for node in self.nodes.values():
100
- new_deps = []
101
- for dep in node['deps']:
102
- if dep in originals:
103
- new_deps.append(redirect)
104
- else:
105
- new_deps.append(dep)
106
- node['deps'] = new_deps
107
-
108
- def add_arc(self, head_address, mod_address):
109
- """
110
- Adds an arc from the node specified by head_address to the
111
- node specified by the mod address.
112
- """
113
- relation = self.nodes[mod_address]['rel']
114
- self.nodes[head_address]['deps'].setdefault(relation, [])
115
- self.nodes[head_address]['deps'][relation].append(mod_address)
116
- #self.nodes[head_address]['deps'].append(mod_address)
117
-
118
-
119
- def connect_graph(self):
120
- """
121
- Fully connects all non-root nodes. All nodes are set to be dependents
122
- of the root node.
123
- """
124
- for node1 in self.nodes.values():
125
- for node2 in self.nodes.values():
126
- if node1['address'] != node2['address'] and node2['rel'] != 'TOP':
127
- relation = node2['rel']
128
- node1['deps'].setdefault(relation, [])
129
- node1['deps'][relation].append(node2['address'])
130
- #node1['deps'].append(node2['address'])
131
-
132
- def get_by_address(self, node_address):
133
- """Return the node with the given address."""
134
- return self.nodes[node_address]
135
-
136
- def contains_address(self, node_address):
137
- """
138
- Returns true if the graph contains a node with the given node
139
- address, false otherwise.
140
- """
141
- return node_address in self.nodes
142
-
143
- def to_dot(self):
144
- """Return a dot representation suitable for using with Graphviz.
145
-
146
- >>> dg = DependencyGraph(
147
- ... 'John N 2\\n'
148
- ... 'loves V 0\\n'
149
- ... 'Mary N 2'
150
- ... )
151
- >>> print(dg.to_dot())
152
- digraph G{
153
- edge [dir=forward]
154
- node [shape=plaintext]
155
- <BLANKLINE>
156
- 0 [label="0 (None)"]
157
- 0 -> 2 [label="ROOT"]
158
- 1 [label="1 (John)"]
159
- 2 [label="2 (loves)"]
160
- 2 -> 1 [label=""]
161
- 2 -> 3 [label=""]
162
- 3 [label="3 (Mary)"]
163
- }
164
-
165
- """
166
- # Start the digraph specification
167
- s = 'digraph G{\n'
168
- s += 'edge [dir=forward]\n'
169
- s += 'node [shape=plaintext]\n'
170
-
171
- # Draw the remaining nodes
172
- for node in sorted(self.nodes.values(), key=lambda v: v['address']):
173
- s += '\n%s [label="%s (%s)"]' % (node['address'], node['address'], node['word'])
174
- for rel, deps in node['deps'].items():
175
- for dep in deps:
176
- if rel is not None:
177
- s += '\n%s -> %s [label="%s"]' % (node['address'], dep, rel)
178
- else:
179
- s += '\n%s -> %s ' % (node['address'], dep)
180
- s += "\n}"
181
-
182
- return s
183
-
184
- def _repr_svg_(self):
185
- """Show SVG representation of the transducer (IPython magic).
186
-
187
- >>> dg = DependencyGraph(
188
- ... 'John N 2\\n'
189
- ... 'loves V 0\\n'
190
- ... 'Mary N 2'
191
- ... )
192
- >>> dg._repr_svg_().split('\\n')[0]
193
- '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
194
-
195
- """
196
- dot_string = self.to_dot()
197
-
198
- try:
199
- process = subprocess.Popen(
200
- ['dot', '-Tsvg'],
201
- stdin=subprocess.PIPE,
202
- stdout=subprocess.PIPE,
203
- stderr=subprocess.PIPE,
204
- universal_newlines=True,
205
- )
206
- except OSError:
207
- raise Exception('Cannot find the dot binary from Graphviz package')
208
- out, err = process.communicate(dot_string)
209
- if err:
210
- raise Exception(
211
- 'Cannot create svg representation by running dot from string: {}'
212
- ''.format(dot_string))
213
- return out
214
-
215
- def __str__(self):
216
- return pformat(self.nodes)
217
-
218
- def __repr__(self):
219
- return "<DependencyGraph with {0} nodes>".format(len(self.nodes))
220
-
221
- @staticmethod
222
- def load(filename, zero_based=False, cell_separator=None, top_relation_label='ROOT'):
223
- """
224
- :param filename: a name of a file in Malt-TAB format
225
- :param zero_based: nodes in the input file are numbered starting from 0
226
- rather than 1 (as produced by, e.g., zpar)
227
- :param str cell_separator: the cell separator. If not provided, cells
228
- are split by whitespace.
229
- :param str top_relation_label: the label by which the top relation is
230
- identified, for examlple, `ROOT`, `null` or `TOP`.
231
-
232
- :return: a list of DependencyGraphs
233
-
234
- """
235
- with open(filename) as infile:
236
- return [
237
- DependencyGraph(
238
- tree_str,
239
- zero_based=zero_based,
240
- cell_separator=cell_separator,
241
- top_relation_label=top_relation_label,
242
- )
243
- for tree_str in infile.read().split('\n\n')
244
- ]
245
-
246
- def left_children(self, node_index):
247
- """
248
- Returns the number of left children under the node specified
249
- by the given address.
250
- """
251
- children = chain.from_iterable(self.nodes[node_index]['deps'].values())
252
- index = self.nodes[node_index]['address']
253
- return sum(1 for c in children if c < index)
254
-
255
- def right_children(self, node_index):
256
- """
257
- Returns the number of right children under the node specified
258
- by the given address.
259
- """
260
- children = chain.from_iterable(self.nodes[node_index]['deps'].values())
261
- index = self.nodes[node_index]['address']
262
- return sum(1 for c in children if c > index)
263
-
264
- def add_node(self, node):
265
- if not self.contains_address(node['address']):
266
- self.nodes[node['address']].update(node)
267
-
268
- def _parse(self, input_, cell_extractor=None, zero_based=False, cell_separator=None, top_relation_label='ROOT'):
269
- """Parse a sentence.
270
-
271
- :param extractor: a function that given a tuple of cells returns a
272
- 7-tuple, where the values are ``word, lemma, ctag, tag, feats, head,
273
- rel``.
274
-
275
- :param str cell_separator: the cell separator. If not provided, cells
276
- are split by whitespace.
277
-
278
- :param str top_relation_label: the label by which the top relation is
279
- identified, for examlple, `ROOT`, `null` or `TOP`.
280
-
281
- """
282
-
283
- def extract_3_cells(cells, index):
284
- word, tag, head = cells
285
- return index, word, word, tag, tag, '', head, ''
286
-
287
- def extract_4_cells(cells, index):
288
- word, tag, head, rel = cells
289
- return index, word, word, tag, tag, '', head, rel
290
-
291
- def extract_7_cells(cells, index):
292
- line_index, word, lemma, tag, _, head, rel = cells
293
- try:
294
- index = int(line_index)
295
- except ValueError:
296
- # index can't be parsed as an integer, use default
297
- pass
298
- return index, word, lemma, tag, tag, '', head, rel
299
-
300
- def extract_10_cells(cells, index):
301
- line_index, word, lemma, ctag, tag, feats, head, rel, _, _ = cells
302
- try:
303
- index = int(line_index)
304
- except ValueError:
305
- # index can't be parsed as an integer, use default
306
- pass
307
- return index, word, lemma, ctag, tag, feats, head, rel
308
-
309
- extractors = {
310
- 3: extract_3_cells,
311
- 4: extract_4_cells,
312
- 7: extract_7_cells,
313
- 10: extract_10_cells,
314
- }
315
-
316
- if isinstance(input_, string_types):
317
- input_ = (line for line in input_.split('\n'))
318
-
319
- lines = (l.rstrip() for l in input_)
320
- lines = (l for l in lines if l)
321
-
322
- cell_number = None
323
- for index, line in enumerate(lines, start=1):
324
- cells = line.split(cell_separator)
325
- if cell_number is None:
326
- cell_number = len(cells)
327
- else:
328
- assert cell_number == len(cells)
329
-
330
- if cell_extractor is None:
331
- try:
332
- cell_extractor = extractors[cell_number]
333
- except KeyError:
334
- raise ValueError(
335
- 'Number of tab-delimited fields ({0}) not supported by '
336
- 'CoNLL(10) or Malt-Tab(4) format'.format(cell_number)
337
- )
338
-
339
- try:
340
- index, word, lemma, ctag, tag, feats, head, rel = cell_extractor(cells, index)
341
- except (TypeError, ValueError):
342
- # cell_extractor doesn't take 2 arguments or doesn't return 8
343
- # values; assume the cell_extractor is an older external
344
- # extractor and doesn't accept or return an index.
345
- word, lemma, ctag, tag, feats, head, rel = cell_extractor(cells)
346
-
347
- if head == '_':
348
- continue
349
-
350
- head = int(head)
351
- if zero_based:
352
- head += 1
353
-
354
- self.nodes[index].update(
355
- {
356
- 'address': index,
357
- 'word': word,
358
- 'lemma': lemma,
359
- 'ctag': ctag,
360
- 'tag': tag,
361
- 'feats': feats,
362
- 'head': head,
363
- 'rel': rel,
364
- }
365
- )
366
-
367
- # Make sure that the fake root node has labeled dependencies.
368
- if (cell_number == 3) and (head == 0):
369
- rel = top_relation_label
370
- self.nodes[head]['deps'][rel].append(index)
371
-
372
- if self.nodes[0]['deps'][top_relation_label]:
373
- root_address = self.nodes[0]['deps'][top_relation_label][0]
374
- self.root = self.nodes[root_address]
375
- self.top_relation_label = top_relation_label
376
- else:
377
- warnings.warn(
378
- "The graph doesn't contain a node "
379
- "that depends on the root element."
380
- )
381
-
382
- def _word(self, node, filter=True):
383
- w = node['word']
384
- if filter:
385
- if w != ',':
386
- return w
387
- return w
388
-
389
- def _tree(self, i):
390
- """ Turn dependency graphs into NLTK trees.
391
-
392
- :param int i: index of a node
393
- :return: either a word (if the indexed node is a leaf) or a ``Tree``.
394
- """
395
- node = self.get_by_address(i)
396
- word = node['word']
397
- deps = sorted(chain.from_iterable(node['deps'].values()))
398
-
399
- if deps:
400
- return Tree(word, [self._tree(dep) for dep in deps])
401
- else:
402
- return word
403
-
404
- def tree(self):
405
- """
406
- Starting with the ``root`` node, build a dependency tree using the NLTK
407
- ``Tree`` constructor. Dependency labels are omitted.
408
- """
409
- node = self.root
410
-
411
- word = node['word']
412
- deps = sorted(chain.from_iterable(node['deps'].values()))
413
- return Tree(word, [self._tree(dep) for dep in deps])
414
-
415
- def triples(self, node=None):
416
- """
417
- Extract dependency triples of the form:
418
- ((head word, head tag), rel, (dep word, dep tag))
419
- """
420
-
421
- if not node:
422
- node = self.root
423
-
424
- head = (node['word'], node['ctag'])
425
- for i in sorted(chain.from_iterable(node['deps'].values())):
426
- dep = self.get_by_address(i)
427
- yield (head, dep['rel'], (dep['word'], dep['ctag']))
428
- for triple in self.triples(node=dep):
429
- yield triple
430
-
431
- def _hd(self, i):
432
- try:
433
- return self.nodes[i]['head']
434
- except IndexError:
435
- return None
436
-
437
- def _rel(self, i):
438
- try:
439
- return self.nodes[i]['rel']
440
- except IndexError:
441
- return None
442
-
443
- # what's the return type? Boolean or list?
444
- def contains_cycle(self):
445
- """Check whether there are cycles.
446
-
447
- >>> dg = DependencyGraph(treebank_data)
448
- >>> dg.contains_cycle()
449
- False
450
-
451
- >>> cyclic_dg = DependencyGraph()
452
- >>> top = {'word': None, 'deps': [1], 'rel': 'TOP', 'address': 0}
453
- >>> child1 = {'word': None, 'deps': [2], 'rel': 'NTOP', 'address': 1}
454
- >>> child2 = {'word': None, 'deps': [4], 'rel': 'NTOP', 'address': 2}
455
- >>> child3 = {'word': None, 'deps': [1], 'rel': 'NTOP', 'address': 3}
456
- >>> child4 = {'word': None, 'deps': [3], 'rel': 'NTOP', 'address': 4}
457
- >>> cyclic_dg.nodes = {
458
- ... 0: top,
459
- ... 1: child1,
460
- ... 2: child2,
461
- ... 3: child3,
462
- ... 4: child4,
463
- ... }
464
- >>> cyclic_dg.root = top
465
-
466
- >>> cyclic_dg.contains_cycle()
467
- [3, 1, 2, 4]
468
-
469
- """
470
- distances = {}
471
-
472
- for node in self.nodes.values():
473
- for dep in node['deps']:
474
- key = tuple([node['address'], dep])
475
- distances[key] = 1
476
-
477
- for _ in self.nodes:
478
- new_entries = {}
479
-
480
- for pair1 in distances:
481
- for pair2 in distances:
482
- if pair1[1] == pair2[0]:
483
- key = tuple([pair1[0], pair2[1]])
484
- new_entries[key] = distances[pair1] + distances[pair2]
485
-
486
- for pair in new_entries:
487
- distances[pair] = new_entries[pair]
488
- if pair[0] == pair[1]:
489
- path = self.get_cycle_path(self.get_by_address(pair[0]), pair[0])
490
- return path
491
-
492
- return False # return []?
493
-
494
- def get_cycle_path(self, curr_node, goal_node_index):
495
- for dep in curr_node['deps']:
496
- if dep == goal_node_index:
497
- return [curr_node['address']]
498
- for dep in curr_node['deps']:
499
- path = self.get_cycle_path(self.get_by_address(dep), goal_node_index)
500
- if len(path) > 0:
501
- path.insert(0, curr_node['address'])
502
- return path
503
- return []
504
-
505
- def to_conll(self, style):
506
- """
507
- The dependency graph in CoNLL format.
508
-
509
- :param style: the style to use for the format (3, 4, 10 columns)
510
- :type style: int
511
- :rtype: str
512
- """
513
-
514
- if style == 3:
515
- template = '{word}\t{tag}\t{head}\n'
516
- elif style == 4:
517
- template = '{word}\t{tag}\t{head}\t{rel}\n'
518
- elif style == 10:
519
- template = '{i}\t{word}\t{lemma}\t{ctag}\t{tag}\t{feats}\t{head}\t{rel}\t_\t_\n'
520
- else:
521
- raise ValueError(
522
- 'Number of tab-delimited fields ({0}) not supported by '
523
- 'CoNLL(10) or Malt-Tab(4) format'.format(style)
524
- )
525
-
526
- return ''.join(template.format(i=i, **node) for i, node in sorted(self.nodes.items()) if node['tag'] != 'TOP')
527
-
528
- def nx_graph(self):
529
- """Convert the data in a ``nodelist`` into a networkx labeled directed graph."""
530
- import networkx
531
-
532
- nx_nodelist = list(range(1, len(self.nodes)))
533
- nx_edgelist = [
534
- (n, self._hd(n), self._rel(n))
535
- for n in nx_nodelist if self._hd(n)
536
- ]
537
- self.nx_labels = {}
538
- for n in nx_nodelist:
539
- self.nx_labels[n] = self.nodes[n]['word']
540
-
541
- g = networkx.MultiDiGraph()
542
- g.add_nodes_from(nx_nodelist)
543
- g.add_edges_from(nx_edgelist)
544
-
545
- return g
546
-
547
-
548
- class DependencyGraphError(Exception):
549
- """Dependency graph exception."""
550
-
551
-
552
- def demo():
553
- malt_demo()
554
- conll_demo()
555
- conll_file_demo()
556
- cycle_finding_demo()
557
-
558
-
559
- def malt_demo(nx=False):
560
- """
561
- A demonstration of the result of reading a dependency
562
- version of the first sentence of the Penn Treebank.
563
- """
564
- dg = DependencyGraph("""Pierre NNP 2 NMOD
565
- Vinken NNP 8 SUB
566
- , , 2 P
567
- 61 CD 5 NMOD
568
- years NNS 6 AMOD
569
- old JJ 2 NMOD
570
- , , 2 P
571
- will MD 0 ROOT
572
- join VB 8 VC
573
- the DT 11 NMOD
574
- board NN 9 OBJ
575
- as IN 9 VMOD
576
- a DT 15 NMOD
577
- nonexecutive JJ 15 NMOD
578
- director NN 12 PMOD
579
- Nov. NNP 9 VMOD
580
- 29 CD 16 NMOD
581
- . . 9 VMOD
582
- """)
583
- tree = dg.tree()
584
- tree.pprint()
585
- if nx:
586
- # currently doesn't work
587
- import networkx
588
- from matplotlib import pylab
589
-
590
- g = dg.nx_graph()
591
- g.info()
592
- pos = networkx.spring_layout(g, dim=1)
593
- networkx.draw_networkx_nodes(g, pos, node_size=50)
594
- # networkx.draw_networkx_edges(g, pos, edge_color='k', width=8)
595
- networkx.draw_networkx_labels(g, pos, dg.nx_labels)
596
- pylab.xticks([])
597
- pylab.yticks([])
598
- pylab.savefig('tree.png')
599
- pylab.show()
600
-
601
-
602
- def conll_demo():
603
- """
604
- A demonstration of how to read a string representation of
605
- a CoNLL format dependency tree.
606
- """
607
- dg = DependencyGraph(conll_data1)
608
- tree = dg.tree()
609
- tree.pprint()
610
- print(dg)
611
- print(dg.to_conll(4))
612
-
613
-
614
- def conll_file_demo():
615
- print('Mass conll_read demo...')
616
- graphs = [DependencyGraph(entry)
617
- for entry in conll_data2.split('\n\n') if entry]
618
- for graph in graphs:
619
- tree = graph.tree()
620
- print('\n')
621
- tree.pprint()
622
-
623
-
624
- def cycle_finding_demo():
625
- dg = DependencyGraph(treebank_data)
626
- print(dg.contains_cycle())
627
- cyclic_dg = DependencyGraph()
628
- cyclic_dg.add_node({'word': None, 'deps': [1], 'rel': 'TOP', 'address': 0})
629
- cyclic_dg.add_node({'word': None, 'deps': [2], 'rel': 'NTOP', 'address': 1})
630
- cyclic_dg.add_node({'word': None, 'deps': [4], 'rel': 'NTOP', 'address': 2})
631
- cyclic_dg.add_node({'word': None, 'deps': [1], 'rel': 'NTOP', 'address': 3})
632
- cyclic_dg.add_node({'word': None, 'deps': [3], 'rel': 'NTOP', 'address': 4})
633
- print(cyclic_dg.contains_cycle())
634
-
635
- treebank_data = """Pierre NNP 2 NMOD
636
- Vinken NNP 8 SUB
637
- , , 2 P
638
- 61 CD 5 NMOD
639
- years NNS 6 AMOD
640
- old JJ 2 NMOD
641
- , , 2 P
642
- will MD 0 ROOT
643
- join VB 8 VC
644
- the DT 11 NMOD
645
- board NN 9 OBJ
646
- as IN 9 VMOD
647
- a DT 15 NMOD
648
- nonexecutive JJ 15 NMOD
649
- director NN 12 PMOD
650
- Nov. NNP 9 VMOD
651
- 29 CD 16 NMOD
652
- . . 9 VMOD
653
- """
654
-
655
- conll_data1 = """
656
- 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
657
- 2 had heb V V trans|ovt|1of2of3|ev 0 ROOT _ _
658
- 3 met met Prep Prep voor 8 mod _ _
659
- 4 haar haar Pron Pron bez|3|ev|neut|attr 5 det _ _
660
- 5 moeder moeder N N soort|ev|neut 3 obj1 _ _
661
- 6 kunnen kan V V hulp|ott|1of2of3|mv 2 vc _ _
662
- 7 gaan ga V V hulp|inf 6 vc _ _
663
- 8 winkelen winkel V V intrans|inf 11 cnj _ _
664
- 9 , , Punc Punc komma 8 punct _ _
665
- 10 zwemmen zwem V V intrans|inf 11 cnj _ _
666
- 11 of of Conj Conj neven 7 vc _ _
667
- 12 terrassen terras N N soort|mv|neut 11 cnj _ _
668
- 13 . . Punc Punc punt 12 punct _ _
669
- """
670
-
671
- conll_data2 = """1 Cathy Cathy N N eigen|ev|neut 2 su _ _
672
- 2 zag zie V V trans|ovt|1of2of3|ev 0 ROOT _ _
673
- 3 hen hen Pron Pron per|3|mv|datofacc 2 obj1 _ _
674
- 4 wild wild Adj Adj attr|stell|onverv 5 mod _ _
675
- 5 zwaaien zwaai N N soort|mv|neut 2 vc _ _
676
- 6 . . Punc Punc punt 5 punct _ _
677
-
678
- 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
679
- 2 had heb V V trans|ovt|1of2of3|ev 0 ROOT _ _
680
- 3 met met Prep Prep voor 8 mod _ _
681
- 4 haar haar Pron Pron bez|3|ev|neut|attr 5 det _ _
682
- 5 moeder moeder N N soort|ev|neut 3 obj1 _ _
683
- 6 kunnen kan V V hulp|ott|1of2of3|mv 2 vc _ _
684
- 7 gaan ga V V hulp|inf 6 vc _ _
685
- 8 winkelen winkel V V intrans|inf 11 cnj _ _
686
- 9 , , Punc Punc komma 8 punct _ _
687
- 10 zwemmen zwem V V intrans|inf 11 cnj _ _
688
- 11 of of Conj Conj neven 7 vc _ _
689
- 12 terrassen terras N N soort|mv|neut 11 cnj _ _
690
- 13 . . Punc Punc punt 12 punct _ _
691
-
692
- 1 Dat dat Pron Pron aanw|neut|attr 2 det _ _
693
- 2 werkwoord werkwoord N N soort|ev|neut 6 obj1 _ _
694
- 3 had heb V V hulp|ovt|1of2of3|ev 0 ROOT _ _
695
- 4 ze ze Pron Pron per|3|evofmv|nom 6 su _ _
696
- 5 zelf zelf Pron Pron aanw|neut|attr|wzelf 3 predm _ _
697
- 6 uitgevonden vind V V trans|verldw|onverv 3 vc _ _
698
- 7 . . Punc Punc punt 6 punct _ _
699
-
700
- 1 Het het Pron Pron onbep|neut|zelfst 2 su _ _
701
- 2 hoorde hoor V V trans|ovt|1of2of3|ev 0 ROOT _ _
702
- 3 bij bij Prep Prep voor 2 ld _ _
703
- 4 de de Art Art bep|zijdofmv|neut 6 det _ _
704
- 5 warme warm Adj Adj attr|stell|vervneut 6 mod _ _
705
- 6 zomerdag zomerdag N N soort|ev|neut 3 obj1 _ _
706
- 7 die die Pron Pron betr|neut|zelfst 6 mod _ _
707
- 8 ze ze Pron Pron per|3|evofmv|nom 12 su _ _
708
- 9 ginds ginds Adv Adv gew|aanw 12 mod _ _
709
- 10 achter achter Adv Adv gew|geenfunc|stell|onverv 12 svp _ _
710
- 11 had heb V V hulp|ovt|1of2of3|ev 7 body _ _
711
- 12 gelaten laat V V trans|verldw|onverv 11 vc _ _
712
- 13 . . Punc Punc punt 12 punct _ _
713
-
714
- 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
715
- 2 hadden heb V V trans|ovt|1of2of3|mv 0 ROOT _ _
716
- 3 languit languit Adv Adv gew|geenfunc|stell|onverv 11 mod _ _
717
- 4 naast naast Prep Prep voor 11 mod _ _
718
- 5 elkaar elkaar Pron Pron rec|neut 4 obj1 _ _
719
- 6 op op Prep Prep voor 11 ld _ _
720
- 7 de de Art Art bep|zijdofmv|neut 8 det _ _
721
- 8 strandstoelen strandstoel N N soort|mv|neut 6 obj1 _ _
722
- 9 kunnen kan V V hulp|inf 2 vc _ _
723
- 10 gaan ga V V hulp|inf 9 vc _ _
724
- 11 liggen lig V V intrans|inf 10 vc _ _
725
- 12 . . Punc Punc punt 11 punct _ _
726
-
727
- 1 Zij zij Pron Pron per|3|evofmv|nom 2 su _ _
728
- 2 zou zal V V hulp|ovt|1of2of3|ev 7 cnj _ _
729
- 3 mams mams N N soort|ev|neut 4 det _ _
730
- 4 rug rug N N soort|ev|neut 5 obj1 _ _
731
- 5 ingewreven wrijf V V trans|verldw|onverv 6 vc _ _
732
- 6 hebben heb V V hulp|inf 2 vc _ _
733
- 7 en en Conj Conj neven 0 ROOT _ _
734
- 8 mam mam V V trans|ovt|1of2of3|ev 7 cnj _ _
735
- 9 de de Art Art bep|zijdofmv|neut 10 det _ _
736
- 10 hare hare Pron Pron bez|3|ev|neut|attr 8 obj1 _ _
737
- 11 . . Punc Punc punt 10 punct _ _
738
-
739
- 1 Of of Conj Conj onder|metfin 0 ROOT _ _
740
- 2 ze ze Pron Pron per|3|evofmv|nom 3 su _ _
741
- 3 had heb V V hulp|ovt|1of2of3|ev 0 ROOT _ _
742
- 4 gewoon gewoon Adj Adj adv|stell|onverv 10 mod _ _
743
- 5 met met Prep Prep voor 10 mod _ _
744
- 6 haar haar Pron Pron bez|3|ev|neut|attr 7 det _ _
745
- 7 vriendinnen vriendin N N soort|mv|neut 5 obj1 _ _
746
- 8 rond rond Adv Adv deelv 10 svp _ _
747
- 9 kunnen kan V V hulp|inf 3 vc _ _
748
- 10 slenteren slenter V V intrans|inf 9 vc _ _
749
- 11 in in Prep Prep voor 10 mod _ _
750
- 12 de de Art Art bep|zijdofmv|neut 13 det _ _
751
- 13 buurt buurt N N soort|ev|neut 11 obj1 _ _
752
- 14 van van Prep Prep voor 13 mod _ _
753
- 15 Trafalgar_Square Trafalgar_Square MWU N_N eigen|ev|neut_eigen|ev|neut 14 obj1 _ _
754
- 16 . . Punc Punc punt 15 punct _ _
755
- """
756
-
757
- if __name__ == '__main__':
758
- demo()
1
+ # Natural Language Toolkit: Dependency Grammars
2
+ #
3
+ # Copyright (C) 2001-2018 NLTK Project
4
+ # Author: Jason Narad <jason.narad@gmail.com>
5
+ # Steven Bird <stevenbird1@gmail.com> (modifications)
6
+ #
7
+ # URL: <http://nltk.org/>
8
+ # For license information, see LICENSE.TXT
9
+ #
10
+
11
+ """
12
+ Tools for reading and writing dependency trees.
13
+ The input is assumed to be in Malt-TAB format
14
+ (http://stp.lingfil.uu.se/~nivre/research/MaltXML.html).
15
+ """
16
+ from __future__ import print_function, unicode_literals
17
+
18
+ from collections import defaultdict
19
+ from itertools import chain
20
+ from pprint import pformat
21
+ import subprocess
22
+ import warnings
23
+
24
+ from six import string_types
25
+
26
+ from nltk.tree import Tree
27
+ from nltk.compat import python_2_unicode_compatible
28
+
29
+
30
+ #################################################################
31
+ # DependencyGraph Class
32
+ #################################################################
33
+
34
+
35
+ @python_2_unicode_compatible
36
+ class DependencyGraph(object):
37
+ """
38
+ A container for the nodes and labelled edges of a dependency structure.
39
+ """
40
+
41
+ def __init__(self, tree_str=None, cell_extractor=None, zero_based=False, cell_separator=None, top_relation_label='ROOT'):
42
+ """Dependency graph.
43
+
44
+ We place a dummy `TOP` node with the index 0, since the root node is
45
+ often assigned 0 as its head. This also means that the indexing of the
46
+ nodes corresponds directly to the Malt-TAB format, which starts at 1.
47
+
48
+ If zero-based is True, then Malt-TAB-like input with node numbers
49
+ starting at 0 and the root node assigned -1 (as produced by, e.g.,
50
+ zpar).
51
+
52
+ :param str cell_separator: the cell separator. If not provided, cells
53
+ are split by whitespace.
54
+
55
+ :param str top_relation_label: the label by which the top relation is
56
+ identified, for examlple, `ROOT`, `null` or `TOP`.
57
+
58
+ """
59
+ self.nodes = defaultdict(lambda: {'address': None,
60
+ 'word': None,
61
+ 'lemma': None,
62
+ 'ctag': None,
63
+ 'tag': None,
64
+ 'feats': None,
65
+ 'head': None,
66
+ 'deps': defaultdict(list),
67
+ 'rel': None,
68
+ })
69
+
70
+ self.nodes[0].update(
71
+ {
72
+ 'ctag': 'TOP',
73
+ 'tag': 'TOP',
74
+ 'address': 0,
75
+ }
76
+ )
77
+
78
+ self.root = None
79
+
80
+ if tree_str:
81
+ self._parse(
82
+ tree_str,
83
+ cell_extractor=cell_extractor,
84
+ zero_based=zero_based,
85
+ cell_separator=cell_separator,
86
+ top_relation_label=top_relation_label,
87
+ )
88
+
89
+ def remove_by_address(self, address):
90
+ """
91
+ Removes the node with the given address. References
92
+ to this node in others will still exist.
93
+ """
94
+ del self.nodes[address]
95
+
96
+ def redirect_arcs(self, originals, redirect):
97
+ """
98
+ Redirects arcs to any of the nodes in the originals list
99
+ to the redirect node address.
100
+ """
101
+ for node in self.nodes.values():
102
+ new_deps = []
103
+ for dep in node['deps']:
104
+ if dep in originals:
105
+ new_deps.append(redirect)
106
+ else:
107
+ new_deps.append(dep)
108
+ node['deps'] = new_deps
109
+
110
+ def add_arc(self, head_address, mod_address):
111
+ """
112
+ Adds an arc from the node specified by head_address to the
113
+ node specified by the mod address.
114
+ """
115
+ relation = self.nodes[mod_address]['rel']
116
+ self.nodes[head_address]['deps'].setdefault(relation, [])
117
+ self.nodes[head_address]['deps'][relation].append(mod_address)
118
+ #self.nodes[head_address]['deps'].append(mod_address)
119
+
120
+
121
+ def connect_graph(self):
122
+ """
123
+ Fully connects all non-root nodes. All nodes are set to be dependents
124
+ of the root node.
125
+ """
126
+ for node1 in self.nodes.values():
127
+ for node2 in self.nodes.values():
128
+ if node1['address'] != node2['address'] and node2['rel'] != 'TOP':
129
+ relation = node2['rel']
130
+ node1['deps'].setdefault(relation, [])
131
+ node1['deps'][relation].append(node2['address'])
132
+ #node1['deps'].append(node2['address'])
133
+
134
+ def get_by_address(self, node_address):
135
+ """Return the node with the given address."""
136
+ return self.nodes[node_address]
137
+
138
+ def contains_address(self, node_address):
139
+ """
140
+ Returns true if the graph contains a node with the given node
141
+ address, false otherwise.
142
+ """
143
+ return node_address in self.nodes
144
+
145
+ def to_dot(self):
146
+ """Return a dot representation suitable for using with Graphviz.
147
+
148
+ >>> dg = DependencyGraph(
149
+ ... 'John N 2\\n'
150
+ ... 'loves V 0\\n'
151
+ ... 'Mary N 2'
152
+ ... )
153
+ >>> print(dg.to_dot())
154
+ digraph G{
155
+ edge [dir=forward]
156
+ node [shape=plaintext]
157
+ <BLANKLINE>
158
+ 0 [label="0 (None)"]
159
+ 0 -> 2 [label="ROOT"]
160
+ 1 [label="1 (John)"]
161
+ 2 [label="2 (loves)"]
162
+ 2 -> 1 [label=""]
163
+ 2 -> 3 [label=""]
164
+ 3 [label="3 (Mary)"]
165
+ }
166
+
167
+ """
168
+ # Start the digraph specification
169
+ s = 'digraph G{\n'
170
+ s += 'edge [dir=forward]\n'
171
+ s += 'node [shape=plaintext]\n'
172
+
173
+ # Draw the remaining nodes
174
+ for node in sorted(self.nodes.values(), key=lambda v: v['address']):
175
+ s += '\n%s [label="%s (%s)"]' % (node['address'], node['address'], node['word'])
176
+ for rel, deps in node['deps'].items():
177
+ for dep in deps:
178
+ if rel is not None:
179
+ s += '\n%s -> %s [label="%s"]' % (node['address'], dep, rel)
180
+ else:
181
+ s += '\n%s -> %s ' % (node['address'], dep)
182
+ s += "\n}"
183
+
184
+ return s
185
+
186
+ def _repr_svg_(self):
187
+ """Show SVG representation of the transducer (IPython magic).
188
+
189
+ >>> dg = DependencyGraph(
190
+ ... 'John N 2\\n'
191
+ ... 'loves V 0\\n'
192
+ ... 'Mary N 2'
193
+ ... )
194
+ >>> dg._repr_svg_().split('\\n')[0]
195
+ '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
196
+
197
+ """
198
+ dot_string = self.to_dot()
199
+
200
+ try:
201
+ process = subprocess.Popen(
202
+ ['dot', '-Tsvg'],
203
+ stdin=subprocess.PIPE,
204
+ stdout=subprocess.PIPE,
205
+ stderr=subprocess.PIPE,
206
+ universal_newlines=True,
207
+ )
208
+ except OSError:
209
+ raise Exception('Cannot find the dot binary from Graphviz package')
210
+ out, err = process.communicate(dot_string)
211
+ if err:
212
+ raise Exception(
213
+ 'Cannot create svg representation by running dot from string: {}'
214
+ ''.format(dot_string))
215
+ return out
216
+
217
+ def __str__(self):
218
+ return pformat(self.nodes)
219
+
220
+ def __repr__(self):
221
+ return "<DependencyGraph with {0} nodes>".format(len(self.nodes))
222
+
223
+ @staticmethod
224
+ def load(filename, zero_based=False, cell_separator=None, top_relation_label='ROOT'):
225
+ """
226
+ :param filename: a name of a file in Malt-TAB format
227
+ :param zero_based: nodes in the input file are numbered starting from 0
228
+ rather than 1 (as produced by, e.g., zpar)
229
+ :param str cell_separator: the cell separator. If not provided, cells
230
+ are split by whitespace.
231
+ :param str top_relation_label: the label by which the top relation is
232
+ identified, for examlple, `ROOT`, `null` or `TOP`.
233
+
234
+ :return: a list of DependencyGraphs
235
+
236
+ """
237
+ with open(filename) as infile:
238
+ return [
239
+ DependencyGraph(
240
+ tree_str,
241
+ zero_based=zero_based,
242
+ cell_separator=cell_separator,
243
+ top_relation_label=top_relation_label,
244
+ )
245
+ for tree_str in infile.read().split('\n\n')
246
+ ]
247
+
248
+ def left_children(self, node_index):
249
+ """
250
+ Returns the number of left children under the node specified
251
+ by the given address.
252
+ """
253
+ children = chain.from_iterable(self.nodes[node_index]['deps'].values())
254
+ index = self.nodes[node_index]['address']
255
+ return sum(1 for c in children if c < index)
256
+
257
+ def right_children(self, node_index):
258
+ """
259
+ Returns the number of right children under the node specified
260
+ by the given address.
261
+ """
262
+ children = chain.from_iterable(self.nodes[node_index]['deps'].values())
263
+ index = self.nodes[node_index]['address']
264
+ return sum(1 for c in children if c > index)
265
+
266
+ def add_node(self, node):
267
+ if not self.contains_address(node['address']):
268
+ self.nodes[node['address']].update(node)
269
+
270
+ def _parse(self, input_, cell_extractor=None, zero_based=False, cell_separator=None, top_relation_label='ROOT'):
271
+ """Parse a sentence.
272
+
273
+ :param extractor: a function that given a tuple of cells returns a
274
+ 7-tuple, where the values are ``word, lemma, ctag, tag, feats, head,
275
+ rel``.
276
+
277
+ :param str cell_separator: the cell separator. If not provided, cells
278
+ are split by whitespace.
279
+
280
+ :param str top_relation_label: the label by which the top relation is
281
+ identified, for examlple, `ROOT`, `null` or `TOP`.
282
+
283
+ """
284
+
285
+ def extract_3_cells(cells, index):
286
+ word, tag, head = cells
287
+ return index, word, word, tag, tag, '', head, ''
288
+
289
+ def extract_4_cells(cells, index):
290
+ word, tag, head, rel = cells
291
+ return index, word, word, tag, tag, '', head, rel
292
+
293
+ def extract_7_cells(cells, index):
294
+ line_index, word, lemma, tag, _, head, rel = cells
295
+ try:
296
+ index = int(line_index)
297
+ except ValueError:
298
+ # index can't be parsed as an integer, use default
299
+ pass
300
+ return index, word, lemma, tag, tag, '', head, rel
301
+
302
+ def extract_10_cells(cells, index):
303
+ line_index, word, lemma, ctag, tag, feats, head, rel, _, _ = cells
304
+ try:
305
+ index = int(line_index)
306
+ except ValueError:
307
+ # index can't be parsed as an integer, use default
308
+ pass
309
+ return index, word, lemma, ctag, tag, feats, head, rel
310
+
311
+ extractors = {
312
+ 3: extract_3_cells,
313
+ 4: extract_4_cells,
314
+ 7: extract_7_cells,
315
+ 10: extract_10_cells,
316
+ }
317
+
318
+ if isinstance(input_, string_types):
319
+ input_ = (line for line in input_.split('\n'))
320
+
321
+ lines = (l.rstrip() for l in input_)
322
+ lines = (l for l in lines if l)
323
+
324
+ cell_number = None
325
+ for index, line in enumerate(lines, start=1):
326
+ cells = line.split(cell_separator)
327
+ if cell_number is None:
328
+ cell_number = len(cells)
329
+ else:
330
+ assert cell_number == len(cells)
331
+
332
+ if cell_extractor is None:
333
+ try:
334
+ cell_extractor = extractors[cell_number]
335
+ except KeyError:
336
+ raise ValueError(
337
+ 'Number of tab-delimited fields ({0}) not supported by '
338
+ 'CoNLL(10) or Malt-Tab(4) format'.format(cell_number)
339
+ )
340
+
341
+ try:
342
+ index, word, lemma, ctag, tag, feats, head, rel = cell_extractor(cells, index)
343
+ except (TypeError, ValueError):
344
+ # cell_extractor doesn't take 2 arguments or doesn't return 8
345
+ # values; assume the cell_extractor is an older external
346
+ # extractor and doesn't accept or return an index.
347
+ word, lemma, ctag, tag, feats, head, rel = cell_extractor(cells)
348
+
349
+ if head == '_':
350
+ continue
351
+
352
+ head = int(head)
353
+ if zero_based:
354
+ head += 1
355
+
356
+ self.nodes[index].update(
357
+ {
358
+ 'address': index,
359
+ 'word': word,
360
+ 'lemma': lemma,
361
+ 'ctag': ctag,
362
+ 'tag': tag,
363
+ 'feats': feats,
364
+ 'head': head,
365
+ 'rel': rel,
366
+ }
367
+ )
368
+
369
+ # Make sure that the fake root node has labeled dependencies.
370
+ if (cell_number == 3) and (head == 0):
371
+ rel = top_relation_label
372
+ self.nodes[head]['deps'][rel].append(index)
373
+
374
+ if self.nodes[0]['deps'][top_relation_label]:
375
+ root_address = self.nodes[0]['deps'][top_relation_label][0]
376
+ self.root = self.nodes[root_address]
377
+ self.top_relation_label = top_relation_label
378
+ else:
379
+ warnings.warn(
380
+ "The graph doesn't contain a node "
381
+ "that depends on the root element."
382
+ )
383
+
384
+ def _word(self, node, filter=True):
385
+ w = node['word']
386
+ if filter:
387
+ if w != ',':
388
+ return w
389
+ return w
390
+
391
+ def _tree(self, i):
392
+ """ Turn dependency graphs into NLTK trees.
393
+
394
+ :param int i: index of a node
395
+ :return: either a word (if the indexed node is a leaf) or a ``Tree``.
396
+ """
397
+ node = self.get_by_address(i)
398
+ word = node['word']
399
+ deps = sorted(chain.from_iterable(node['deps'].values()))
400
+
401
+ if deps:
402
+ return Tree(word, [self._tree(dep) for dep in deps])
403
+ else:
404
+ return word
405
+
406
+ def tree(self):
407
+ """
408
+ Starting with the ``root`` node, build a dependency tree using the NLTK
409
+ ``Tree`` constructor. Dependency labels are omitted.
410
+ """
411
+ node = self.root
412
+
413
+ word = node['word']
414
+ deps = sorted(chain.from_iterable(node['deps'].values()))
415
+ return Tree(word, [self._tree(dep) for dep in deps])
416
+
417
+ def triples(self, node=None):
418
+ """
419
+ Extract dependency triples of the form:
420
+ ((head word, head tag), rel, (dep word, dep tag))
421
+ """
422
+
423
+ if not node:
424
+ node = self.root
425
+
426
+ head = (node['word'], node['ctag'])
427
+ for i in sorted(chain.from_iterable(node['deps'].values())):
428
+ dep = self.get_by_address(i)
429
+ yield (head, dep['rel'], (dep['word'], dep['ctag']))
430
+ for triple in self.triples(node=dep):
431
+ yield triple
432
+
433
+ def _hd(self, i):
434
+ try:
435
+ return self.nodes[i]['head']
436
+ except IndexError:
437
+ return None
438
+
439
+ def _rel(self, i):
440
+ try:
441
+ return self.nodes[i]['rel']
442
+ except IndexError:
443
+ return None
444
+
445
+ # what's the return type? Boolean or list?
446
+ def contains_cycle(self):
447
+ """Check whether there are cycles.
448
+
449
+ >>> dg = DependencyGraph(treebank_data)
450
+ >>> dg.contains_cycle()
451
+ False
452
+
453
+ >>> cyclic_dg = DependencyGraph()
454
+ >>> top = {'word': None, 'deps': [1], 'rel': 'TOP', 'address': 0}
455
+ >>> child1 = {'word': None, 'deps': [2], 'rel': 'NTOP', 'address': 1}
456
+ >>> child2 = {'word': None, 'deps': [4], 'rel': 'NTOP', 'address': 2}
457
+ >>> child3 = {'word': None, 'deps': [1], 'rel': 'NTOP', 'address': 3}
458
+ >>> child4 = {'word': None, 'deps': [3], 'rel': 'NTOP', 'address': 4}
459
+ >>> cyclic_dg.nodes = {
460
+ ... 0: top,
461
+ ... 1: child1,
462
+ ... 2: child2,
463
+ ... 3: child3,
464
+ ... 4: child4,
465
+ ... }
466
+ >>> cyclic_dg.root = top
467
+
468
+ >>> cyclic_dg.contains_cycle()
469
+ [3, 1, 2, 4]
470
+
471
+ """
472
+ distances = {}
473
+
474
+ for node in self.nodes.values():
475
+ for dep in node['deps']:
476
+ key = tuple([node['address'], dep])
477
+ distances[key] = 1
478
+
479
+ for _ in self.nodes:
480
+ new_entries = {}
481
+
482
+ for pair1 in distances:
483
+ for pair2 in distances:
484
+ if pair1[1] == pair2[0]:
485
+ key = tuple([pair1[0], pair2[1]])
486
+ new_entries[key] = distances[pair1] + distances[pair2]
487
+
488
+ for pair in new_entries:
489
+ distances[pair] = new_entries[pair]
490
+ if pair[0] == pair[1]:
491
+ path = self.get_cycle_path(self.get_by_address(pair[0]), pair[0])
492
+ return path
493
+
494
+ return False # return []?
495
+
496
+ def get_cycle_path(self, curr_node, goal_node_index):
497
+ for dep in curr_node['deps']:
498
+ if dep == goal_node_index:
499
+ return [curr_node['address']]
500
+ for dep in curr_node['deps']:
501
+ path = self.get_cycle_path(self.get_by_address(dep), goal_node_index)
502
+ if len(path) > 0:
503
+ path.insert(0, curr_node['address'])
504
+ return path
505
+ return []
506
+
507
+ def to_conll(self, style):
508
+ """
509
+ The dependency graph in CoNLL format.
510
+
511
+ :param style: the style to use for the format (3, 4, 10 columns)
512
+ :type style: int
513
+ :rtype: str
514
+ """
515
+
516
+ if style == 3:
517
+ template = '{word}\t{tag}\t{head}\n'
518
+ elif style == 4:
519
+ template = '{word}\t{tag}\t{head}\t{rel}\n'
520
+ elif style == 10:
521
+ template = '{i}\t{word}\t{lemma}\t{ctag}\t{tag}\t{feats}\t{head}\t{rel}\t_\t_\n'
522
+ else:
523
+ raise ValueError(
524
+ 'Number of tab-delimited fields ({0}) not supported by '
525
+ 'CoNLL(10) or Malt-Tab(4) format'.format(style)
526
+ )
527
+
528
+ return ''.join(template.format(i=i, **node) for i, node in sorted(self.nodes.items()) if node['tag'] != 'TOP')
529
+
530
+ def nx_graph(self):
531
+ """Convert the data in a ``nodelist`` into a networkx labeled directed graph."""
532
+ import networkx
533
+
534
+ nx_nodelist = list(range(1, len(self.nodes)))
535
+ nx_edgelist = [
536
+ (n, self._hd(n), self._rel(n))
537
+ for n in nx_nodelist if self._hd(n)
538
+ ]
539
+ self.nx_labels = {}
540
+ for n in nx_nodelist:
541
+ self.nx_labels[n] = self.nodes[n]['word']
542
+
543
+ g = networkx.MultiDiGraph()
544
+ g.add_nodes_from(nx_nodelist)
545
+ g.add_edges_from(nx_edgelist)
546
+
547
+ return g
548
+
549
+
550
+ class DependencyGraphError(Exception):
551
+ """Dependency graph exception."""
552
+
553
+
554
+ def demo():
555
+ malt_demo()
556
+ conll_demo()
557
+ conll_file_demo()
558
+ cycle_finding_demo()
559
+
560
+
561
+ def malt_demo(nx=False):
562
+ """
563
+ A demonstration of the result of reading a dependency
564
+ version of the first sentence of the Penn Treebank.
565
+ """
566
+ dg = DependencyGraph("""Pierre NNP 2 NMOD
567
+ Vinken NNP 8 SUB
568
+ , , 2 P
569
+ 61 CD 5 NMOD
570
+ years NNS 6 AMOD
571
+ old JJ 2 NMOD
572
+ , , 2 P
573
+ will MD 0 ROOT
574
+ join VB 8 VC
575
+ the DT 11 NMOD
576
+ board NN 9 OBJ
577
+ as IN 9 VMOD
578
+ a DT 15 NMOD
579
+ nonexecutive JJ 15 NMOD
580
+ director NN 12 PMOD
581
+ Nov. NNP 9 VMOD
582
+ 29 CD 16 NMOD
583
+ . . 9 VMOD
584
+ """)
585
+ tree = dg.tree()
586
+ tree.pprint()
587
+ if nx:
588
+ # currently doesn't work
589
+ import networkx
590
+ from matplotlib import pylab
591
+
592
+ g = dg.nx_graph()
593
+ g.info()
594
+ pos = networkx.spring_layout(g, dim=1)
595
+ networkx.draw_networkx_nodes(g, pos, node_size=50)
596
+ # networkx.draw_networkx_edges(g, pos, edge_color='k', width=8)
597
+ networkx.draw_networkx_labels(g, pos, dg.nx_labels)
598
+ pylab.xticks([])
599
+ pylab.yticks([])
600
+ pylab.savefig('tree.png')
601
+ pylab.show()
602
+
603
+
604
+ def conll_demo():
605
+ """
606
+ A demonstration of how to read a string representation of
607
+ a CoNLL format dependency tree.
608
+ """
609
+ dg = DependencyGraph(conll_data1)
610
+ tree = dg.tree()
611
+ tree.pprint()
612
+ print(dg)
613
+ print(dg.to_conll(4))
614
+
615
+
616
+ def conll_file_demo():
617
+ print('Mass conll_read demo...')
618
+ graphs = [DependencyGraph(entry)
619
+ for entry in conll_data2.split('\n\n') if entry]
620
+ for graph in graphs:
621
+ tree = graph.tree()
622
+ print('\n')
623
+ tree.pprint()
624
+
625
+
626
+ def cycle_finding_demo():
627
+ dg = DependencyGraph(treebank_data)
628
+ print(dg.contains_cycle())
629
+ cyclic_dg = DependencyGraph()
630
+ cyclic_dg.add_node({'word': None, 'deps': [1], 'rel': 'TOP', 'address': 0})
631
+ cyclic_dg.add_node({'word': None, 'deps': [2], 'rel': 'NTOP', 'address': 1})
632
+ cyclic_dg.add_node({'word': None, 'deps': [4], 'rel': 'NTOP', 'address': 2})
633
+ cyclic_dg.add_node({'word': None, 'deps': [1], 'rel': 'NTOP', 'address': 3})
634
+ cyclic_dg.add_node({'word': None, 'deps': [3], 'rel': 'NTOP', 'address': 4})
635
+ print(cyclic_dg.contains_cycle())
636
+
637
+ treebank_data = """Pierre NNP 2 NMOD
638
+ Vinken NNP 8 SUB
639
+ , , 2 P
640
+ 61 CD 5 NMOD
641
+ years NNS 6 AMOD
642
+ old JJ 2 NMOD
643
+ , , 2 P
644
+ will MD 0 ROOT
645
+ join VB 8 VC
646
+ the DT 11 NMOD
647
+ board NN 9 OBJ
648
+ as IN 9 VMOD
649
+ a DT 15 NMOD
650
+ nonexecutive JJ 15 NMOD
651
+ director NN 12 PMOD
652
+ Nov. NNP 9 VMOD
653
+ 29 CD 16 NMOD
654
+ . . 9 VMOD
655
+ """
656
+
657
+ conll_data1 = """
658
+ 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
659
+ 2 had heb V V trans|ovt|1of2of3|ev 0 ROOT _ _
660
+ 3 met met Prep Prep voor 8 mod _ _
661
+ 4 haar haar Pron Pron bez|3|ev|neut|attr 5 det _ _
662
+ 5 moeder moeder N N soort|ev|neut 3 obj1 _ _
663
+ 6 kunnen kan V V hulp|ott|1of2of3|mv 2 vc _ _
664
+ 7 gaan ga V V hulp|inf 6 vc _ _
665
+ 8 winkelen winkel V V intrans|inf 11 cnj _ _
666
+ 9 , , Punc Punc komma 8 punct _ _
667
+ 10 zwemmen zwem V V intrans|inf 11 cnj _ _
668
+ 11 of of Conj Conj neven 7 vc _ _
669
+ 12 terrassen terras N N soort|mv|neut 11 cnj _ _
670
+ 13 . . Punc Punc punt 12 punct _ _
671
+ """
672
+
673
+ conll_data2 = """1 Cathy Cathy N N eigen|ev|neut 2 su _ _
674
+ 2 zag zie V V trans|ovt|1of2of3|ev 0 ROOT _ _
675
+ 3 hen hen Pron Pron per|3|mv|datofacc 2 obj1 _ _
676
+ 4 wild wild Adj Adj attr|stell|onverv 5 mod _ _
677
+ 5 zwaaien zwaai N N soort|mv|neut 2 vc _ _
678
+ 6 . . Punc Punc punt 5 punct _ _
679
+
680
+ 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
681
+ 2 had heb V V trans|ovt|1of2of3|ev 0 ROOT _ _
682
+ 3 met met Prep Prep voor 8 mod _ _
683
+ 4 haar haar Pron Pron bez|3|ev|neut|attr 5 det _ _
684
+ 5 moeder moeder N N soort|ev|neut 3 obj1 _ _
685
+ 6 kunnen kan V V hulp|ott|1of2of3|mv 2 vc _ _
686
+ 7 gaan ga V V hulp|inf 6 vc _ _
687
+ 8 winkelen winkel V V intrans|inf 11 cnj _ _
688
+ 9 , , Punc Punc komma 8 punct _ _
689
+ 10 zwemmen zwem V V intrans|inf 11 cnj _ _
690
+ 11 of of Conj Conj neven 7 vc _ _
691
+ 12 terrassen terras N N soort|mv|neut 11 cnj _ _
692
+ 13 . . Punc Punc punt 12 punct _ _
693
+
694
+ 1 Dat dat Pron Pron aanw|neut|attr 2 det _ _
695
+ 2 werkwoord werkwoord N N soort|ev|neut 6 obj1 _ _
696
+ 3 had heb V V hulp|ovt|1of2of3|ev 0 ROOT _ _
697
+ 4 ze ze Pron Pron per|3|evofmv|nom 6 su _ _
698
+ 5 zelf zelf Pron Pron aanw|neut|attr|wzelf 3 predm _ _
699
+ 6 uitgevonden vind V V trans|verldw|onverv 3 vc _ _
700
+ 7 . . Punc Punc punt 6 punct _ _
701
+
702
+ 1 Het het Pron Pron onbep|neut|zelfst 2 su _ _
703
+ 2 hoorde hoor V V trans|ovt|1of2of3|ev 0 ROOT _ _
704
+ 3 bij bij Prep Prep voor 2 ld _ _
705
+ 4 de de Art Art bep|zijdofmv|neut 6 det _ _
706
+ 5 warme warm Adj Adj attr|stell|vervneut 6 mod _ _
707
+ 6 zomerdag zomerdag N N soort|ev|neut 3 obj1 _ _
708
+ 7 die die Pron Pron betr|neut|zelfst 6 mod _ _
709
+ 8 ze ze Pron Pron per|3|evofmv|nom 12 su _ _
710
+ 9 ginds ginds Adv Adv gew|aanw 12 mod _ _
711
+ 10 achter achter Adv Adv gew|geenfunc|stell|onverv 12 svp _ _
712
+ 11 had heb V V hulp|ovt|1of2of3|ev 7 body _ _
713
+ 12 gelaten laat V V trans|verldw|onverv 11 vc _ _
714
+ 13 . . Punc Punc punt 12 punct _ _
715
+
716
+ 1 Ze ze Pron Pron per|3|evofmv|nom 2 su _ _
717
+ 2 hadden heb V V trans|ovt|1of2of3|mv 0 ROOT _ _
718
+ 3 languit languit Adv Adv gew|geenfunc|stell|onverv 11 mod _ _
719
+ 4 naast naast Prep Prep voor 11 mod _ _
720
+ 5 elkaar elkaar Pron Pron rec|neut 4 obj1 _ _
721
+ 6 op op Prep Prep voor 11 ld _ _
722
+ 7 de de Art Art bep|zijdofmv|neut 8 det _ _
723
+ 8 strandstoelen strandstoel N N soort|mv|neut 6 obj1 _ _
724
+ 9 kunnen kan V V hulp|inf 2 vc _ _
725
+ 10 gaan ga V V hulp|inf 9 vc _ _
726
+ 11 liggen lig V V intrans|inf 10 vc _ _
727
+ 12 . . Punc Punc punt 11 punct _ _
728
+
729
+ 1 Zij zij Pron Pron per|3|evofmv|nom 2 su _ _
730
+ 2 zou zal V V hulp|ovt|1of2of3|ev 7 cnj _ _
731
+ 3 mams mams N N soort|ev|neut 4 det _ _
732
+ 4 rug rug N N soort|ev|neut 5 obj1 _ _
733
+ 5 ingewreven wrijf V V trans|verldw|onverv 6 vc _ _
734
+ 6 hebben heb V V hulp|inf 2 vc _ _
735
+ 7 en en Conj Conj neven 0 ROOT _ _
736
+ 8 mam mam V V trans|ovt|1of2of3|ev 7 cnj _ _
737
+ 9 de de Art Art bep|zijdofmv|neut 10 det _ _
738
+ 10 hare hare Pron Pron bez|3|ev|neut|attr 8 obj1 _ _
739
+ 11 . . Punc Punc punt 10 punct _ _
740
+
741
+ 1 Of of Conj Conj onder|metfin 0 ROOT _ _
742
+ 2 ze ze Pron Pron per|3|evofmv|nom 3 su _ _
743
+ 3 had heb V V hulp|ovt|1of2of3|ev 0 ROOT _ _
744
+ 4 gewoon gewoon Adj Adj adv|stell|onverv 10 mod _ _
745
+ 5 met met Prep Prep voor 10 mod _ _
746
+ 6 haar haar Pron Pron bez|3|ev|neut|attr 7 det _ _
747
+ 7 vriendinnen vriendin N N soort|mv|neut 5 obj1 _ _
748
+ 8 rond rond Adv Adv deelv 10 svp _ _
749
+ 9 kunnen kan V V hulp|inf 3 vc _ _
750
+ 10 slenteren slenter V V intrans|inf 9 vc _ _
751
+ 11 in in Prep Prep voor 10 mod _ _
752
+ 12 de de Art Art bep|zijdofmv|neut 13 det _ _
753
+ 13 buurt buurt N N soort|ev|neut 11 obj1 _ _
754
+ 14 van van Prep Prep voor 13 mod _ _
755
+ 15 Trafalgar_Square Trafalgar_Square MWU N_N eigen|ev|neut_eigen|ev|neut 14 obj1 _ _
756
+ 16 . . Punc Punc punt 15 punct _ _
757
+ """
758
+
759
+ if __name__ == '__main__':
760
+ demo()