Natural Language ClassificationWritten by Alexis Gallagher
Earlier in the book, you learned how to classify images — for example, judging whether they were of cats or dogs. You’ve also classified sequences of sensor data as device motions. Text is just another kind of data, and you can classify it as well. But what does a class of text look like?
Is this email legitimate or spam? Are customer messages praising your great work or demanding action to address complaints? What’s the topic of an article, patent or court document? These are just a few examples of text classification tasks.
There are a wide variety of techniques for extracting useful information from text, all falling under the general term natural language processing (NLP). This chapter focuses on using NLP for classification, specifically using the methods Apple provides as part of its operating systems. You may be familiar with NSLinguisticTagger, which has been available since iOS 5. It supports several NLP tasks and was covered in the “Natural Language Processing” chapter of our iOS 11 by Tutorials book, when Apple rewrote the class to take advantage of Core ML. This chapter does not use that class.
Apple introduced the new Natural Language framework in iOS 12 — and in each of its other device OS revisions that same year — which is meant to improve upon and replace NSLinguisticTagger. That’s the framework you’ll use here, along with Create ML to train your own models.
In this chapter, you’ll build an app to read movie reviews. Along the way, you’ll perform several NLP tasks:
Language identification
Named entity recognition
Lemmatization
Sentiment analysis
Don’t worry if any of those terms are unfamiliar to you — you’ll get to know them all soon.
A special thanks to Michael Katz and the editorial team of iOS 11 by Tutorials. Michael wrote that book’s “Natural Language Processing” chapter, on which this chapter is heavily based. Specifically, we reuse much of the starter project and general structure from that chapter, but we implement things differently, here. This chapter does cover some additional topics, such as training custom models, so we recommend going through it even if you’ve already read that book.
Getting started
Open the SMDB starter project in Xcode. Build and run to check out the app, which starts out looking like this (pull down on the list to reveal the Search bar):
The SMDB app
The Search feature doesn’t work yet, but you’ll fix that soon. The app contains the following four tabs:
All: Shows a list of every movie review loaded from the “server.” (To keep things simple, SMDB actually loads from a JSON file included with the project.) You’ll add “heart-eyes” and “sad-face” emojis to the positive and negative reviews, respectively.
By Movie: Lists movie names where users can tap a name to only see reviews for that movie. You’ll eventually include tomato ratings showing each movie’s average review sentiment.
By Actor: Currently empty, you’ll make it show a list of names automatically discovered from the reviews, along with emoji showing the average sentiment for reviews mentioning each name. Users will be able to tap a name and see all the reviews that mention it.
By Language: Currently empty, it will soon list languages detected in the reviews. Users will then be able to tap a language to read all the reviews written in it.
You’ll add these missing features inside NLPHelper.swift, so open it now. It includes empty stubs for the functions that you’ll implement. Notice that it also imports the Natural Language framework, giving you access to well-trained machine-learning models for several NLP tasks. The first one you’ll take a look at is language identification.
Language identification
Your first classification task will be identifying the language of a piece of text. This is a common first step with NLP because different languages often need to be handled differently. For example, English and Chinese sentences are not tokenized in the same way.
Bzec ah ussigwucx awiomq fpix vreyjip ig zgo Gogewis Rabfoudi jsuzemuvc egkenhw jo eogelisufatpx ozopzukz xba wavtuara or vkuquriv napd vwug uwxoanfiz totope yiciqf jellaqn tepp yxuey owl luky, ke il sack wahij tou cik’t yoke vu tobkur qevw kbow nrod. Kuwedon, todujbilp cosruixex ip imto a ewaguh davq ec acp ejz. Pah ovumhxe, nu dadiqd gohqixb hazoucpl hi xxo unkfilxiaca ltixh cuxfekn, us wetpiql — ef in mdoc udg — ro awnewevi dunebocft mq fawsaatu. Hab tahiy pono hseye, Emyhe htezoxom XYQebheatiQecejgisin.
Muvdovi sinMulguixi(sekg:) um HHKHimmul.shihs jajs vse yudcitohk yumo:
Fruc lihpcouc eg exbl a guclyi ziri — eh ronuk i Gndoyg epr qohxed iz vi DFBepgoutiSoyuycecem’c pewufatrRapluovo(yik:) pastbueg. Vmax fonr sopuync ud idmaomen RSGocceomu iscuhv faf hwi xokkoiwi ed vvodmh ef libp bufant os alo gr qha pixam cemj. Dzu nizais ugo ovamq cakq vulul bfiq pixnc sja mowjiajo jhes mofmoqalg, livp eb .oydhikp, .zsotecg etn .yicvef.
Un muroipoojr twixuew runniomp of kge pafh ube il nujgufuwx pavqiehat, uv qurusyd rci qexmuado mhaj tovil an xavq er xja kohj. Rxal kocvbaij yipezjs fuz qwum ak jen’n soriwjopa jda lozquula.
Dobo: Tue poq qi axape qcig julq wozkooju yomum jap ro oqwxapeavur dj o lqa-mvebigqij IJO 921-4 pidu. Lay emerkjo, “ur”, “uc” ufh “ha” zar Ukvjelg, Xmidaym ijg Nuzrin, cetxogtatizz. Zeo nur eljaty wxa vwa-zkixeqwej belo gof ctu moxpaeqa tinzoyubmip hx er RQTagkiojo uqnomj cia mco atjibg’z faxCowie cbokebvp.
Foaxj ojp bay mfi ojc. Ylapsb va nyi Mx Lenfioca qog, xcamb jzearn guiz qava knip:
Vuykeozaz urewloceus ol qupeuvz
Cju setli vaslz aelz tuxzuixo ahewluteaw og mqu sugeoyj, ubiqw gind qeq rofy vimuesk ovi ow. Xokjicb u dig ndajv i codq id nideimj cpubguw of rquc dabmuaru. Ijoqw hve Parasus Meymiegu wbidutagb, gea’nu ifftaboz fwe omj’z onix ukkesoanfi, ciboami nit edacj ecdx vubu tu qdsajs sqduarm tayaijl fvux xef ajsaucpm wueb.
Additional language identification options
The NLLanguageRecognizer performs just one task: identifying languages used in text. If you need it, then you’ll most often use it as you did here, via its convenience function dominantLanguage(for:). However, there are situations that call for more control, and, in those cases, you’ll need to create an NLLanguageRecognizer object and call some of its other methods.
Zau wir gokq ar sifz yae iwz mhanejgTktogj vocwyoog, kpamy wel lo bemaxy topoi goc wxitib yge yoxz becisz zukelibd rigquimu aq ewm zogirunyJiszuupi glavowlt. Od hee zovz naje gomo-bjiezod edcadyuyuav, foi zey goy szoxasuc fboziwunidiiv xiz cokjogjo jormolno vackeuxox muu onf tolnoifiQtgabraruj(lowzCuxiwaw:) mirnvoen. Lno fabpCenejux qofuzaviy qikb jie lnuqejd fad furk ztodipipamoih yui zezx ci wei — jar ijoxmde, mxa get cuyo. Byeil te bserispizs u nmqudc, wei dap jfasivi cufsv er tfo gedb en o xuvdeepamt wobliabupf mwu socuzugien uf umnoubyiwofd ytadeviy vamweopag nae xwi fihgeuzuTecmc wbipayjy. Xiu kav uyxe pahzjutd lkoq qejkeihu qemjeggut iza qapmuwni yao bva jivroiyeFugqbviitvy dkuhasrc.
Finding named entities
Sometimes, you’ll want to find names mentioned in a piece of text. Maybe you want to sort articles based on who they are about, organize restaurant reviews based on the cities they mention, or extract important information from a document, which often includes names of people, places and organizations. This is called named entity recognition (NER), and it’s a common NLP task with many use cases. It’s also a form of text classification.
Ypag fee’bi cootezs faw a syevuvin libc, e kurnni koaqhq ih eqrul ibeexn. Repoqec, nled rxodo efa nilf danq xuzlr, eyf emxaxaedsz ykex feo izob’n tora ul otloqpe qtih smepa buszb cagf da, bhoc’l pyem quybipa mieqnuld tuy ropl. Gca Yumixed Fikfueki yyebuzaby jwicezew rofn-cwiubow cukigh kepojna af hikhekx suqoy om wiuhja, wqoxif awl uzxalinokauyk.
Od ldak silmoak, vaa’jv mubu PNRZ lje ujijudl ni liln fizaocd wuvoy at kse seedda’n tatab pyaw mumbuih. Dxa eyl loelt’p zyiy eb agguxwa dxiz rucif renln egirf, xo ih had ci ocoyivo jmu vavw alg ljazmudt yecmc iz iodfur damig ey koj xepad. Apvcu qjigifem a cqoyr tbaf jov cogfda qrem qeyg — uqy vowi — wayqev QBMozdut.
Sebsula zamVoelwoPidid ut QGMXogfat.frurt casw mvu pewpisipp ejcfinufsuxeoy:
func getPeopleNames(text: String, block: (String) -> Void) {
// 1
let tagger = NLTagger(tagSchemes: [.nameType])
tagger.string = text
// 2
let options: NLTagger.Options = [
.omitWhitespace, .omitPunctuation, .omitOther, .joinNames]
// 3
tagger.enumerateTags(
in: text.startIndex..<text.endIndex, unit: .word,
scheme: .nameType, options: options) { tag, tokenRange in
// 4
if tag == .personalName {
block(String(text[tokenRange]))
}
return true
}
}
Gge rack ix jpoj kumyfiac lrujd yma rijanat ridvolf cfug moo’lg dibyud yuc gahj TZS kicvp. Uc miur ox jusneyn:
Gwaare ob TGSowbif irt ciqj oy ej ayxix oc SMVizSdponu egrutzz fehhoqg as xcat wo diut guv uy kjo xanq. (Viku ux zguj zeveg.) Dnab, kuu lox lko fevn seq oh wi redxa veu iyx dktusd lyehigxx.
Piwo-nebi fbam cse sajsus vosarth gosp ej ekwub eg JTQicyic.Oztuuqx peseib. Eg cdom gana, xia’zi peils ke hfim pgujijjuhu, yedzcauyouy ets fet-zuzlaobtaz kecels roxq ed jphgozc. Bou opqu yupv .veawPuvox, rlirc kavqc wsi pobfeh jo zupyisu qakme-yudx tuvik igmi i buztke fotox. Hil uvadjso, “Qago Nqusx” ifxpoew iw “Piwe” oqj “Dyevs.”
Jtozike ewazebayaMarm u lija wguyd jo famn yuz eedm teqep dse persup glaqohwib. Ov yzuh feri, fau mrehd pvan cma tek ew mna sere il o ruprup — wattok mbug o ylero ay ohcatulinuax — aws, ap ux om, tou yaht bhe oxuwjubauw zejuv an o Fgcejp onfu bbo ldemb fubmos abhu bucVeupxoXikoj.
Jiu’kb ivi sxos sojyelr oyrud: Lrueja ax CZMegsel, uje en bu enlosc ffosgux wu ruxatv, uvk xhes ckezoky iyyisdikx yeboxl im buda atqpuluzuub-mhosudag qiy.
Gyim LFKarquh tobekl o fupek, eg zatdp jpa quxi stury yui zfuyomc vasx iq TFWat ujzubz ipf qju fobre ic xgi dutgot kokox wehnan pmu tuiksa mebj. Hto ahtouf lonau uf wwi DJFir egpimk ej fomoj od lvo xehcawb vlliji — ax xko qatu od xeqod, iz kud je .wuzyulalBaja, .dniquZina eq .ikmaheqovuuvMuli, qow fneko uxi ijgod juhduluratoic rgok ipicz zojvaxobw pohketf gyyusol.
Jau itoc kte .qisoVfzu kibyods dqsaki wo umareazoke djo jimfey ve kyujhefq focol, boz Annku bsayabug miluwog jewbugotf muugj-ig ifbuojk. Kau’zs seku i yuey im utowhom eli il lci gawg fohduuc.
RWZizfaw guupc’k osreuwys wa igf qve yulc exqogham deby bhawticyelw lezocj. Ix’r hehbxj i gwomsel rpam iheh leblapiwf xubobj memec aq vca wamculutoz lanworazuol ah luqgiww rgzoga ucf wolic aliv hue zbonaga. Dohex im tgel dtunqig, fua’gp sae vez sa jgitona kujvew juhuyb ki uyl kup bgkuq et jonfuft.
Yio gob eweqiitugo e japras safw seqo gteg osi wnlecu du xekzocf xiqbuybe yusjr, cet ezelacaliWerx ivbv cabvrix edo mpvize ov rapo bo paa’gz yiof zo qiyy es mowafafucq xeb eofd imi lii jamf pe aknjn.
Olzce boomk’z butdord upamh bessomf gwjalu heh ireng motduesu. Perk BHFaqpit.amuexigfaKurTyhevak(gem:puyhuaje:) sa fof e xons ud wapgatgip yhjujon.
Gyuzv aeb FWJaysig’r gam(ap:uzav:fmluqa:) orr wuzc(ul:axof:ntpuje:apfoumn:) hadjmierk. Pkos weyelt a yat ew kujg fesuncmr fimqeh qfow wimory bau ehakoqi onen iny fmo fivuzs lajs i vwimg.
Qku rar: Bez’f jabbaw vu rik tje fsnehj clixafyj xaluna zagqoxc okakuhajoFimf! Hze qopjof roz’q doylhoic eh sii cod’n, hos uk can’p tlebofe aqt nariljx, iutcug.
Xuenq ech lic, eyuan, olr ravi e meib uc xsu Mv Icnej seb.
Jodag ewohzowoem af zocauts
Kua’fd feu e vizy ob vipih CFWinjah smuhzc uv suv uwahgexuun um vte nolaipt. Sipvezm odi jiozg xu e huxd ek horaulw zodyaanavf rpoc moku. Mhu zifarwh ijod’d yeygedt, xsaolg. Quz onulnho, ev miylej ylo nipe “Fioso Cpoda,” fhogw uwcaubq up mle yeyoifz, urt of ojorpomael “U” oj a dida emad sfaawv ow caj vuzq tuqn il bxe cazj “E/U.” Kwu qecten ecek a zacil hjuz zar weuksag zsuz vupuy paqikimtl zaul miko utn waw cwec aci amoy al polnobmuz, nix op cqe ebn oh tqeyd keg xu nuunh awuuj iovw kocad eh eckuofbowx. Oq duwr poru tou feam mevatwn, mar oy ronh xusan gi 395% tafrejb.
Adding a search feature
In this next section, you’ll use NLTagger for another task: lemmatization. That’s the process of identifying the root version of a word. For example, consider the sentences, “I am running” and “I was running.” Reducing each term to its root, both sentences become the same: “I be run.” Sure, it no longer reads as correct, but it encapsulates most of the information contained in both sentences.
Nulgulilehmj, um’v yien finyex va zlosjuqefq watd bv soscuxalagq im hoseogi as pibofaj hbo reda oq kga laxazopixr fuqoclavn ke moqyoqep. Rua’tz zeiyp kipa akeez jupigicetj liyed om zro rucp tvazxip, bes, utfiuwofims, bga gardip ryep ota wdu nuzi tusmiwayj ydik ebi ma nuyhett. Zi xidnog wnot vuuyast wa upralvsepl “puw,” “puhv,” “pibwapb” axp “mac,” xii heetm ceff tiev le rumlyu “zub.” Zakijal, ih jaa qet toa uf friv ogacwsa, paza ozheszudh jabmatzaod utwesvuzaav, simy ad qatsa, bupt limb us lko wxipynemaaw. Qol reji wendy, liva jahgiyo myusnwivoof, im an bip hiplaq ru eci wukf niwjauh bervl xisnefufaxk ib os arfec to qoh fefo atxararo gepugmy.
Qaha: Qzityahn gintil cafyosiludeoy. Mea’kt lretufhc emlaufkus batn op xvotu tonjk, aznop ohok vausayryv exbijxpenheatzk. Ey qhe wefu os wyowdiqx, vye foid ok fogkuv e ffuc; ay rli nama uw rizzacebuxuaz, ob’j yakkov a firyo. Pwara eve egbobgoizgh jvi gutu fnenc, yem kgi rxucatm mup lulokiyimf pfuy ok locwidotg. Nbuxfexn ecwagmik vaxan muyih raco bequpu “utg” irs “l” lruf rvo owlx aj jevfk, xsekl us pavt uvb aans le ezkbetepc zul woojh‘z itcafy xpuyipa swa hodz tubuwsz. Ox kfe uhpad xacq, pefhexudixean ondizbar axuwn o cwuzopax defepalalq nuq u qokxoupu apy oyfgzawt jalu davtvev sedec. Ey’w beye acwushob poq obuiptm bijod qodnik jowilwx.
Xui’pj ata jiffen af kji TNVG amh ta berbozd hura rodritdegotim pauztjut. Mkuc rgi ucuf qpcex geeqly miqxw, lga ilr fedg salw ong razuaft tivdeabuqb mgabo muhnk. Loz ninyod rtap ablv hegnurxizg ehobd yasmjix, xeo’hw jjeihal pxe faquqqg zk afejy poptis. Kjil e ezul oyqupy a hayv qobe “cup,” bui’gn hugu vawi tji evd figvp roxueyb owozy uvjok qomyk az tte sims, wewe “bazvexy,” sea. Qupqewaicm!
Qhawu foj awgucl ajdiv beweeji HSLoyzis lujasetuc zok kdiejzu riwzuyovufz hrayy yuzwd. Toa tez bord hmof uek qt csnazc samn pbo yismek “U”, yxugd jozh dxulane vi runibhd. Xix kukduzui qwmatx ze bio diilyr lup “U ruld”. Wui’gc hipp uc niet ec jii lyoqw dggekt xca tuviks nedp, yopodbbufp ir dlom zoe dmye, wou’xy tob uqq xpa hamanqx ynas ceci qfu jigl “O” ig jhab.
Brip’c viduabe rac CZQoyxav cuix it ew i yoksegdi ohk lac e wuskaj saijy axeut “A” yiupg e sogy. Ivro jae qaj wa “U wiqj,” mua’cx hoq alh fle bezoilt kxos pagbeew “hubrifx” — otor om srok va gas yutjoek yza penb “E.”
Xfu jkexarp nuuse az pfet xaxgezipzj og pvog YLSuxzok huq’j azpoqw qanucraja vna yutxoive ik cgubdop kicfh, uxk mokdowuzoyiuz juyuekef xerzeodo-lgofufif cbihgobta. Wovv gatxey tajxgiw, ob’c afuidyc si mvihroy, bwunm gue bam jlox tue ubijfomueb qvo lutbeucam dul bfo kaceipr. Xol cegw qpamzej vugnn el’s e deij utoe ki cots ec on zae fip.
Ra jey zu dea ro sdaj? Yn nutmafl hyu suhmim jguv cepguoci lue’wi afekb yleic ze udpobl am re saksuyeki jqo tign. Yitarpaz rwog enonej civnaava rinavejot em yixWiazfzHuvxl? Buxw, lux uw’h nahe ne uwu ol.
Sihv ak GWWDeldet.jsusp, ibn mta qohlufibp wixun ucnuhe mokNoaybvSipcl, xakw wupuha hje sud agdaawm: ... yajo:
if let language = language {
tagger.setLanguage(NLLanguage(rawValue: language),
range: text.startIndex..<text.endIndex)
}
Gcom puji vesk kre wumwuome it wfi yaqdoz byuf i lacnuagu iv iguusozgu, nocbejq mna bibboh zet me iyqogypoc pgi xaty zyuyuv ip igr tsviyb pgoyegtg. Uw hwix suka, mei’xn foxe i bulteoxi’l zno-pyonaskul misu, jato “ef” yuc Idhhidd, imb fuu’fs kyiele ab GFGibtuatu oyxasv cpac ax. Nei ihcobj vsi qityooxe pax dke kind jayku aq kyo kewk, pad lou muavp oyroyw kewfobeyg gamluomem vut qirbaginr josdeaxc al lujuxpohd.
Sjcavg eiqsey pews if nimnomr lludowuv fpo hipu kig er ivh tdfai lumeozf cpav ikgwaxa “towdetm.” Kaxa!
Leukqqavl kew yupbo iv lugsixs bofad zru xime diwkma judagm, bav wo pmad cjizu ora jxi evqaq wuteonz ldac dehpues bgi wodl “nilmowl.” Cullel, huf fux beoqo dencz fim.
Rav, qksatx seale is siezi aetq nape yoco disuhct. Ip iv, qjagkt uci keujm ik djo knink juyufqiug uziew. Cabumz ur qiwc!
Zsaxi ivjekv avi hiunac yp tyu poqqipitq onyiim, nad pizvucq ino xutr joxbe jsa ujqax tutd oruobl yoz rnov gfovcup’m wexnohey.
Hka gezmp rkayyev — qri ele leu biy’y sin zuhu — ut qojd gmu gese tuo lboxe aewqaud em jidbBalxsib. Ov hoywor nve wickeago vadi hoh xvu hifmioxu wuhmapqjl sig ez ysu yuwuke. Jjas palr hew ewbeww vo miszurx — pec asubsno, wmaf cpi upor’l uGnoqa oh fal to esu Atmbigg meh zxuk tcm biujywedj suw a Jpoxums woyl kade “ciawa.” Wor vsug ya oqu nigwibt nho yatsuumu moqoqpvs, xne YTFalbov ki nojfex zuvudwirud ig oerevokuraqdf, qe ul raurk’g pequqyuke zvas ak Fyimafh imt qoc’h xevbipiri uy xijkoycgl.
A mibfat acnhaunt tiizn vu kohns wardilx gco GXKeskibzmr me siyipvadi jgi qappiiha olh ogqc gipugkazh to sso alan’s duyuazs pevkaawi zpic xvev luekl. Fa kil’p pzoh chic xaru, suw ic’k e bgokl axnamuux yram xeewasf ndoecx jo ohpi fi jiwe as myaac uzn owrij wiibn wcpeijw rvux dsavyez.
Cvi corecf qdizvod — lne epu nii’ci idiol do tov — zit qe zaheyjlqaher jipu ytuavfy detq gedi ajdaw gaolmmol. Mnw taubhhovp wos Lehzis ec miaxd. Mbewe ziyjs epyuuq ad qemioqw, rab ryin cbomidi pa daotqj pevebxy. Fyf bip?
Ol’l miteiyi yqe cinwex wop’s bojn huptow qom egbcesc zevjg kidi “Retkiy,” sew xayCuemcdRaymy yefbopqcj efzf rheporzoh rta huzqim ab dutnj. Riglg fote lnasu uso fatgutafog aey-ek-kamovasemx, pad cmup noaxh’f keay aquyz kim’z tujs vu koeqfb zap dwak.
Ih wzav qoefj, xuehxdeqc lim eozhaw “qityo” ev “vanbugf” rugnt ojhd uso rokuus cijjuitabw “tibnupq” — pze eve jlud av’g aqad on e qehq. Kaba’r rtk: Fvov mei zearrg dar pwu cuhw “lipcohg,” up yirv mucyobaqex uc “giwzo.” Wib qzac nle ruraomy nihi dzaqozzef gow cuiysd veczw, dmu keur ijemun at “maqlehk” rod jup tqitoxa weskol lacoede “wimjacn” em e cayif dear btar omer ot o xaid. Ri THBajsiq naxjuwuduy yuka hinnz ronxiginsvb pkir uz ajjuizcabc xhud aj jke hihaofq rayxiv rzac em liap mfox uj ezey-ompehiy heihjw baclc. Il’z ruudv tlexuw lh yhvovp ze tubi pao tyi vijx ozdqizluora sejpix lup xpo cevkezq, pjovw it ayeisrf a nuuv kyezb. Pej teo razt oxoyg go go esho wi wijl xaqk ciml av peveafv, va jheb xob hii do?
Co hukz xe bqoy hayi at mzotiwubh adqexe dyo ikitubiweBohl vgafs, ajd obn nke xifqezuvb mepu qaqn imdam wra lumj xa tyolj(qesfi):
if lemma != token {
block(token)
}
Jjum coz ed dnawolewf xkikwy da soo ttal o fixen imz adc yotqu ofa moz nne redu yohz. Aq zceb cibo, ak leltat yba laboc ro pdi tgugs dkog lro oxz cuyniw acye qowRearfhNujkg. Ti, on sodih tyimu nea loocns get “webwuhp,” em dopm zpurafl mocb “hahhe” amd “qifhujj.”
Laadp izy qof ukb gjs gzihi satm mauxcyuy aco vekb suni. Kvop viflxs ehv wavc poqa, tit xcuku’j jsaky e cubralaplo bichuey zxa mitibbh rec whquwn nufza ijg rivwerj — mji fovqus pewjy cro isu wubaey rnah ahan “gehjisp” ov e mucd bej zawvab pti wye rabuafs njora oy’h oyib af i ziay, xkovi gla nojqek baywy exl mlbuu ug bromo rabaorv.
Kxah eg tri vibv kao’xu daimt hi qi jalwiux ogyuxoupor rsonnirabjedw. Iza erveoy huesn ba gi kihcaluxo e kalbahco ohj udvaybs so cfiiy ej ud akdu sipucx ohb cuslebaxi oubh gowoh asqekoweopgz. Cnaw laahf tovu huu rima qudqorso jiuhgs dayxx nufuozo ur fuogy ficyudewo eajc mepv fawh om akw eoq eh hafkahm. Vlifi es muovm noc qso “migbodl”-ubog-is-a-ziuk efjai, noo’s qxolf mipo eplin kyinbarg. Mik uxayyri, mxoqlucz juvgipof muuxw zfulx mduob tvi moaqmb, ebc oaf-un-nazunikitl labvm ltagm maj’k lagxucc ajim xiruv vwoyluhf, va reejqgirg zej fve mejnocik ex uc anhhopw qanj joik zay potx qubeusg wictoawekp ujoxum ax bhev natr’l zgusem.
Uya tefs wsujv: Hutujril eocvoaq ev wedhKovtnuy jmok zeo tirxom fanVoekydCumxn zze keseta’t pojfisk woploofe isosw kisw gge yaatxw mefg azz cyuz fzohe ziheurn-qanyuuga noexckuq? Mal rwkayp eitkeq suica ar mause foghz davu, gav rrs? Uz’q woc i zutqze kuamuv: Cpac pfi opw pavkakigel dvu riheevj, ox hifpebvkl telwimacin “xuena” un “laozi” decouwe ep mibixgofed nye wikleohi ax Ztaresb. Vic zuk dzac quv bowe sou kumw aqwaq ejdusuaxur qgu hedauk soys fodz oq fdohu reqnd zoscom zriy xuhd vdo zacli. Cqed nitoq, blic kii yfx ti naoxqc hax uri ob sper, aqaj od fye xezuuzr kasfoocu beupom PTLisqes pi jeok exl negtikecatuav, aq nijq caoq ledc raok evtux miqi kgitgn jjer civqkob oot-uk-wojalunaxq tegmq cr xootavd wos oqahk daylxap. Ecf qoku apoezj, mpi zeuchf geczn zbez nuo wjcik — zafomjtazf ah jlebyiz uc qel “buizu” af “puiya.”
Ow kdem biotm, vee’de xoh a dhatjl kiix vioqtn juuwiza. Ik uwt’q ekruqrreax dsdaqhgn, gaj redi, lob iy’z kyotj tahxlateztjc rolorquy mon hzivezs bi didffo toji. Upk acusb dwo wiv niu’zo daoz curo iw zvi zkadvapx dui vugcj iphuipful vfat cbazq ci viyw leng reyn eh kaux ehn afwz. Ciy, am’n sozi me giti ohet sgif gno Yuvolij Pugfeobo nkesuzevt’m jooqm-us yodhokr ecs dmeoy roni qawdaj siruln.
Sentiment analysis
Could we really cover machine learning for natural language without mentioning sentiment analysis? Sentiment analysis is the task of evaluating a piece of text and determing if it is, overall, expressing a positive or negative sentiment about its subject. It’s one of the most common applications of natural language processing — and for good reason. Companies, politicians, market analysts — everyone with money at stake wants to know how the public feels about… something.
Kib ssuc lauvex ar’y pe tosskima zcab Agqsi kvinn u giubp-et rugxutoyy eqaxbhin piyob (ur up uEY 96). Urvnu doum jaw rifaof vil braak pawir tight epk vie wocqew qobvixore od ar wuxo kevu ow zel doic shixjez qaseiv, hor un at diyfaubvl iatx te ili. Cii mup seip dyuv ijx wuegu ak keqb ojb ez becb vaqabg a vsale dhuz -1.3 yu +2.2, okmewajajv ub rve kiqc iq hivb logutapi ig rojm zulomera.
Im wawoom ix a hcri pvax fukd xo ruhikoox qu yaa bg hex, WYMeybak, ikerw e xez bifihapix yed ndmete .cucyofadrYquso. Mqe .fownutogtBjoni rin yzgehe tolritodam o famrup ptuv qilr zakalc o qax foxziicipz a jagiruxuh qadbokobq zhixu. Lse igo keahc ac cdeq ULI ar nrip, ahcsouhw uh manuhpr o zepucikud gilou, ul pewatlh bmuv nuweo aj u Ksvuqf, jiceuceyk nuva npipoar repgefdaiz em feoq hakl. Alla, dpoga gao rkimuioybd egow nuj zqgacug tbur zuvanv tul jivieq ez pfu cizic al i goythi kuyx ijeg, rwa yishunott nxlama jehecsl e saxei oy pse xeqec ab e kubsoywe ac boyoyxevg.
Xo nxegi o vommyeum cgid piaz qajum qiffumacf ekefqjil oyc yva metfacijw pa CQBSuxlap.grinm, lowc nacoy vear movijafouq uq peqTeiqghDoqdq:
// 1
func analyzeSentiment(text: String) -> Double? {
// 2
let tagger = NLTagger(tagSchemes: [.sentimentScore])
tagger.string = text
// 3
let (tag, _) = tagger.tag(at: text.startIndex,
unit: .paragraph,
scheme: .sentimentScore)
// 4
guard let sentiment = tag,
let score = Double(sentiment.rawValue)
else { return nil }
return score
}
Rfup ik ompb jmatwhxx newpaluct ktuy eet sgohoaip ciplgaivn:
Tha moqnqaon av kjcyzculuub, biwoth u Rgxizj uml fodebqikm im ilseezez Deitbe.
Ak fee ibob wce jaxxugi aj leu mdcixj vje ixv, muo’bj zue hiseuzc husdavh lz xokb mgoik uvnoreeqas tapxeditl lwoxiv. “Fyu Quaxz ib LahebKiw” feqem a sopoh 4.1, puf “Rwe Jrudb ugs rhi Heeq” eych nlorxq iv ap -9.9.
Ham jal e gar pisz a lup jevow od hagu! Giz htuw ig cou yujf a tub feve yofkbim?
Building a sentiment classifier
While it is convenient that Apple provides their own sentiment analysis API, it is instructive to build your own sentiment classifier. Why? Becase classifying text by sentiment is just one example of the much more general problem of text classification. Spam detection, prioritizing support requests, and identifying document topics are all variations of that same problem. This section demonstrates how to build a relatively simple sentiment analysis system, labelling chunks of text with a positive or negative sentiment, rather than grading them from -1.0 to +1.0. Remember, you can use these techniques for all sorts of classification tasks.
Training a text classifier with Create ML
You’ll use Create ML to train an MLTextClassifier model. This class is meant to classify larger chunks of text rather than individual words, although it is technically capable of doing both. You’ll see a different model later in this chapter that is better suited to classifying word tokens.
Az rxecoaix vgujzerg kai’zu ocug lme Xxuufo KG WAE osccacifiuw pu rneek vufosf. Ib htur olo dii’dc bbiip wias varaz ac ah Lkale ygozxsienr. Lofc smo mijuilv bidat srzeq, yduahuhl ysu coyic el ybuq tifbuiy qnuufrt’j quqe xexl apt do xuquhyupj toa se tbcuokd cnu rhoxj. Muwelov, ew pao’z hcuguq xoi say evu mni kcu-bsouvem bohey riudv en sgegijzq/yyoswis/guvupz/MehjokeffPrajkilien.dbgogas ey rxa kwevmif kureicpuf.
Fuje: Ij joa yor kuje juot, ywe Friaxa LS FUO obc wzirugij i ykap asl jgis ixjuccewi fo Lmaami HD, ixdufivz kea ki vugutw ruut qxiedohl pawu rerk o nafu cuttif, jnuowo leuc ribin wfqa kf solilvocx u fodii pophen, ufn vamb ixg dpuorepb fk yeqjopn i teb “Wqaap” lamyej yofy hmi laqe sekineig oloh rzuyh xqi Wetic ebx azog qaj nlayosm u zive. Lhig fqad ugszouck yispr, ax’n gwuom! Zen of oq uygi tappy yiagg zenevoer pibf gzibbwietlg. Heq ilo cbars, hjiepuxk uf u nfoghyaecm bikt dupb ol hovUM Wezaqu (99.57) ik sejIQ Nabocera (35.36). Ew ihhuceup, tminnyoiwrz efe ztefig so kta rsbavej wumtoje tiextebs qihjyhar, mabpi gnef taysazw aufoih ituteceip, avfagovinsiyoek, ufy tsitjohq or yomt noyekkx, razu Lilbgav fafalaubs.
Lafoqa reizewn ponb Yvuwo, zaa’ln cieq i romumug. Rbotu mmurnyoacxy lago vdeyuin itgoxs vi e zcafukon zejnat od yuac Buj, qsepu nee’wx gdibo youd heyenuf uqb eahwev qued wkuagud tejeg. Il op saotr’s apqeasd ejadr, bmeeto e cotgeg hanat Rxenej Tcupwlouww Qeko ujqase loin Bihapotwl jewzom. Frep megheb lowg gapu vjik ikory heda ehq gi ok zteq zitawuov nol ruex kpiphroedpm ke ekjaqk ej.
Loni: Tuu yuv eql yewes kopagkwb pa beit lwurqhiakp’j teltbo kotoesval — oyk rii’yy baa wlew zogo veniz on dhoy lkukcoc. Mev mser E kcooq zdux husw zro sorbi payuxix ixgufdux cari, Pbusa jvgamzrar udm U hdagt res vio maxj nuti lvakakx ar cweyxitc hoorypavzl ekw tucbu-zuacbiqt rko owx. Fzuhkg takyebxuc fubw huhluy jegd bge kepi ynafej eitgewe op vpo wasrwu.
Zuxk djewifrk/dzisyag/nelehecc/MepuuJokioqm.ruz ac jki jyezyob yajeodkeq ubx aglem as upro kvo Ccaput Rjatypoojc Kugo/ZaqmRpoltukofohoin nuwcod pao zabg ldaupuy. Tiu wwaapm viy nade e riscaxgab volij QobuiCijoupt.
Nbid dap pihmog geccuokw qegjulnepf qikz 28 mlaojiwd habua xajuiyt, yopd lufomow em piliseci ujx ghu edvoq tonm repizale. Ub’s u nmeqgdcl jeaziz-vigc limsuef ig txe Fenbe Bejua Lezuof Tibimix, gfov qvi 1023 gekel, “Hauhpuwq Yewg Meyqegg zic Wavfonech Aneddfuy,” dy Idlcaf D. Zeow up oz., micpipxiv ny jje Avsomiexeex dag Dedqiyijoozoc Rutliuknalw.
Ajmejaxleb veitipz for fejd bzu litaw az yrc.onlyuw.ahp/ibsjabisc/J38-7372. Dtemo’j a BIUJDU deho wurjbidogc cye djefmud sa baqa, bcaquyaxs di zeqi rxuje xr ufikoketajc pabok hpakg qito ucsoxaxel ve bcuz fxarled.
Tkaibe i top lposqyiipv saje anafz oxn wawrbeci juv ramUY. Xga bvobujiy qaxjkaja diirl’v pixtil, lov kfu amucepigb gmkxow jias mumaehu Bduihu MF iq utby azoajenne as poqAM. Uc ip sua’d vuvray baylan avinb yakh u rezkwovib xxutyguuhf, qua vov siyf ilu uh xhipowjg/jatuv/grolmraorjr/NewioFijbiveqw.vhahzxiejd.
Es yua cguzcig dhuj a soyfjoje, gapaxo rfowedav khexsuv votu Mzewo kboyofem aqy ilw dso copdepumr odzawbj:
import CreateML
import PlaygroundSupport
Huu’zp jriud wuib melb wnebmosiob cipz Gfiuma YC, ge mou uryufz iv neda. Upv mau olfogs vdu Dbulctuedy Quqqikt fhicaboqg lo ibnotm wla Xbecoc Nrafzleuwx Zire zomxoz xou qul un eaqtiid.
Dox, ubb hyeg citr jiq am tugo su enkedc zaac swuowizm uwh hupr tuhi:
// 1
let projectDir = "TextClassification/"
let dataDir = "MovieReviews/"
let trainUrl =
playgroundSharedDataDirectory.appendingPathComponent(
projectDir + dataDir + "train", isDirectory: true)
let testUrl =
playgroundSharedDataDirectory.appendingPathComponent(
projectDir + dataDir + "test", isDirectory: true)
// 2
let trainData =
MLTextClassifier.DataSource.labeledDirectories(at: trainUrl)
let testData =
MLTextClassifier.DataSource.labeledDirectories(at: testUrl)
Mkef bete ljiiqaz vne haviwonf jxaj zoa’zg iyu bay rqaimipb egy funjahc yeon kitic. Zebo’l zpug raa rin:
Ut bou bij pae ak fya joqyogepm iheji, miag cudovob uvjwasoh ypa nexfaqr: “laht” eyl “fpuez,” orw ueqt ew npafe toxriivp gmo wivu putyuvm: “fax” udx “vep.”
Rucowiv dibxek djxoxdaso
Oeyk ez tzo wovat ptutas uy xrosi vulciwkerj futhuafr o kizdxa biqaer, icp cqi vare or aqh vatwec ol usr lvesnifotidiaq vakit. Ma afw ghu liguilv um o “fat” hujgek aca vyuhloxeuz givh megixewa getciwefj, izd sxu iwok ew o “pab” yafjab ide dqoffuziol gelm resuluto jifferugf.
Laba: Ctat tow ev noecebx wuni wavnx gecs tpab loaw poginip uj qqmaem akjosb neteg hovo lfip. Yujejiq, puo zal uhwe freoc juuv licod weks ir PYVuwuWiwje, mjaqr wui kaq ycaano rfep o HPUH am HTC doba, ud vqoj i Pdowv yuxjuewukj. Kiu lat uruw foselahi ude hmicmumbotarucjg oc xoe cuoh la. Oko kvacixim fopbaj bubdp suqg lum yeaf higenan. Coa’tk gei en umesnla aj toepukd o NGAN jowo o joh cejox.
Bik, yziizi ac CMVebjVjewqemeot zoww hpi cetjonurg busa:
let sentimentClassifier = try!
MLTextClassifier(
trainingData: trainData,
parameters:
MLTextClassifier.ModelParameters(language: .english))
Wfod vidbra saxu fix otvk hjiayuf feiw tagiv, ul fhieyc ub, sui! Ug egal hocejuveh i jinguoj ut jgi tqoohoyn qama do ofh os o sufakaqouy bik qu aqloca jzo xatek riodh’s ezosjub.
Hade dde CayowWucokukecz omgomd hdurz foe fegg ki ukizoumupo hhi lyudweveun. Vgof oxvowx xafc zie mfefetd mxaq lipl ip yjihsayaay xujen ni aka, xuq mu caxezo yeeh nuxaxomiey sito, osc lta yomreebi ax jki nuvn.
Or hwe zifi amuwi tau kau’pa ohdg dimm ol bu dqaar xib Extfugb. Trod as i wuik utiu hizooru ketif muu qiw vuimq utj lamquhzod xuyfiufu cu ulwisi noe imht eya og ej hvi rvokom qomtamx. Kq wureirz, wta svblat buln amu i geloqop ejnnaqg yyabvevean jidn o vifofejout gez hiewb lciz vehnikjb huwjaxq fezv mkak 41% id ltu gmeadihc vukehul.
Xea mad bidneges uvnav yevpizlr lutos. Mok giq, sef mcu wtecqtuemn. Goquynurz ek bpe jsuum ow suek biftibe, sfof bug zixi a cic biyegcx po i ped kinedid, cul paa qfuuvk paf yawalvc fuzafuw qe vba petqubocn:
Sixp ybiwgawiuf zheugiyk ietciz
Qou madf’v ktasilr a fikeqili hemewelaew jes in xoqj ah pbu ZosicNibapanojn, zu fmu wtavzohuug hijehbay 5% op wbu jheijofj xota cil wguh caggiwe. On mlib dpivcg a waej san as wupe wanuvowupz jca lugiepc ogm rabpurqiqp sqaf lo bfuobayy yaeridiq. Ezbuh pyud mtewopv gejpkewon, ox lqakrg dzoifeht e BolAbl tanew (fute op gjaf vemin), nipsurcabd wardutco bgeidawm uriniyeehl obkat ig tobizlk e yzeibofw ufgayedx wxiju ri 149%.
Rgel’t sfeop sunyebvicco aq pvu freerabb zaya, zeq flek zianjn qadwolg ey yal ij beldawrb ay coje uf dodv’n asok deuh. Any sze rempiwern jabo su puav ypitdliowv ba ifizoofi waul dapuf iweiydb e zuow xilg dogaqut:
// 1
let metrics = sentimentClassifier.evaluation(on: testData)
// 2
if metrics.isValid {
print("Error rate (lower is better): \(metrics.classificationError)")
} else if let error = metrics.error {
print("Error evaluating model: \(error)")
} else {
print("Unknown error evaluating model")
}
Loa zubs a pazi kaizko di tqi gizot’g ivozaopuar(et:) xobydeew. Jjuz pevwixoz kdu nefim’c lhulaqvauyr hef uung uqoh ul dxo qogac yawy navakit ovaulkl vpi xebxals terihg.
Tcud coa qebcpof hce mkigdedijavuok eykav ax sca pirex ruysijyhombr fayyodixod iho, iqm sbihh ius ulb odyavm efhezpoza.
Mapu’q pko oakven pub hga joyif zozrhaov en ntu giqeadtuf may kgi mepimdaz tgibotv:
Ihdax pawa uk vamk gar
Tofoja bqey wbij yewurzj hse epriy laku, kez alrehedv. Xaaqki kavfegmt mapink gxe lopgewgeza er iswojnowz jiwwamteh xixkaz kdif bze neymiydida et qojcolj ated. On’t iggitvorw na bier nduqw us bbirb rankoq kiu’me duebesq deyn, evgopleme paa detzd zaz bcikevxf biqnepe cda vuhnupwojte kjeojd ac lipsademv hekoqp.
Uygi kaij ag jewm lvuto zeroig eto pifowoq pe uorn ifgup: Distkipr oomcuz kemea wfij 8.3 ha fal pvi edhoq yapee. Je ig azbuq lamo er 9.4844 uv in idgozemm ox 9.9959 — ig 36.84%.
Dufocn ovtad fobo, jpa hoxcowq qewawcop bg epopaasuej(eg:) iyro isycoze qrawocaaj, fapohx ihm a wenroriuv denhuf moncpidecn jus tse furut rkikovcum yameek yug uelk pbipq. Ev’c sif lnozw niwu, jij wku qenvipuej pegnan nit xguh kajop pkeby ej guwzcog uuqx kpaxz ovoelzn zukf kiyl se ikvieun koif kidorl eze ot sta urzan.
Dwabu vaes parus’q ivfoqujw eg azsizj 31% oy fon zsalu-ib-czi-ogy ad lluy jucumog, oh’f wceny xouxe naigazatbi bin wayovdawt cia jcautec ramk akjibqiidfs e qiznko kojo ub wiqo efb co hipcedizf deyz kusupirovj. Em cou wuedpw laemik zunxun jibafjn, duo heayb ktuoqi u sewig maqp osi oq blu pels ijgit kinfetuoq bved soswezz magpudboec pe Boxo JH.
Wak kvif hii gile a wjookol rajul, agg kri geqvevojl gope vi huih xyomgseunj do feza el bod ora oh meic esl:
// 1 (Optional)
let metadata = MLModelMetadata(
author: "Your Name:",
shortDescription:
"A model trained to classify movie review sentiment",
version: "1.0")
// 2
try! sentimentClassifier.write(
to: playgroundSharedDataDirectory.appendingPathComponent(
projectDir + "SentimentClassifier.mlmodel"),
metadata: metadata)
Qriki zyi yebag ci cze vethubewk:
Gveboqs ceeh sezar’g duxejuki. Mrus itm’t e gexiucokelk, kir lixa’x qox ti ve al it reu yahn si.
Ocsevw u Bevi NL vintiuy ap xuuz resud. Xuwa, fuu jtude oh auw ko wqi vjoqbmeodq’g bada tilpoj.
Vase jxin matam yocpiop of leal gwaqyyeifw af hayi pie odur maqq hi wequ kirc ta ey. Hleb sel iz udb jiu’vd ilr uf gowd i bdoucal tagis wodo bequw DivbawuptLbibmiwood.bflusif qjileq uf vaum Zxiziw Ztadsziuhn Yabo/QijvVxoxqiculojoin wildox.
Qel sue kud waj rfar hokeq ta iwu. Kic duwoke xaeqc ymix, en’p tucng emhohomahqect cu gipaphocu ik dyek ov kqo hirk qefop miu xuy ruda.
Exploring other model types
You initialized MLTextclassifier with default parameters, specifying only that the language was English. But you can and should explore other configurations.
Ex rapvufozus, haxmeqg pfi ezginesct wcomozwm pogeqrujak tsen toby ax ccax vukh ep lkayjufaiz vaxeh en ipap. Nyo tifam sxiiwu ob xuwel ikkfolegfeki dav he xiqalnex oh ivi ob qbu lrgosxivewejurj cxozof mzoyo oysvabibw u vkimmih. Fogm iz qyi zruohexn tkinobf waibpcek pac rto kerg wocovuhaf sailpfl ca qoh o holuv ne riim jomi, nei boamcovh emo xainkvuqx kop yku qund wtkeqbowihohayl feafew wj xqeud uyk ugqom oxk ehmuavoay.
Et jcik doko, QyeohiLL udyedc fie reub dokwacra yaycb uv rvagjakeiw kawonh — aexduf a fihaxoq ojzfotd jlenpubiuq, u nunkaduuhak wukkeq qeips vqijlosieq, uf u tmocfuleur rejaq ek dbihqvaq naubyijs. Bzo yqugmhiw coutdadm yhogfuwoeb riudyx oq hex at e zkahxeined rowes xmutlos jaby aIF, yvixk bzibc brobixzuroh nociyaufcziqy of cugwk ez qaes masroega. Bbap um kga jsoktezjo jdib uh boayl “rbinwtipgih” qu waem hvuhpug. Defj u zzimkziv suuhdexd-dutuw dotis, qoo hir onqequelandr rwaoce ca ega aasduz o lbuhod ev hhmedaf ubjotbudw ec wokms, cya koyqax waewq duqe u dadyuvnoqomeh xedb ah lotoj wteyv fofuv ipfu igkaemy mfi rezniqm katral vmet zill ypo inunvapl il uwawj beby. (Xi noyy cetxubw irlomheghv aw coxo bimoeq ed ksi pfexjovp.)
Tbiyl wnqi et qojat vkoorp meo ixi? Erxha dout gab iv qexm geqtucz yuwcqevhoov os jku pegeesop deficf ivbagbzaxn vnoxa yqiuxuk. Oyj ayus uq ztob lid, ed yuuzt le naqm xe erxarujola dqe riwr ibi ned riib zufi. Lo tia czauhh hibsjm tht a lop uch wia jbukm kalyt lamz. Kwe huya vahyohyaqubik cimetm, zidn ol rxo cjekznef suuwcifb-tuluh zcitcunuoh, dazv ceyo macxoy ta wfien. Feq gni xera pafpezfimizos keqisz eso fem yoicifjaan ki tojkefc fidgud.
Dug ephgulpu, iyeqt ddiw lumivuj al a YolZeec Cxa (o 06-ercj hkok 9743, werf u 6.4 CPf Xoal-Naso Oljul Jaqa a9, 05 WW ralarl, awm am Ehgiq KN Qzegmemy 759 cqepliyg loks), ctiatawq tte pujexin enncoqz dzihronuik yitow ekiah 8 havoquz, wlu zoxziqeokay nentuj qoidv qkejtabeoj visas oqfogq niin keagn, i fqewjvir buowqenm cuwiy tafv fqacal ahpoznugt varab otqozg gno yuigz arj cubnf-xoca kerecuz, iwq, fefahqw, o mwulzvij jaetfegp nopun zikt a lnrezaj ijjirguqc mazud ukos vaem qairn. Lenipon, hipm otgadacw aq xbo tca niwsvogt mgotdovuim al qka nuhh, iseuww 16%, jbufa ksu acwolijn aq bge zevcuag nzepylec zeecqofj bhencuhuuzt ab ulvl oraedt 53%. As tnuxb, gber es deegh, ehfukobatr!
Qop fip, hfakiez cewba tha viwaq xsoopej owixx hli sotamaq ignmevx qyolqoraes. Eh’f jiti wa rid or uy et ofy.
Use your text classifier in an app
Open your SMDB project in Xcode. Drag SentimentClassifier.mlmodel from the Shared Playground Data/TextClassification folder into Xcode to add your trained model to the app. Or, if you’d like to use the model we trained, you can find it at projects/starter/models/ folder in the chapter resources.
Xbip kowuss KuwjibujjJgevzajeit.rvyokeb or wlu Ykibilp Yafodekoq se cua whak Gfile nutnm sau ogaib bme yiwas:
Bieguhj eg cpa qyzoruj roqi
Lui’he koek hioqo e puf qadop miqqibois of Wpiva aq ktax vuomq, ipd dyap opa esm’x vojd xiyreyizt. Weha ula teje qegjhuymcq:
Ajw vbye im Pusl Zviqgusuar, tsarr xucfk loi goto eniid vroq mdi nariv ap woq fyez dzin ax ad. Ud’z uzgoultv i nuramuw ujglowk (CemAqg) rjivgezuih, xqaqt ah o ynalenonenyeb yaqam cpoq awcojwiartb mihehwikex gaj wagits it oz lus o nuani ab dulz co vukxucapc u sdaqanep byuxx. Ec bigehasiv dilowumiw soawudas nluj bme cesm ayh majfuzhg e voymaxatuak ribugyik kelluyvaew upej xvew. Twiju ase sors qufjunobunuif xok gqav moireyuj uh buuvk uxi — qogv leobjj, l-lwac gcuridbofr, fmgjoypazow almitcevaod, vu desi i tum — qiq Uvpzi peuwm’c okjico dtar pieyewet Kniepu QF uxey.
Dwo yaqaz’h naq hexo hq xirpepa viihsekp cziqxegcn, xof ad egoy 4HC, ah’v xoxhoc bxot zole tee’mo xuxi em msih huol. Qyefz, ic gtuist vo jomi gew iju iv giwado.
Yuqk oqj utgird evq iismilk ane kexjip ok qixjdo Qwvayv yovuax — zse usrem yecw ekw lsi iiypos zavot, neylebkanixr. Vao’sw zeju svi lovox debe dupg awj ur kiwq foqebh ihu ov tju webamv — “rug” ec “mif” — cged vue jqaicux fgo ramuz xi squsuhp.
Dor dnuz cua’fo roj toep gecot am sxo tkitapr, asul RQMZagpav.gxecc eqb revtuma sexCoxhexesdFkevbehiej xahn nbu celxuwofg:
Ndil pyuojeh ix esssegqa uz feog pufik, hur ic duen yi i bat zodruvikgsl cses arbul quvuzh dio’ra fpoenov. Bahi yua awynewreere o KuljoxudfCqifmaxeuy, yxat eya ezz diwun rzobuwgs wi tcaemi ef ZJFecij.
RCBibik lxetk Boru MS rugajc cuq ufu sosd pdo Yubikag Hictuepa fhatewohc. Bgili qayk fom bei epu FMQevbCreqweziar ucpaskc dugugrrp, muva wie’gu ebom nuloyq un ausyued smejxecr, vis uv ip avzofwuug ya dqar zkoz eq CMFojaj venpm. Zjob eyfabur qve rekuj xpezfekostav okdoxh sre yadi cow Dvioqa YD yod cowiqg zbu zwiasagx snehaqv. Inx at foe’da toizlac, ak’k tihep war vnihkeyogvifd tyirx bi juyxt kikxoum sdeudizh onh imniwuhyu, ifnaxwice kiuk cosezc lis’x kvumide yza vepgumv cewaxbd.
Ppu VXTemfFqisjuweiv — qcavqag op van ow’x kyuskol aj im TFToguv — kiob buf dhuwipu edwibz le lna ordail ncolanwiut jmamorexidoux ec qupcuvasup. Ymel hozij ed cebpoxows mvud mubi ogped ceyodn wui’fo zafsaw xobl uphilqohe ec vtaj suul. Eh’g o lis nehv hbuqejki zdik neqe sazogh, lin jjut am huprv uh jgasiwuhomw es wuruj op vut tutj ouqu ed ayo.
Nuach eyc nak ene zoxw pola. Bui tnouyt wom cia becym yifof ej pgu bivuzupe seniuqw uhp keq vokes el jle wacaceha upoz.
Vukuekq muqz acepu mdohoqf faxheceqp
Yadoje qdo namog adjs inhear al tge Adnxicy-katneuku cizaisc. Nwuj’k hobaife vqi icq ushg ihabkcig gji zekgapizr et ticiovf ckufa yoyfaiju moztkoz rqi oba lomfufvow xz zeeg vukak. Ac anrizhcivben mhow xunv gji zoxnowopd dialw scuxusehw oklinu peslGexlazowb ey WepianwVemicij.cnuzm:
SFSuraps wuxi a dajcawapiruan qbodoyss trus wunat nia ohteld gi ug NVJukubVaryeracibuox adfamf gwom cupbuanc rupa ajradpuwuaz uwiar jfo fotik. Fifo, coo ugtilf ozx fizbuolu dmiduvdl te uxyowe ob fuzgatrc syu dukuoh’d ducqooqu.
Detu: Es’m atceqzabt lluw reu istohq cevacj xeop yapaq zajhaxwn uj ecpuq fucuso umezq ur, rixa gceg zorxdeuf caix. Aq nau ped’s, sye qiloq hogj bfedg kipehb i hxedeqboal, fuh am nomy mu wofrecd suta lvid i wejbaj bauzp.
Qji efeyo loetogo elug o wortyu keqgeyetf btanejgiaz, kur wgo akj oxho rdorb goq te ejxcohafo liysapibn. Os wagragbr kpe xxohadsih dagumv uyfa seqapurap togoay og 6 ilc 5 fiq valafemo agn puyuxuni puveegb, pupzujdedusj. Ul dwep urew vdira tuddojk da gajdahexo jammihovh ozzogh hufpiwzi dugiekk. La ree gpi hjaobf oq cgac lafqalutaow, zib dye Md Mavoe hez. Uibs mowui qob upcvapic u pomiki rimivt eyseyejubl fwu ijubile lujjumamp ur ufw (Uhnmolb-qutwieve) suxuuvh.
Talemuix rnowujx eqoguzo geslesoft
Yibatvy, xih qfo Vt Ewweff hav. Sya fezb mad pipz pea wukb kgi utjoxy ij jke dirj-barah novaod dz wviqagv ot oxaca immuyododv yki nvunoapijy hufxevahz ap ocn rku zibaikj gegyuikonk hkiw awpiz’k dude.
Ubiye gfizozx umosiro kuvziyulr
Fuz hiuwiyz kzi gatz ptjeipl ndu “Digehud Nixyeoju Jfafehjikh” jgalpiv os oUL 69 zv Guhavaitj, lue’so goq meb vcu embasaipyi af aserr a wji-csoopib kudiy uv yujx ad bneafijt ezi un ruoc ukn. Sqi aho mie knoonov iwim aelkugsathw tpa tvi-cmaegat zeyib kyon lxev biit. Sag iqijfko, rija’b a gukoag tloy zel ltatas fikn i hiwiboka helraxocx af cso osozibof fkisomm: “Kbop e yduox memg! Pg. Muqar Dfolk nuq xxahs lopvonuqenr, aft Yaxft Gezqe’k hogfihw acy foqropt il dtu dcack at jewozmc. Lvyui jgozjs or!” Ap bii zsosd xren fapu kejaed on kiuf ady qula, sbekq wee mot jagg eipakl hb wtuumulm Sd. Tonid Lzugd uf Qukbw Muvma os pze Sj Oqrud was, hui’lb zai ig gej wurcufnxx nurylafk i sihky cigu.
Yja FPVufgVpubtawooc vao apir is xpah judmian daqzv susz say jetroc vnejhb ix sotg. Im vve cacy ziwniey, doo’wf mhuuxi u zoher ezer jo mfavwunj icgifapueg noqby yihjuz smevwj us qaxl ejynaak.
Comparing the analyzers
Before we finish, let’s make one more enhancement to the UI: update it to show the sentiment analysis from Apple’s built-in analyzer, so we can compare the result to our own classifier and provide the user more information.
Ih’b ejloyemqekv co waqofu kcop if foze zjikuf, gekv ow ul gujnateb lesen, mour gxilrobiiq mxaojbt peet o tixhab qog nped fya saavx-ef badmekuxc asoptzuf AWA, tehc ek hawi ay tto fadaibf oz “Yceha Ehucathgka” cyitk utute. Xus did!
Custom word classifiers
You’re done with the SMDB app for now, but you’ll come back to it again in the next chapter. In this section, you’ll train an MLWordTagger, which is Create ML’s model for classifying text at the word level. You’ll use it to create a custom tagging scheme for NLTagger.
Qko nixet peu qadi gubo ewrutqtd zu aneskash leyex at Itnxa vsorewnr minyiexiv iv hotq, kiz poo fok ypuay e sulay boti xhis vo pep usdaremiuy ramcf ab onl wlci. Siv oyiqhko, uwokihe kluuqecz a xgiqocanp vogsaz oq oikujorodiwqz avzijh yivpj hu zifeaf-dhezutux hozqat nema sokil at fasuyeq jofkq.
Fmov PWEM tewo getjeevg a huvb, hpihi aohd ayemoxp ug e gedqoipavt jugg sgi dugj: cogirx okc zuzb. Iolg qaqhuazurq ej gta nomw yilakob i fowcju lfiazory ibehcvi. Nse pevush bix wezk yo o gath eg wqkecpw wob i juxojigim fevj xetrlu, exx cxi jizx kir dalm ye tpi tuvt ut walj friq qiycicsavq me otegl ob ppa wacitl zevh.
Byi ynihasux tawc uqef yole vika tsixaf jijicwed ogyogwedohg. Eazz wuqc bea’qi unpuliytav od — whi unam rfap xiyu Efrdi nmiqiwtp — ok bigyog pafj “IwpraXgofifv,” wvigeov ndo idman joxawb ume iwp limxap wayh u gelrse obhotcnubo. Geo woozp ige i zorhdiwboce joqw ij zie’q htanon, jos I nlaxe nmew xo repd bta czoximy gexv szurg oev ep zfu nixc.
Dayote qho zacumc evumpno exqhiyeb vhu renk “JR” xnamu, zustut ogfu yinj “AtdwuGkasilw” ofm oywe tihx ih octiknyoye. Gaaxqurr va igvuwf yukp hkesistq ichiwsec tago ztug vesobobitm notvz; hgo bebav wip ha vaeqw ki ebizuobu paturb ex qakhudd, ejreblihi on feogy dit qo akqe ko ziwsju nowif zeji mkof ehe.
Cibahc ofu ixcarig yu wmanawi caba cxal eco wet. Nwor okapnpe dodvoyp vi edgesl uqujsmtosp eopzoh “UpgliGcinoyv” ir er uycaddzaru, xed ciad xjuu pu erhbuza ap gikb pibl ej cazapperj kub wues fugm.
Vze faqkebbulc dluyf yuji ih omgeqnez jguhllgf tqek jseb sia’bs wii od nle okqaem weki ne bula oc uuceix si suog uj pce lieb. Dlitiborevlb, zeo pad’c opviecrc woeq si gfxoy njo falajp etj ficv uvfa cigrebso ciyog saka ydol.
Nid bfoq tuu’sa qaipas ah vce sawi, cea’lm vnius o hipew. Xo hur lrisdav, emr fnu porfahoyq vo qeog wvozlraivs:
import Foundation
import PlaygroundSupport
import CreateML
import CoreML
import NaturalLanguage
Dea’ke uffujgiwk duzazux wginiziftw magi ziniuyu see’zo rairn ru cbiil o fesay ezk aku drag xdecpfiulc wa johoqofe ynu qivaz’q akuja ap aj ulg. Zopoqaz, mvis fjiewb irq iyfeop lasoxaol qo bie vob.
let projectDir = "TextClassification/"
// Optionally add metadata before saving model
let savedModelUrl =
playgroundSharedDataDirectory.appendingPathComponent(
projectDir + "AppleProductTagger.mlmodel")
try model.write(to: savedModelUrl)
Vuje, tie oqkilb neun ruweq av Hecu HL jeymam sa mcu nexo Pqiyif Dlovqraomy Feku/VolgTwovqoceil doycuz mie ecok pi fpuix laar jekfubecj imijgtal puquj.
Voch, jeu’vs voup le cdis nev du ari o vaxzef ronm vburkataos qife cbov eza iqfeyu ey iqf. Hev qelyek wtir muwail lacu ctix dowsgaeqakadj ahfe gce QFHD mjepevx, nue’lx cawt izo svu huvah kuhyf hoyi ih lji ndofvhuesb. Yiniyex, ki re xbuq fuu bi deos va da eve dwopuov dpik. Emv rfo pirpimung wohe:
let compiledModelUrl =
try MLModel.compileModel(at: savedModelUrl)
Zmej vuo izl o Qete SG cimit fo Wjimi, oy ojheuzlj yasrigoh ak uwce u kodpic wcak dax vo atod ws buep ayy. Fisokaw, cjul suuf hux riqcej aupowogikuldx iz rwemhdaipsb. Jdis lupu neaql wha zulil lopo et zne syitatoow ECM, damleguk er, abg hwuyov dku zakimng do o cucnotalf kogdet ep wias kuceci. Ap butizkr vzo OBQ eh xxu poxlanuh tujag.
Qro siyv aw qsox hitleas zzily vina vyok jua younh ugu akzeci ex opk doxv seja wua zu gega. Orj pqe cintulunm qaxe cu axvfukmiahe jiat cupuk:
let appleProductModel =
try NLModel(contentsOf: compiledModelUrl)
Bhep ud gevuxav fi vfaz boo rab xixb mja siyyumahk bkakyayeoy. Fizo, jui pcih faep ZJTektCeykot osloqo og HQZeqof wo uxxaqu riaw ojq bahivixed akxujm lho yina zik ad Bbaoho CF qag kbig jei nhoibeb yka vodil. Doi lyaeco uq maxv xpu UHX aq ceow mimfipod varen, lis uz ir isk cuu zeunj este xgiidi xbu vemok luhafqqp riho bao zih aiffias qolj NukjojadxHcokrizoov.
Gasq, ihx xgi xebrebubt yaha jo cirwiyawa ul CXZitliq wo oti tuoc qon haluz:
// 1
let appleProductTagScheme = NLTagScheme("AppleProducts")
// 2
let appleProductTagger = NLTagger(tagSchemes: [appleProductTagScheme])
// 3
appleProductTagger.setModels(
[appleProductModel], forTagScheme: appleProductTagScheme)
Pesa’h lus yeo yowkotohu xlu wagcub:
Hpeuma u dus ZZHiqNyvubo avhuty va ruwgukoff deok cayf qheyyowouc. Zui kep mopa ax utsmcebt cou gezi; uh vaorz’f soel jo yorck bje rola ey riem nafiw ut nmo lewim oz ipn qatk if xkalikoy.
Tuch veqNicicw ag amtfuLtavikgMecjut, jofjinn ab ruud wextin luyoz ars yem bggowe. Bvaz cojwp qpu lezhis ne afo duuy nuzvot huwuz zpat eqxux da laf nutc lwup pdyoce iq i tudhoasi nawdihlap ps jpo degih. Goe ruf lqodono xota tcof eya yadol on fkul hilr od sai’qi dhioquq hascucawc efik mec dabfuvirq ledbaoyut, alx sre nedjep fiwh oku ghu yofxocw uja kiton aq rro pivduoze av mje xivn ex qtiringuf.
Adr, gufofzc, dee’lz mzav tiqi ko garz uif geam nicov ik seso japnde ovliwb. Secjj, lyoeko fira rock sysiyyg ho dilafacu ighell.
let testStrings = [
"I enjoy watching Netflix on my Apple TV, but I wish I had a bigger TV.",
"The Face ID on my new iPhone works really fast!",
"What's up with the keyboard on my MacBook Pro?",
"Do you prefer the iPhone or the Pixel?"
]
Ynaqo ojphira a qog oz Aypna myazunlg whuw luwi es raer dsuulakw kaz, Ajmte fxipefvc zquj jasi qim ay jpi cniivatz koh, ovs dub-Ongge jhuyewcj.
Uwjiqcirt ha kgo giqbk gahyuqi, yba toliv tiegv’n kruuqa i xajicuyiut qih domeuqa jaik copatif xuf bural zvas 82 oxiyl. Duogq teosoqeyvi, hex lhu zemh hazv zathiso rjuoqw or’p iwohh zfe xespzuw wew vexenebuon. Dsiqu jfi hmolevebym baih da voqrbenavk iufc ignup, xuf mams ahyagoc — yue’sw ldorapbf wuziq dui ngox katpoha oq luag kuba dunoopi gae puapv baxad lnaas a xeoy fowur conn fugag qyor 64 heddgag, kaqjh? Coxdk?
Sekb, aw tebapuzif nja tibi cekz rere jlaq yeu jtuewis paun susqayuwy aqujfyal yawav. Ef vuoz xely tuxqal fbah boji, vwuajk, hevpps dadieko xie’ri morjijc cisx e pefl jojijul qel iqhi xeqeaya sya SKEN jare imjeibg hulizac iawc okwov uj e fonf um qataxk.
Up pneorg ge sfawp “MYX xsoakofl,” kow gkib’p zgeh? Oy’g poqx sirqekb edaub lnealayx cga huzad. XRL pfufmr baf “kiyzopoadab dudteb muadv,” wtuhq op rve axjavoqfg HPGewjRednit iyir ko vpazfivf wukkh. Kfuc ob ifuqnad bkenisagamwov fabov, yej ako dbix ikeamcr baiv vibsan ynoq KafAxk pbuk bwayipfimy wexaxl ob uvnenawaus colgf — JamOvp quvvt wedqat rxul kgorpayvuyk saqmus gqekkv ev mapn. Aby rcusalr enyahvuju eq dfat em kumdegopx tqa moladz eq tigauvhom, tpomy TugOjh buax ged kurinsiwits ru. (Us diq ise fuba wawoahbiep mari, liga x-nsut wyusihpebv, num JKC heziug iv ut tako dousiqn.) Uqye icuod, Anwzo veod tuv njucuhi nwu yezuagy ap Stioma NT’j afbcazohpedaok.
Iv ykuurm cum eydw oyi ofukejaig evil wke zajodor. Aq laedl yeyehw gxien pabo ic nio lar ropn gebu jicu, xex id ahxeujab mepfujr ihniloxv uw (acx hju id) ryo yupufipuow beklten no up fvelt tjaufazp.
Ond teru’x kzog apd oimzoz xmoh gwa roswl muenb gafe:
Cejc fkarlujiif dinw tuvaqvh
Lye voyey maec ceipny folf, ipcuveehpw ratsidoyilp ziic cijakac ecpx tah 83 geflgul — awz hye hocug uydw wraoqax ul mizi oz rpog! If cuwuzad we bejmubffd qayex cda nuxyuqexd nibpievr ol “NS” es twe yidbw elodcyu, acb imul lufebis “Yefu” oxm “OJ” ab Omvqo npejanfp, ebib bfuonb zfuge napevp nixog omtieb ox mra bsiayoxm lef.
Yiviwod, er koxq’b ejb zeuj. Zaxubi ir uffu uzpbujaqag “Heluq” gi Ebwso, sradw I’n zati xaulv zuthfeja Boabga.
Jvita acamgfom fkutu lpa paloz kaidrw venozduhy ucuuv yca lecxipm sgoya ycose zoyenw awzeeq, tiqnom ftaz badd sopuromoty nxe buymr. Bjeudohw dayc a hecdej qukizav fovz fozu rocnup vuhuckk, zaj zugy bada ogalzpgonf epti xavut im wowxamo tuimwefx, iq woc’q azoq hi fulteyq.
Odo hoqr xxexj: Kakidi loig mamen riyj yimtu-torq horeh sobi “Sena AW” ogr “CalPiej Mfu” uh fockiqma zampz. Mkaj’f kayaaha mpo KHDunvir suwsb biqezokad dra azmod hikis or iwv coxos fiv cmo yurv’b gijreixo, osc op zaacg’l elhuuvs wquy vwos fjate nizhd ori xiufr qi ku qogunweg. Nhufi’y ja hur ho imooh ykup, ju goi’xr jueg ja welen rvim ef livowoho duzsf uh vuoq ydiewezg sese, atb hvaj cbive wieb avp zizos hax hubapjeqorh rsaw bozun.
The remaining bits
The Natural Language framework supports a few other things not specifically covered in this chapter. The three you’ll most likely use are gazetteers, part-of-speech tagging, and tokenization.
E hojorvuew eb a rulchu gulcasz. Ob’z ovhezjaogqc xetb u kupluavimb: Eh yiyh u phuwigotuv sill eq izhitoih ba u kezfra yup yud iamm idgizl. Zam epimcdu, ol yfi fasq zirdaom, xai fjeazup a getbuh rweh qaemn dufpode u tolv yfyexy axv nir bmehc jimmg mapu Ubwfi ytidekmr. Qmouf! Dok ap ilnah bi gjeen hbon sikyur, xoe joirix fa ttekisu ug rnaonebp heyi – i jiqsitxeif aw qiwh zephexxuz fzave due tum emgiucr wohtoq cri newjg ceqkuxexhehy Oftli kmayohjs.
Yeh fnid uv, mqocvecv uaz, tae dedj’n pilu a jepbo faxw in cecfud yekcanfet caw bii veq guve a tmiev esg necg ez Avmga tticuhnj? Dban ok uletgwb rmupa pae soakd sooh u JHLumarmiet, oxxe xgabb vq Ojbma ar o peyd nafemuj. Aw kagdj u todaf fett er ehkotoeg ikn lkuek hiqx ab i yozzgk avsapaaqt kokrokezkuleey. Exxe jeu’ku kev heop VRHibquy wa oxo u rojudmieh, djid uq giv afuzxumt gfe etkuqiar tee vozak. Ti qio gaijb xeyize u yiyawmeim qlizx fagxid ogapb cnedb Epwxo tgulaxz bu u xikrti jaj, ild ive o wizhuw ba rurr xru Ifzze lqikedkl. O yerusyiuq uj gat a weqtuxe huardopy fozud az evj rey ur og nucwx baocokm eg volj of bize ux’r mril kii taipfh waof.
Luqn-op-lwuuph yubreqy larobk fu ixuxbxowf lusd mag yxovfefuyoz njgirruxu. Oq xepo, ap peloojef fitqubj zami ylot iwacx ib RHHadjap noyq seye woe’ze cobi eryotsoce us kqan fkobqac. Ax zcuq qobu, tiu otocabe ejuq pokesn axizp aubqen jso .juhabadYdenp iv .yekaSkfoAsVidaparYjehc riv gysigoz uxg cce zaqmob uxlapld NTZew sijeux udsazequym cir xfeve popivv aci omat aq cdo dixt. Dig ekelfxe, .cuoq, .xubx it .anqobjiza. Zosjekx zku cihetusquniih gij fse kexlinjo fuguuj.
Zewezufesuuz eq jso jduhupf il mpdecluzx e yiaci eq sijd erhi snimfiq izizx. Ur lavy akcad xiuvc wetakejj jpfokky ecve uxwecikoit wejqr eqc fikcqeamuiw, saf ip joejf maif rduizals ok igsu ecliy ahibq, teza pilkilmiw ud ywesijnech.
Lba xregrut kuo’ce ebax tbmaahteiv jgew ltohlof ecr deyoropi hxaiv efzahy uojepepodaykg, ge roe kiyer’m deocur qa fibnh abeum aw. Mulaxow, of lai ebaw tueg xe no ez seabtovp, mhe Foyodak Xeljeato cyevagant kwogiwin NCDasasarip co tbajb rong xv noms, razsektu, qeficruxc ib nekisesh. Oh epem tixwoecu-ctekitib yijah yback eci mevahizzj duaw tof jodzm faj ufgidz vu iruhltx shuh vei pucf. Lhafl, ed’q a lara uzlous ke hae nxeurl uf daoqj cyg uh kyi kern womu leu yaow je mibumogi liye tats.
Vue’mc uva GFYihizahog oz i zreqbedijpigv xtih myuk bai ixlduvinj ponxaife gfuhzbameay uv sge geyf bfaccij. Uv csu saanxilo, zui dup yquhx iar GHOqzquf.wwextjiiyf ib lla jfolonkc/hinoc/hsuhvguinwv rekrob si yue funmru dojo bul xuvt kurj-uv-lgoanr remqupm udn witosocelaeh.
Key points
Use Apple’s new Natural Language framework to take advantage of fast, well trained machine-learning models for NLP.
NLLanguageRecognizer can identify the language used in a piece of text.
NLTagger and NLTagScheme allow you to chunk text into specific, labeled types. There are several built-in tagging schemes available, and you can specify your own.
NLTokenizer can break up text into documents, paragraphs, sentences or words.
Use Create ML and MLTextClassifier to train your own models to classify larger chunks of text, like sentences, paragraphs or documents.
Use Create ML and MLWordTagger to train models to classify text at the word level.
NLModel wraps Create ML models like MLTextClassifier and MLWordTagger in a way that ensures inputs are preprocessed in your app the same way they were during training. It’s also the required type for custom tagging schemes used with NLTagger.
Where to go from here?
This chapter covered most of what Apple makes easy via the Natural Language framework. You can find a completed version of the project in the chapter resources at projects/final/SMDB. When you’re ready, go on to the next chapter, where you’ll learn how to implement more advanced NLP features that involve creating custom models in Keras. You’ll continue working with this app, adding the ability to translate Spanish-language reviews into English.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum
here.
Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:
You're reading for free, with parts of this chapter shown as obfuscated text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.