Luonnollisen kielen käsittelystä - tekniikasta, jonka avulla ohjelmistosovellukset pystyvät käsittelemään ihmiskielen - on tullut jonkin verran kaikkialla viime vuosina.
Google-haku pystyy vastaamaan luonnollisesti kuulostaviin kysymyksiin. Applen Siri pystyy ymmärtämään monenlaisia kysymyksiä, minkä vuoksi monet yritykset käyttävät (kohtuullisia) älypuhelimia ja bottipuhelimia kommunikoimaan asiakkaiden kanssa. Mutta miten tämä näennäisesti 'älykäs' ohjelmisto todella toimii?
Tässä artikkelissa opit tekniikasta, joka ohjaa näitä sovelluksia, sekä opit kehittämään luonnollisen kielen käsittelyohjelmiston itse.
Artikkelissa käydään läpi esimerkki uutisarvoisesta analysaattorin rakennusprosessista. Kuvittele, että sinulla on arvopaperisalkku ja haluat sovelluksen, joka käy automaattisesti läpi suosittujen uutisverkkosivustojen ja tunnistaa artikkelit, jotka liittyvät salkkuusi. Jos esimerkiksi osakekannassasi on yrityksiä, kuten Microsoft, BlackStone ja Luxottica, sinun tulisi olla tietoinen artikkeleista, joissa mainitaan nämä kolme yritystä.
Luonnolliset kielenkäsittelysovellukset, kuten kaikki muut koneoppimissovellukset, rakennetaan suhteellisen pienten, yksinkertaisten ja intuitiivisten algoritmien pohjalle, jotka toimivat yhdessä. Usein on järkevämpää käyttää ulkoista kirjastoa, jossa kaikki nämä algoritmit on jo toteutettu ja integroitu.
Esimerkiksi aiomme käyttää Stanfordin NLP-kirjasto , tehokas Java-pohjainen luonnollisen kielen prosessointikirjasto, tukee useita kieliä.
Yksi erityinen algoritmi, joka kiinnostaa meitä tässä kirjastossa, on kieliopin koodaus. Kieliopin koodausta käytetään puheosien automaattiseen määrittämiseen jokaiselle tekstin pala sanalle. Tämä kieliopillinen merkintä luokittelee sanat tekstiin leksikaalisten ominaisuuksien perusteella ja analysoi niitä suhteessa muihin ympäröiviin sanoihin.
Kieliopin koodausalgoritmin tarkka mekaniikka on tämän artikkelin ulkopuolella, mutta voit oppia siitä. tässä .
Aluksi aiomme luoda uuden Java-projektin (voit käyttää interaktiivista kehitysympäristöäsi TÄSSÄ ) ja lisää Stanfordin NLP-kirjasto riippuvuusluetteloon. Jos käytät Mavenia, lisää se vain pom.xml
:
edu.stanford.nlp stanford-corenlp 3.6.0 edu.stanford.nlp stanford-corenlp 3.6.0 models
Koska sovelluksen on purettava artikkelin sisältö automaattisesti verkkosivulta, sinun on määritettävä myös seuraavat kaksi riippuvuutta:
de.l3s.boilerpipe boilerpipe 1.1.0
net.sourceforge.nekohtml nekohtml 1.9.22
Lisäämällä nämä riippuvuudet olet valmis siirtymään:
Analysaattorimme ensimmäinen osa koskee artikkeleiden ottamista ja niiden sisällön noutamista verkkosivuilta.
Kun otamme artikkeleita uutislähteistä, sivut ovat yleensä täynnä epäolennaisia tietoja (upotetut videot, lähtevät linkit, videot, mainonta jne.), Jolla ei ole merkitystä itse artikkelille. Täällä Kattilaputki on huomattava.
Kattilaputki on erittäin tärkeä ja tehokas algoritmi artikkelin pääsisällön tunnistavan 'sekaan' poistamiseksi analysoimalla erilaisia sisältölohkoja käyttämällä ominaisuuksia, kuten keskimääräinen lauseen pituus, sisältölohkoissa käytetyt tunnistetyypit ja sisällön tiheys. - algoritmi kattilaputki se on osoittanut pystyvänsä kilpailemaan muiden laskennallisesti kalliimpien algoritmien kanssa, kuten konenäön perusteella. Voit oppia lisää projektisi verkkosivustolta .
Rovaniemen kirjasto kattilaputki mukana tulee asennettu tuki verkkosivujen raapimiselle. Voit hakea HTML-koodin verkosta, poimia tekstiä HTML-koodista ja puhdistaa puretun tekstin. Voit määrittää funktion extractFromURL
, joka vie URL-osoitteen ja käyttää sitä Kattilaputki palauttaa osuvin teksti merkkijonona käyttämällä ArticleExtractor
Tätä tehtävää varten:
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); } }
Kirjasto kattilaputki tarjoaa kattilanputkialgoritmiin perustuvia erottimia ArticleExtractor
: lla optimoidaan erityisesti HTML-muotoisiksi uutisartikkeleiksi. ArticleExtractor
keskittyy kussakin sisältölohkossa käytettäviin HTML-tunnisteisiin ja lähtevien linkkien tiheyteen. Tämä sopii paremmin tehtäväämme kuin nopeampi, mutta helpompi DefaultExtractor
Lisätyt toiminnot hoitavat kaiken puolestamme:
HTMLFetcher.fetch
Tartu HTML-asiakirjaangetTextDocument
pura tekstiasiakirjaCommonExtractors.ARTICLE_EXTRACTOR.getText
poimia asiaankuuluva teksti artikkelista algoritmilla kattilaputki Nyt voit kokeilla sitä esimerkkiartikkelilla, joka liittyy optisten jättiläisten Essilorin ja Luxottican fuusioihin, jonka löydät tässä . Voit lisätä tämän URL-osoitteen funktioon ja nähdä tuloksen.
Lisää seuraava koodi päätoimintoon:
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); } }
Sinun pitäisi nähdä lähtötiedot artikkelin pääosassa ilman mainontaa, HTML-tunnisteita ja lähteviä linkkejä. Tässä on pieni osa siitä, mitä sain aloittaessani sen:
MILAN/PARIS Luxottica de Italia (LUX.MI) y Essilor de Francia (ESSI.PA) han llegado a un acuerdo de una fusión de 46 billones de euros (49 billones de dólares) para crear *global eyewear powerhouse* con ingresos anuales de más de 15 billones de euros. El acuerdo de todo tipo de acciones es uno de los mayores vínculos transfronterizos de Europa y une a Luxottica, el mayor creador de lentes del mundo con marcas como Ray-Ban y Oakley, con el fabricante de lentes líder Essilor. 'Finalmente... dos productos que naturalmente se complementan – es decir monturas y lentes – serán diseñados, manufacturados y distribuidos bajo el mismo techo,' Leonardo Del Vecchio, fundador de Luxottica de 81 años, dijo en un comunicado el lunes. Las acciones en Luxottica subieron un 8.6 por ciento a 53.80 euros a las 1405 GMT (9:05 a.m. ET), con Essilor arriba un 12.2 por ciento a 114.60 euros. La fusión entre estos jugadores tan importantes en el mercado de lentes de 95 billones, se enfoca en ayudar a los negocios a aprovechar la demanda tan fuerte que se espera para lentes de prescripción y lentes de sol, debido a una población global que envejece y una toma de conciencia mayor con respecto al cuidado de los ojos. Los analistas Jefferies estiman que el mercado está creciendo entre…
Ja se on pääartikkelin runko. On vaikea kuvitella, että tätä on helpompi toteuttaa.
Nyt kun olet purkanut artikkelin rungon onnistuneesti, voit keskittyä selvittämään, mainitaanko artikkelissa käyttäjiä kiinnostavia yrityksiä.
Saatat olla houkutus tehdä vain merkkijono tai hakea regexiä, mutta tällä lähestymistavalla on useita haittoja.
Ensinnäkin merkkijonohaku voi altistua väärille positiivisille. Artikkeli, jossa mainitaan Microsoft Excel, voidaan merkitä ikään kuin siinä mainitaan esimerkiksi Microsoft.
Toiseksi, säännöllisen lausekkeen rakentamisesta riippuen säännöllisen lausekkeen haku voi johtaa vääriin negatiivisiin. Esimerkiksi artikkeli, joka sisältää lauseen 'Luxottican neljännesvuositulot ylittivät odotukset', voi kadota säännöllisen lausekkeen haulla, joka löytää sanan 'Luxottica' valkoisten tilojen ympäröimänä.
Lopuksi, jos olet kiinnostunut suuresta joukosta yrityksiä ja käsittelet suurta määrää artikkeleita, jokaisen yrityksen etsiminen käyttäjän salkusta koko tekstin pääosassa voi johtaa heikkoon suorituskykyyn ja samalla vievään pitkään aika.
Stanfordin CoreNLP-kirjasto sillä on monia vahvoja piirteitä ja se tarjoaa tavan ratkaista nämä kolme ongelmaa.
Parserissamme aiomme käyttää kieliopin koodausta. Voimme erityisesti käyttää sitä etsimään kaikki artikkelin oikeat nimet ja vertailla niitä mielenkiintoisten osakkeiden valikoimastamme.
Sisällyttämällä NLP-tekniikkaa emme vain paranna tarraimeemme tarkkuutta ja minimoimme edellä mainitut vääriä positiivisia ja negatiivisia asioita, mutta myös minimoimme dramaattisesti tekstimäärän, jota meidän on verrattava varastosalkkuun, koska oikeat nimet vaarantavat vain pienen artikkelin koko teksti.
Käsittelemällä artikkelimme ennakkoon tietorakenteessa, jolla on alhaiset jäsenyysneuvottelujen kustannukset , voimme vähentää huomattavasti kohteen analysointiin kuluvaa aikaa.
Stanfordin CoreNLP tarjoaa erittäin kätevän taggerin, jota kutsutaan MaxentTagger joka voi tarjota kieliopin merkinnät muutamalla rivillä koodia.
Tässä on yksinkertainen toteutus:
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); }
Tagger-toiminto tagPos
ottaa merkkijonon syötteeksi ja antaa merkkijonon, joka sisältää alkuperäisen merkkijonon sanat vastaavan puheen osan kanssa. Instantoi päätoiminnossasi PortfolioNewsAnalyzer
ja tuottaa kaavin tagger-toimintoon ja sinun pitäisi pystyä näkemään jotain tällaista:
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...
Tähän mennessä olemme rakentaneet toimintoja uutisartikkelin lataamiseen, puhdistamiseen ja merkitsemiseen. Mutta meidän on vielä selvitettävä, mainitaanko artikkelissa käyttäjiä kiinnostavia yrityksiä.
Tätä varten meidän on kerättävä kaikki oikeat nimet ja tarkistettava, kuuluvatko jotkut salkussamme olevat osakkeet niihin oikeisiin nimiin.
Kaikkien oikeiden nimien löytämiseksi meidän on ensin erotettava merkitty tulostusmerkkijono tunnisteiksi (käyttäen välilyöntejä erottimina), sitten erotettava jokainen tunniste alaviivasta (_
) ja tarkistettava, onko puheen osa oikea nimi.
Kun meillä on kaikki oikeat nimet, meidän tulisi tallentaa ne tietorakenteeseen, joka on paremmin optimoitu tarkoituksellemme. Esimerkissä aiomme käyttää HashSet
. Kompromissina päällekkäisten merkintöjen kieltämisestä ja merkintäjärjestyksen seuraamatta jättämisestä HashSet
mahdollistaa erittäin nopeat jäsenyyskyselyt. Koska olemme kiinnostuneita vain jäsenyyden hakemisesta, HashSet
se on täydellinen tarkoituksiimme.
Alla on funktio, joka toteuttaa oikean nimen erottamisen ja tallentamisen. Sijoita tämä funktio luokkaasi PortfolioNewsAnalyzer
:
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; }
Tässä toteutuksessa on kuitenkin ongelma. Jos yrityksen nimi koostuu useista sanoista (esim. Carl Zeiss Luxottica-esimerkissä), tämä toteutus ei pysty saamaan sitä kiinni. Carl Zeiss -esimerkissä 'Carl' ja 'Zeiss' lisätään sarjaan erikseen, joten ne eivät koskaan sisällä ainutlaatuista merkkijonoa 'Carl Zeiss'.
Tämän ongelman ratkaisemiseksi voimme kerätä kaikki oikeat nimet rivissä ja liittää ne välilyönneillä. Tässä on päivitetty toteutus, jolla tämä saavutetaan:
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; }
Nyt funktion pitäisi palauttaa joukko, jolla on yksittäiset oikeat nimet Y peräkkäiset oikeat nimet (esim. liitetty välilyönneillä). Jos tulostat propNounSet
, sinun pitäisi nähdä jotain seuraavista:
[... 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, ...]
Olemme melkein valmista!
Edellisissä osioissa rakensimme a kaavin joka voi ladata ja purkaa artikkelin rungon, taggerin, joka voi jäsentää artikkelin rungon ja tunnistaa oikeat nimet, sekä renderöijän, joka ottaa koodatun tuloksen ja kerää oikeat nimet HashSet
Nyt tehtävänä on vielä ottaa HashSet
ja vertaa sitä meitä kiinnostavien yritysten luetteloon.
Toteutus on hyvin yksinkertaista. Lisää seuraava koodi luokkaasi PortfolioNewsAnalyzer
:
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); }
Nyt voimme suorittaa koko sovelluksen - kaapimalla, puhdistamalla, merkitsemällä, keräämällä ja vertaamalla. Tässä on toiminto, joka toimii koko sovelluksessa. Lisää tämä funktio luokkaasi PortfolioNewsAnalyzer
:
public boolean analyzeArticle(String urlString) throws IOException, SAXException, BoilerpipeProcessingException { String articleText = extractFromUrl(urlString); String tagged = tagPos(articleText); HashSet properNounsSet = extractProperNouns(tagged); return arePortfolioCompaniesMentioned(properNounsSet); }
Lopuksi voimme käyttää sovellusta!
Tässä on esimerkki käyttäen samaa artikkelia yllä ja Luxotticaa kuin kohdeyritys:
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'); } }
Suorita tämä ja sovelluksen tulisi tulostaa 'Artikkelissa mainitaan kohdeyritykset'.
Vaihda Luxottican kohdeyritys yhtiöksi, jota ei mainita artikkelissa (kuten 'Microsoft'), ja sovelluksen tulisi tulostaa 'Artikkelissa ei mainita kohdeyrityksiä'.
Tässä artikkelissa käymme läpi sellaisen sovelluksen rakentamisen, joka lataa artikkelin URL-osoitteesta ja puhdistaa sen Kattilaputki , käsittelee sen Stanfordin NLP: n avulla ja tarkistaa, aiheuttaako artikkeli erityisiä viitteitä (tapauksessamme salkkuamme kuuluvat yritykset). Kuten on jo osoitettu, tämän tekniikkamatriisin hallinta tekee muuten pelottavan tehtävän, joka on suhteellisen yksinkertainen tehtävä.
Toivon, että tämä artikkeli on opettanut sinulle hyödyllisiä käsitteitä ja tekniikoita luonnollisen kielen prosessoinnissa ja innoittanut sinua kirjoittamaan luonnollisen kielen sovelluksia itse.
[Huomaa: Löydät kopion koodista, johon tässä artikkelissa viitataan tässä .