{"id":153,"date":"2019-10-31T18:42:07","date_gmt":"2019-10-31T18:42:07","guid":{"rendered":"https:\/\/leme.utoronto.ca\/?page_id=153"},"modified":"2019-10-31T18:49:37","modified_gmt":"2019-10-31T18:49:37","slug":"lemmatizer","status":"publish","type":"page","link":"https:\/\/leme.utoronto.ca\/?page_id=153","title":{"rendered":"Lemmatizer"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Since September 2018, I\nhave been developing software to lemmatize historical lexicons. I was given two\nprojects when developing software for lemmatization: the first creates a\ndatabase that allows bibliographic information from early modern lexicons to be\nextracted easily; and the second develops software that would automatically\nlemmatize lexicons based on the modern-day spelling of words from the Oxford\nEnglish Dictionary. The software for lemmatization used bibliographic information\nextracted from my database. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I have developed programs\nin Python to automatically find the difference between OED and historical\nlexicons, which would enable lexicons to be lemmatized semi-automatically. OED\nis a useful resource since it contains extensive information on modern English\nheadwords, such as their part of speech and date on their first and last\noccurrence. OED has given LEME an Excel file of data, which I used to build a &nbsp;relational database to more easily access the\ndata. A relational database organizes data into one or more tables of columns\nand rows, with a unique key identifying each row.<a href=\"#_ftn1\">[1]<\/a> I inserted all the OED\nword-entries into the database by using their unique URL as their ID. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For my first project, I\ncreated a database for historical lexicons that allows information to be\nextracted based on the date of the lexicon. We wanted to find word-entries that\nare in the historical dictionaries but not in the OED, as well as word-entries\nthat antedate or postdate the OED citations. OED cites the first and last\noccurrence of a headword, but historical dictionaries also provide their own\ndate of publication. By comparing these dates, we can determine whether a\nhistorical lexicon antedates or postdates headwords cited by the OED. The date\nof the first and last occurrence of a word in the OED can be simply extracted\nby a SQL command. To accomplish this, I extracted lexemes from word-entries in\nXML files of historical dictionaries. A unique LEME ID is also needed to create\nthe tables. At first, I tried to use Python XML parsing tools to extract the\ninformation. However, I found that not all files were well formatted so I\nneeded to validate and modify them before extracting word-entries. I had to\nwrite programs that automatically corrected invalid XML elements. Then, I\ndecided to consider the original XML files as regular TXT files, which means\nthat I did not use built-in XML functions in Python; I wrote my own functions\nto delete XML tags so that only word-entries and their part of speech remained in\nthe TXT files. As a result, I could easily add word-entries with parts of\nspeech to the database I built, and I used SQL queries to extract the\ninformation we needed. Once we added word-entries into the database, we could\ngather information through one simple command. For example, if we want to find\nword-entries that antedate the OED, we could use a simple SQL command such as <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SELECT\nleme.wordentry, leme.pos FROM leme inner join oed on\noed.headword=leme.wordentry and oed.pos=leme.pos where leme.date &lt; oed,first_date.\n<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Given a historical\ndictionary file, the program could add word-entries into the database and\ngenerate report files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Furthermore, individual\nreport files for historical dictionaries are insufficient for forming any\nconclusions, but graphs may be helpful for comparing several lexicons across\ndifferent periods of time. The database allows us to discover the number of\nantedatings, postdatings, and LEME lexemes not in the OED during a specific\nperiod. For example, we could generate graphs of LEME lexemes not in the OED\n(Figure 1).<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"671\" height=\"503\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig1.png\" alt=\"\" class=\"wp-image-163\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig1.png 671w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig1-300x225.png 300w\" sizes=\"auto, (max-width: 671px) 100vw, 671px\" \/><figcaption> Figure 1: sample graph generated by program. <\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">I\nalso created a user interface (UI) for this program (Figure 2). The program has\ntwo features: one, creating tables for each dictionary; and two, creating\ngraphs. To create tables for each dictionary, we give the program the full path\nof the dictionary file and its LEME id, and then click \u201cCreate.\u201d Now, the\nprogram can automatically parse the file, add new word-entries into the\ndatabase, and generate report files into the same directory as the input. Once\nthe program finishes creating tables for dictionary files, a message would\ninform the user whether the process has successfully finished. Clicking \u201cPlot\u201d\nautomatically plots the graph. When given the desired output path, graphs would\nbe created in that directory. (Figure 3)<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"759\" height=\"528\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig2.png\" alt=\"\" class=\"wp-image-164\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig2.png 759w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig2-300x209.png 300w\" sizes=\"auto, (max-width: 759px) 100vw, 759px\" \/><figcaption> Figure 2: UI <\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"927\" height=\"669\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig3.png\" alt=\"\" class=\"wp-image-165\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig3.png 927w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig3-300x217.png 300w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig3-768x554.png 768w\" sizes=\"auto, (max-width: 927px) 100vw, 927px\" \/><figcaption> Figure 3: Graphs generated by the program. <\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The\nsecond project is a Natural Language Processing project on automatically\nlemmatizing lexicons based on the OED. I started with studying Python NLP tools\nand papers on string matching. I benefited from <em>Natural Language Processing for Historical Texts<\/em>, edited by Graeme\nHirst. The book emphasizes that the spelling of words varies frequently,\ndepending on the grammar and historical period in which the word occurs. To\naddress the variance of spelling, word-entries need to be normalized by\nstandardizing grammar and spelling. In Python, there is a toolkit called NLTK,\nwhich provides text processing libraries for tokenization, stemming, tagging,\nparsing and so on.<a href=\"#_ftn2\">[2]<\/a>\nGiven a sentence, NLTK could automatically recognize the root word (Figure 4)\nor add part of speech tags (Figure 5). <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"877\" height=\"642\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig4.png\" alt=\"\" class=\"wp-image-166\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig4.png 877w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig4-300x220.png 300w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig4-768x562.png 768w\" sizes=\"auto, (max-width: 877px) 100vw, 877px\" \/><figcaption> Figure 4: NLTK lemmatize <\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"877\" height=\"642\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig5.png\" alt=\"\" class=\"wp-image-167\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig5.png 877w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig5-300x220.png 300w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig5-768x562.png 768w\" sizes=\"auto, (max-width: 877px) 100vw, 877px\" \/><figcaption> Figure 5: NLTK PoS tag <\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">However, historical\nspelling is not the same as modern spelling, as there are some rules and\nvariations. Referring to an OED blog post on early modern English pronunciation\nand spelling, I used regular expressions to implement its rules so that\nhistorical spelling could be recognized and modified.<a href=\"#_ftn3\">[3]<\/a> As a result, the program\ncan recognize some simple historical variations. For example, \u2018abiect\u2019 is\nrecognized as \u2018abject\u2019, and \u2018aboue\u2019 is recognized as \u2018above\u2019 (Figure 6).\nHowever, there are more variations than simple rules. Consequently, I tried to\nfind the most similar word in the dictionary by edit distance and longest\ncommon subsequence. Edit distance is way to quantify how dissimilar two strings\nare.<a href=\"#_ftn4\">[4]<\/a> It measures the minimum\nnumber of operations (including insertions, deletions, and substitutions)\nrequired to change one word to another. Instead of regular edit distance, I\nused Damerau-Levenshtein distance, which includes the transposition of two\nadjacent characters as an operation. Damerau-Levenshtein distance allows us to\naccommodate the shifting of historical spellings into modern spellings of\nwords. For example, the program registers that \u2018abel\u2019 could be a historical\nspelling for \u2018able\u2019. Longest common subsequence helps by checking the order of\nthe characters in the original strings. If I find more than one similar word in\nthe dictionary, I will list all of them. For example, although \u2018heereafter\u2019 is\nnot in the OED, the program can find \u2018thereafter, whereafter, hereafter\u2019 as similar\nwords.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"716\" height=\"488\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig6.png\" alt=\"\" class=\"wp-image-168\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig6.png 716w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig6-300x204.png 300w\" sizes=\"auto, (max-width: 716px) 100vw, 716px\" \/><figcaption> Figure 6: Applying spelling rule <\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">I then created a UI to\nrun this program. It could lemmatize a single word or a dictionary file (Figure\n7).<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"716\" height=\"488\" src=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig7.png\" alt=\"\" class=\"wp-image-169\" srcset=\"https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig7.png 716w, https:\/\/leme.utoronto.ca\/wp-content\/uploads\/2019\/10\/fig7-300x204.png 300w\" sizes=\"auto, (max-width: 716px) 100vw, 716px\" \/><figcaption> Figure 7: Lemmatizer UI <\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">However, this program runs slow for large files since it\nguesses the words by edit distance and compares the results with 97,800 OED\nword-entries. I came up with a way to improve the speed by running the program\nin multi-thread. In multi-thread, I can lemmatize several words at the same\ntime, which drastically reduces the time it takes for the program to run. Since\nlemmatizing a single word takes around three &nbsp;minutes, without multi-thread, lemmatizing twenty\nword-entries would take around one hour. With multi-thread, we could lemmatize five\nword-entries simultaneously, and the entire process would take around twelve\nminutes. We could also run the program on a more powerful computer or a virtual\nmachine to improve the efficiency. <br><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"#_ftnref1\">[1]<\/a>\n\u201cRelational database,\u201d Wikipedia, accessed June 6, 2019, https:\/\/en.wikipedia.org\/wiki\/Relational_database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"#_ftnref2\">[2]<\/a>\nSteven Bird, Edward Loper and Ewan Klein, <em>Natural Language Processing\nwith Python<\/em> (O\u2019Reilly Media Inc., 2009). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"#_ftnref3\">[3]<\/a> \u201cEarly\nModern English Pronunciation and Spelling,\u201d OED, accessed June 6, 2019, https:\/\/public.oed.com\/blog\/early-modern-english-pronunciation-and-spelling\/<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"#_ftnref4\">[4]<\/a>\n\u201cEdit Distance,\u201d Wikipedia, accessed June 6, 2019, https:\/\/en.wikipedia.org\/wiki\/Edit_distance.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Since September 2018, I have been developing software to lemmatize historical lexicons. I was given two projects when developing software for lemmatization: the first creates a database that allows bibliographic information from early modern lexicons to be extracted easily; and the second develops software that would automatically lemmatize lexicons based on the modern-day spelling of [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","footnotes":""},"class_list":["post-153","page","type-page","status-publish","entry","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=\/wp\/v2\/pages\/153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=153"}],"version-history":[{"count":6,"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=\/wp\/v2\/pages\/153\/revisions"}],"predecessor-version":[{"id":175,"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=\/wp\/v2\/pages\/153\/revisions\/175"}],"wp:attachment":[{"href":"https:\/\/leme.utoronto.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}