Natūralios kalbos apdorojimas - technologija, leidžianti programinės įrangos programoms apdoroti žmonių kalbą - per pastaruosius kelerius metus tapo gana visur.
„Google“ paieška vis labiau gali atsakyti į natūraliai skambančius klausimus, „Apple“ „Siri“ sugeba suprasti įvairiausius klausimus, o vis daugiau kompanijų naudojasi (pagrįstai) intelektualiaisiais pokalbių ir telefono robotais, kad galėtų bendrauti su klientais. Bet kaip ši iš pažiūros „protinga“ programinė įranga veikia iš tikrųjų?
Šiame straipsnyje sužinosite apie technologiją, leidžiančią pažymėti šias programas, ir sužinosite, kaip sukurti savo natūralios kalbos apdorojimo programinę įrangą.
Straipsnyje apžvelgsite naujienų aktualumo analizatoriaus kūrimo procesą. Įsivaizduokite, kad turite akcijų portfelį ir norėtumėte, kad programa automatiškai tikrintų populiarių naujienų svetaines ir nustatytų straipsnius, susijusius su jūsų portfeliu. Pvz., Jei jūsų akcijų portfelyje yra tokios įmonės kaip „Microsoft“, „BlackStone“ ir „Luxottica“, norėtumėte pamatyti straipsnius, kuriuose paminėtos šios trys įmonės.
Natūralios kalbos apdorojimo programos, kaip ir visos kitos mašininio mokymosi programos, yra sukurtos remiantis daugeliu palyginti mažų, paprastų, intuityvių algoritmų, veikiančių kartu. Dažnai prasminga naudoti išorinę biblioteką, kurioje visi šie algoritmai jau įdiegti ir integruoti.
Mūsų pavyzdyje naudosime Stanfordo NLP biblioteka , galinga „Java“ pagrindu sukurta natūralios kalbos apdorojimo biblioteka, palaikoma daugeliu kalbų.
Vienas konkretus šios bibliotekos algoritmas, kuris mus domina, yra kalbos dalies (POS) žymeklis. POS žymeklis naudojamas automatiškai priskirti kalbos dalis kiekvienam teksto fragmento žodžiui. Šis POS žymeklis klasifikuoja žodžius tekste pagal leksines ypatybes ir analizuoja juos, palyginti su kitais aplink esančiais žodžiais.
Tiksli POS žymenų algoritmo mechanika nepatenka į šio straipsnio taikymo sritį, tačiau apie tai galite sužinoti daugiau čia .
Norėdami pradėti, sukursime naują „Java“ projektą (galite naudoti savo mėgstamą IDE) ir pridėsime Stanfordo NLP biblioteką prie priklausomybių sąrašo. Jei naudojate „Maven“, tiesiog pridėkite jį prie pom.xml
failas:
„css media“ užklausos reaguoja į dizainą
edu.stanford.nlp stanford-corenlp 3.6.0 edu.stanford.nlp stanford-corenlp 3.6.0 models
Kadangi programa turės automatiškai išgauti straipsnio turinį iš tinklalapio, turėsite nurodyti šias dvi priklausomybes:
de.l3s.boilerpipe boilerpipe 1.1.0
net.sourceforge.nekohtml nekohtml 1.9.22
Pridėję šias priklausomybes, esate pasirengę judėti pirmyn.
Pirmoji analizatoriaus dalis apims straipsnių paiešką ir jų turinio iš tinklalapių ištraukimą.
Gaunant straipsnius iš naujienų šaltinių, puslapiuose dažniausiai būna pašalinė informacija (įterpti vaizdo įrašai, siunčiamos nuorodos, vaizdo įrašai, reklamos ir kt.), Kuri nėra svarbi pačiam straipsniui. Tai kur Katilo vamzdis ateina į žaidimą.
„Boilerpipe“ yra ypač patikimas ir efektyvus „netvarkos“ pašalinimo algoritmas, identifikuojantis pagrindinį naujienų straipsnio turinį analizuojant skirtingus turinio blokus, naudojant tokias funkcijas kaip vidutinio sakinio ilgis, turinio blokuose naudojamų žymių tipai ir nuorodų tankis. Įrodyta, kad katilo vamzdžio algoritmas yra konkurencingas su kitais daug skaičiavimais brangesniais algoritmais, pavyzdžiui, pagrįstais mašinos regėjimu. Čia galite sužinoti daugiau projekto vieta .
„Boilerpipe“ bibliotekoje yra įmontuota parama tinklalapių šveitimui. Jis gali parsisiųsti HTML iš interneto, ištraukti tekstą iš HTML ir išvalyti ištrauktą tekstą. Galite apibrėžti funkciją extractFromURL
, kuri imsis URL ir naudos „Boilerpipe“, kad grąžintų aktualiausią tekstą kaip eilutę naudodami ArticleExtractor
šiai užduočiai atlikti:
kaip rašyti programavimo kalbą
import java.net.URL; import de.l3s.boilerpipe.document.TextDocument; import de.l3s.boilerpipe.extractors.CommonExtractors; import de.l3s.boilerpipe.sax.BoilerpipeSAXInput; import de.l3s.boilerpipe.sax.HTMLDocument; import de.l3s.boilerpipe.sax.HTMLFetcher; public class BoilerPipeExtractor { public static String extractFromUrl(String userUrl) throws java.io.IOException, org.xml.sax.SAXException, de.l3s.boilerpipe.BoilerpipeProcessingException { final HTMLDocument htmlDoc = HTMLFetcher.fetch(new URL(userUrl)); final TextDocument doc = new BoilerpipeSAXInput(htmlDoc.toInputSource()).getTextDocument(); return CommonExtractors.ARTICLE_EXTRACTOR.getText(doc); } }
„Boilerpipe“ bibliotekoje pateikiami skirtingi ištraukėjai, pagrįsti „boilerpipe“ algoritmu, su ArticleExtractor
specialiai optimizuotas HTML formato naujienų straipsniams. ArticleExtractor
daugiausia dėmesio skiriama kiekviename turinio bloke naudojamoms HTML žymoms ir siunčiamų nuorodų tankiui. Tai geriau tinka mūsų užduočiai nei greitesnis, bet paprastesnis DefaultExtractor
Integruotos funkcijos rūpinasi viskuo mums:
HTMLFetcher.fetch
gauna HTML dokumentągetTextDocument
ištraukia tekstinį dokumentąCommonExtractors.ARTICLE_EXTRACTOR.getText
naudodamas „boilerpipe“ algoritmą ištraukia atitinkamą straipsnio tekstąDabar galite tai išbandyti pateikdami pavyzdinį straipsnį apie optinių gigantų „Essilor“ ir „Luxottica“ susijungimą, kurį galite rasti čia . Galite pridėti šį URL į funkciją ir pamatyti, kas išeina.
Prie savo pagrindinės funkcijos pridėkite šį kodą:
public class App { public static void main( String[] args ) throws java.io.IOException, org.xml.sax.SAXException, de.l3s.boilerpipe.BoilerpipeProcessingException { String urlString = 'http://www.reuters.com/article/us-essilor-m-a-luxottica-group-idUSKBN14Z110'; String text = BoilerPipeExtractor.extractFromUrl(urlString); System.out.println(text); } }
Pagrindiniame straipsnio tekste turėtumėte matyti išvestį be skelbimų, HTML žymų ir siunčiamų nuorodų. Čia yra pradinis fragmentas iš to, ką gavau, kai paleidžiau:
MILAN/PARIS Italy's Luxottica (LUX.MI) and France's Essilor (ESSI.PA) have agreed a 46 billion euro ( billion) merger to create a global eyewear powerhouse with annual revenue of more than 15 billion euros. The all-share deal is one of Europe's largest cross-border tie-ups and brings together Luxottica, the world's top spectacles maker with brands such as Ray-Ban and Oakley, with leading lens manufacturer Essilor. 'Finally ... two products which are naturally complementary -- namely frames and lenses -- will be designed, manufactured and distributed under the same roof,' Luxottica's 81-year-old founder Leonardo Del Vecchio said in a statement on Monday. Shares in Luxottica were up by 8.6 percent at 53.80 euros by 1405 GMT (9:05 a.m. ET), with Essilor up 12.2 percent at 114.60 euros. The merger between the top players in the 95 billion eyewear market is aimed at helping the businesses to take full advantage of expected strong demand for prescription spectacles and sunglasses due to an aging global population and increasing awareness about eye care. Jefferies analysts estimate that the market is growing at between...
Ir tai iš tikrųjų yra pagrindinis straipsnio straipsnis. Sunku įsivaizduoti, kad tai yra daug paprasčiau įgyvendinti.
Dabar, kai sėkmingai ištraukėte pagrindinį straipsnio turinį, galite dirbti nustatydami, ar straipsnyje minimos vartotoją dominančios įmonės.
Jums gali kilti pagunda tiesiog atlikti eilučių ar reguliarių reiškinių paiešką, tačiau yra keli šio požiūrio trūkumai.
Visų pirma, eilutės paieška gali būti klaidingai teigiama. Straipsnyje, kuriame minima „Microsoft Excel“, galima pažymėti, pavyzdžiui, „Microsoft“.
Antra, atsižvelgiant į reguliariosios išraiškos konstrukciją, reguliariosios išraiškos paieška gali sukelti klaidingus neigiamus dalykus. Pavyzdžiui, straipsnį, kuriame yra frazė „„ Luxottica “ketvirčio uždarbis viršijo lūkesčius“, gali praleisti reguliarios išraiškos paieška, kai ieškoma „Luxottica“, apjuostoje tarpais.
Galiausiai, jei jus domina daugybė kompanijų ir apdorojate daugybę straipsnių, ieškojimas per visą tekstą kiekvienos įmonės portfelio įmonės gali pasirodyti itin daug laiko atimantis, o tai nepriimtina.
Stanfordo „CoreNLP“ biblioteka turi daug galingų funkcijų ir suteikia būdą išspręsti visas šias tris problemas.
grafinio dizaino principai ir elementai
Savo analizatoriui naudosime kalbos dalių (POS) žymeklį. Visų pirma, mes galime naudoti POS žymeklį, kad surastume visus daiktavardžius straipsnyje ir palygintume juos su mūsų įdomių akcijų portfeliu.
Įtraukdami NLP technologiją, mes ne tik pageriname žymeklio tikslumą ir sumažiname klaidingus teigiamus bei neigiamus dalykus, minėtus aukščiau, bet ir dramatiškai sumažiname teksto kiekį, kurį reikia palyginti su mūsų akcijų portfeliu, nes tikriniai daiktavardžiai sudaro tik mažą pogrupį viso straipsnio teksto.
Iš anksto apdorodami mūsų portfelį į duomenų struktūrą, kuri turi maža narystės užklausos kaina , galime žymiai sutrumpinti laiką, reikalingą straipsniui analizuoti.
„Stanford CoreNLP“ teikia labai patogų žymeklį, vadinamą MaxentTagger tai gali suteikti POS žymėjimą tik keliose kodo eilutėse.
Čia yra paprastas įgyvendinimas:
public class PortfolioNewsAnalyzer { private HashSet portfolio; private static final String modelPath = 'edu\stanford\nlp\models\pos-tagger\english-left3words\english-left3words-distsim.tagger'; private MaxentTagger tagger; public PortfolioNewsAnalyzer() { tagger = new MaxentTagger(modelPath); } public String tagPos(String input) { return tagger.tagString(input); }
Žymų žymeklio funkcija tagPos
ima eilutę kaip įvestį ir pateikia eilutę, kurioje yra žodžiai originalioje eilutėje kartu su atitinkama kalbos dalimi. Vykdydami savo pagrindinę funkciją, užfiksuokite PortfolioNewsAnalyzer
ir paduokite grandiklio išvestį į žymėjimo funkciją, ir turėtumėte pamatyti kažką panašaus:
kaip veikia konvertuojamos natos
MILAN/PARIS_NN Italy_NNP 's_POS Luxottica_NNP -LRB-_-LRB- LUX.MI_NNP -RRB-_-RRB- and_CC France_NNP 's_POS Essilor_NNP -LRB-_-LRB- ESSI.PA_NNP -RRB-_-RRB- have_VBP agreed_VBN a_DT 46_CD billion_CD euro_NN -LRB-_-LRB- $_$ 49_CD billion_CD -RRB-_-RRB- merger_NN to_TO create_VB a_DT global_JJ eyewear_NN powerhouse_NN with_IN annual_JJ revenue_NN of_IN more_JJR than_IN 15_CD billion_CD euros_NNS ._. The_DT all-share_JJ deal_NN is_VBZ one_CD of_IN Europe_NNP 's_POS largest_JJS cross-border_JJ tie-ups_NNS and_CC brings_VBZ together_RB Luxottica_NNP ,_, the_DT world_NN 's_POS top_JJ spectacles_NNS maker_NN with_IN brands_NNS such_JJ as_IN Ray-Ban_NNP and_CC Oakley_NNP ,_, with_IN leading_VBG lens_NN manufacturer_NN Essilor_NNP ._. ``_`` Finally_RB ..._: two_CD products_NNS which_WDT are_VBP naturally_RB complementary_JJ --_: namely_RB frames_NNS and_CC lenses_NNS --_: will_MD be_VB designed_VBN ,_, manufactured_VBN and_CC distributed_VBN under_IN the_DT same_JJ roof_NN ,_, ''_'' Luxottica_NNP 's_POS 81-year-old_JJ founder_NN Leonardo_NNP Del_NNP Vecchio_NNP said_VBD in_IN a_DT statement_NN on_IN Monday_NNP ._. Shares_NNS in_IN Luxottica_NNP were_VBD up_RB by_IN 8.6_CD percent_NN at_IN 53.80_CD euros_NNS by_IN 1405_CD GMT_NNP -LRB-_-LRB- 9:05_CD a.m._NN ET_NNP -RRB-_-RRB- ,_, with_IN Essilor_NNP up_IN 12.2_CD percent_NN at_IN 114.60_CD euros_NNS ._. The_DT merger_NN between_IN the_DT top_JJ players_NNS in_IN the_DT 95_CD billion_CD eyewear_NN market_NN is_VBZ aimed_VBN at_IN helping_VBG the_DT businesses_NNS to_TO take_VB full_JJ advantage_NN of_IN expected_VBN strong_JJ demand_NN for_IN prescription_NN spectacles_NNS and_CC sunglasses_NNS due_JJ to_TO an_DT aging_NN global_JJ population_NN and_CC increasing_VBG awareness_NN about_IN...
Iki šiol sukūrėme naujienų straipsnio atsisiuntimo, valymo ir žymėjimo funkcijas. Bet mes vis tiek turime nustatyti, ar straipsnyje minima kokia nors vartotoją dominanti įmonė.
Norėdami tai padaryti, turime surinkti visus daiktavardžius ir patikrinti, ar mūsų portfelio atsargos yra įtrauktos į tuos tikrinius daiktavardžius.
Norėdami rasti visus tikrinius daiktavardžius, pirmiausia norėsime suskirstyti pažymėtą eilutės išvestį į žetonus (naudodami tarpus kaip skiriamuosius skirsnius), tada suskaidykite kiekvieną žetoną apatinėje brūkšnyje (_
) ir patikrinsime, ar kalbos dalis yra tikrasis daiktavardis.
Turėdami visus tikrinius daiktavardžius, norėsime juos išsaugoti duomenų struktūroje, kuri yra geriau optimizuota mūsų tikslams. Pavyzdyje naudosime HashSet
. Mainais už neleidimą dublikatų įrašų ir nesilaikyti įrašų tvarkos, HashSet
leidžia atlikti labai greitas narystės užklausas. Kadangi mus domina tik narystės užklausa, HashSet
puikiai tinka mūsų tikslams.
Žemiau pateikiama funkcija, įgyvendinanti daiktavardžių padalijimą ir saugojimą. Įdėkite šią funkciją į savo PortfolioNewsAnalyzer
klasė:
public static HashSet extractProperNouns(String taggedOutput) { HashSet propNounSet = new HashSet(); String[] split = taggedOutput.split(' '); for (String token: split ){ String[] splitTokens = token.split('_'); if(splitTokesn[1].equals('NNP')){ propNounSet.add(splitTokens[0]); } } return propNounSet; }
Vis dėlto kyla problemų dėl šio įgyvendinimo. Jei įmonės pavadinimas susideda iš kelių žodžių (pvz., Carlottas Zeissas „Luxottica“ pavyzdyje), šis įgyvendinimas negalės jo sugauti. Carl Zeiss pavyzdyje „Carl“ ir „Zeiss“ bus įterpti į rinkinį atskirai, todėl niekada nebus vienos eilutės „Carl Zeiss“.
Norėdami išspręsti šią problemą, galime surinkti visus iš eilės daiktavardžius ir sujungite juos su tarpais. Tai yra atnaujintas diegimas, kuris tai įgyvendina:
public static HashSet extractProperNouns(String taggedOutput) { HashSet propNounSet = new HashSet(); String[] split = taggedOutput.split(' '); List propNounList = new ArrayList(); for (String token: split ){ String[] splitTokens = token.split('_'); if(splitTokens[1].equals('NNP')){ propNounList.add(splitTokens[0]); } else { if (!propNounList.isEmpty()) { propNounSet.add(StringUtils.join(propNounList, ' ')); propNounList.clear(); } } } if (!propNounList.isEmpty()) { propNounSet.add(StringUtils.join(propNounList, ' ')); propNounList.clear(); } return propNounSet; }
Dabar funkcija turėtų grąžinti aibę su individualiais daiktavardžiais ir nuoseklūs daiktavardžiai (t. y. sujungiami tarpais). Jei atspausdinsite propNounSet
, turėtumėte pamatyti panašų tekstą:
[... Monday, Gianluca Semeraro, David Goodman, Delfin, North America, Luxottica, Latin America, Rossi/File Photo, Rome, Safilo Group, SFLG.MI, Friday, Valentina Za, Del Vecchio, CEO Hubert Sagnieres, Oakley, Sagnieres, Jefferies, Ray Ban, ...]
Mes beveik baigėme!
Ankstesniuose skyriuose pastatėme grandiklį, kuris gali atsisiųsti ir išgauti straipsnio turinį, žymeklį, kuris gali analizuoti straipsnio turinį ir nustatyti tikrinius daiktavardžius, ir procesorių, kuris paima pažymėtą išvestį ir renka tikrinius daiktavardžius į HashSet
. Dabar belieka paimti HashSet
ir palyginkite su mus dominančių įmonių sąrašu.
Įgyvendinimas yra labai paprastas. Pridėkite šį kodą savo PortfolioNewsAnalyzer
klasė:
private HashSet portfolio; public PortfolioNewsAnalyzer() { portfolio = new HashSet(); } public void addPortfolioCompany(String company) { portfolio.add(company); } public boolean arePortfolioCompaniesMentioned(HashSet articleProperNouns){ return !Collections.disjoint(articleProperNouns, portfolio); }
Dabar galime paleisti visą programą - kasymą, valymą, žymėjimą, rinkimą ir palyginimą. Čia yra funkcija, vykdoma visoje programoje. Pridėkite šią funkciją prie savo PortfolioNewsAnalyzer
klasė:
public boolean analyzeArticle(String urlString) throws IOException, SAXException, BoilerpipeProcessingException { String articleText = extractFromUrl(urlString); String tagged = tagPos(articleText); HashSet properNounsSet = extractProperNouns(tagged); return arePortfolioCompaniesMentioned(properNounsSet); }
Galiausiai galime naudotis programa!
Štai pavyzdys, naudojant tą patį straipsnį kaip ir aukščiau, ir „Luxottica“ kaip portfelio bendrovę:
public static void main( String[] args ) throws IOException, SAXException, BoilerpipeProcessingException { PortfolioNewsAnalyzer analyzer = new PortfolioNewsAnalyzer(); analyzer.addPortfolioCompany('Luxottica'); boolean mentioned = analyzer.analyzeArticle('http://www.reuters.com/article/us-essilor-m-a-luxottica-group-idUSKBN14Z110'); if (mentioned) { System.out.println('Article mentions portfolio companies'); } else { System.out.println('Article does not mention portfolio companies'); } }
Vykdykite tai ir programoje turėtų būti išspausdinta „Straipsnyje minimos portfelio įmonės“.
Pakeiskite portfelio bendrovę iš „Luxottica“ į kompaniją, nepaminėtą straipsnyje (pvz., „Microsoft“), ir programoje turėtų būti spausdinama „Straipsnyje neminimos portfelio įmonės“.
kam naudojamas c programavimas
Šiame straipsnyje apžvelgėme programos kūrimo procesą, kuris atsisiunčia straipsnį iš URL, valo jį naudodamas „Boilerpipe“, apdoroja naudodamas „Stanford NLP“ ir patikrina, ar straipsnyje pateikiamos konkrečios nuorodos (mūsų atveju įmonės portfelis). Kaip buvo įrodyta, pasinaudojant šia technologijų visuma, tai būtų sunki užduotis, kuri būtų gana paprasta.
Tikiuosi, kad šis straipsnis supažindino jus su naudingomis natūralios kalbos apdorojimo koncepcijomis ir metodais ir įkvėpė jus rašyti savo natūralios kalbos programas.
[Pastaba: kodo kopiją galite rasti šiame straipsnyje čia .]