Cara Membangun Aplikasi Pemrosesan Bahasa Alami
Diterbitkan: 2022-03-11Pemrosesan bahasa alami—sebuah teknologi yang memungkinkan aplikasi perangkat lunak untuk memproses bahasa manusia—telah menjadi cukup umum selama beberapa tahun terakhir.
Pencarian Google semakin mampu menjawab pertanyaan yang terdengar alami, Siri Apple mampu memahami berbagai pertanyaan, dan semakin banyak perusahaan yang menggunakan (cukup) obrolan cerdas dan bot telepon untuk berkomunikasi dengan pelanggan. Tetapi bagaimana perangkat lunak yang tampaknya "pintar" ini benar-benar berfungsi?
Dalam artikel ini, Anda akan belajar tentang teknologi yang membuat aplikasi ini tergerak, dan Anda akan belajar bagaimana mengembangkan perangkat lunak pemrosesan bahasa alami Anda sendiri.
Artikel ini akan memandu Anda melalui contoh proses membangun penganalisis relevansi berita. Bayangkan Anda memiliki portofolio saham, dan Anda ingin aplikasi merayapi situs web berita populer secara otomatis dan mengidentifikasi artikel yang relevan dengan portofolio Anda. Misalnya, jika portofolio saham Anda mencakup perusahaan seperti Microsoft, BlackStone, dan Luxottica, Anda pasti ingin melihat artikel yang menyebutkan ketiga perusahaan ini.
Memulai dengan Perpustakaan NLP Stanford
Aplikasi pemrosesan bahasa alami, seperti aplikasi pembelajaran mesin lainnya, dibangun di atas sejumlah algoritme yang relatif kecil, sederhana, dan intuitif yang bekerja bersama-sama. Seringkali masuk akal untuk menggunakan perpustakaan eksternal di mana semua algoritma ini sudah diterapkan dan terintegrasi.
Untuk contoh kami, kami akan menggunakan perpustakaan Stanford NLP, perpustakaan pemrosesan bahasa alami berbasis Java yang kuat yang dilengkapi dengan dukungan untuk banyak bahasa.
Salah satu algoritme tertentu dari perpustakaan ini yang kami minati adalah tagger part-of-speech (POS). Sebuah tagger POS digunakan untuk secara otomatis menetapkan bagian dari pidato untuk setiap kata dalam sepotong teks. Tagger POS ini mengklasifikasikan kata dalam teks berdasarkan fitur leksikal dan menganalisisnya dalam kaitannya dengan kata lain di sekitarnya.
Mekanisme yang tepat dari algoritme penanda POS berada di luar cakupan artikel ini, tetapi Anda dapat mempelajarinya lebih lanjut di sini.
Untuk memulai, kami akan membuat proyek Java baru (Anda dapat menggunakan IDE favorit Anda) dan menambahkan perpustakaan Stanford NLP ke daftar dependensi. Jika Anda menggunakan Maven, cukup tambahkan ke file pom.xml
Anda:
<dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.6.0</version> </dependency> <dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.6.0</version> <classifier>models</classifier> </dependency>
Karena aplikasi perlu mengekstrak konten artikel secara otomatis dari halaman web, Anda juga perlu menentukan dua dependensi berikut:
<dependency> <groupId>de.l3s.boilerpipe</groupId> <artifactId>boilerpipe</artifactId> <version>1.1.0</version> </dependency>
<dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.22</version> </dependency>
Dengan dependensi ini ditambahkan, Anda siap untuk bergerak maju.
Menggores dan Membersihkan Artikel
Bagian pertama dari penganalisa kami akan melibatkan pengambilan artikel dan mengekstrak kontennya dari halaman web.
Saat mengambil artikel dari sumber berita, halaman biasanya dipenuhi dengan informasi asing (video tersemat, tautan keluar, video, iklan, dll.) yang tidak relevan dengan artikel itu sendiri. Di sinilah Boilerpipe berperan.
Boilerpipe adalah algoritme yang sangat kuat dan efisien untuk menghilangkan "kekacauan" yang mengidentifikasi konten utama artikel berita dengan menganalisis blok konten yang berbeda menggunakan fitur seperti panjang kalimat rata-rata, jenis tag yang digunakan dalam blok konten, dan kepadatan tautan. Algoritme boilerpipe telah terbukti dapat bersaing dengan algoritme lain yang jauh lebih mahal secara komputasi, seperti yang didasarkan pada visi mesin. Anda dapat mempelajari lebih lanjut di situs proyeknya.
Pustaka Boilerpipe dilengkapi dengan dukungan bawaan untuk menggores halaman web. Itu dapat mengambil HTML dari web, mengekstrak teks dari HTML, dan membersihkan teks yang diekstraksi. Anda dapat menentukan fungsi, extractFromURL
, yang akan mengambil URL dan menggunakan Boilerpipe untuk mengembalikan teks yang paling relevan sebagai string menggunakan ArticleExtractor
untuk tugas ini:
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); } }
Pustaka Boilerpipe menyediakan ekstraktor berbeda berdasarkan algoritme boilerpipe, dengan ArticleExtractor
dioptimalkan secara khusus untuk artikel berita berformat HTML. ArticleExtractor
berfokus secara khusus pada tag HTML yang digunakan di setiap blok konten dan kepadatan tautan keluar. Ini lebih cocok untuk tugas kita daripada DefaultExtractor
yang lebih cepat tetapi lebih sederhana.
Fungsi bawaan mengurus semuanya untuk kami:
-
HTMLFetcher.fetch
mendapatkan dokumen HTML -
getTextDocument
mengekstrak dokumen teks -
CommonExtractors.ARTICLE_EXTRACTOR.getText
mengekstrak teks yang relevan dari artikel menggunakan algoritma boilerpipe
Sekarang Anda dapat mencobanya dengan contoh artikel tentang penggabungan raksasa optik Essilor dan Luxottica, yang dapat Anda temukan di sini. Anda dapat memasukkan URL ini ke fungsi tersebut dan melihat apa yang keluar.
Tambahkan kode berikut ke fungsi utama Anda:
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-ma-luxottica-group-idUSKBN14Z110"; String text = BoilerPipeExtractor.extractFromUrl(urlString); System.out.println(text); } }
Anda akan melihat output Anda di badan utama artikel, tanpa iklan, tag HTML, dan tautan keluar. Ini adalah cuplikan awal dari apa yang saya dapatkan ketika saya menjalankan ini:
MILAN/PARIS Italy's Luxottica (LUX.MI) and France's Essilor (ESSI.PA) have agreed a 46 billion euro ($49 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 am 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...
Dan itu memang badan artikel utama artikel. Sulit membayangkan ini menjadi lebih sederhana untuk diterapkan.
Menandai Bagian Pidato
Sekarang setelah Anda berhasil mengekstrak badan artikel utama, Anda dapat bekerja untuk menentukan apakah artikel tersebut menyebutkan perusahaan yang menarik bagi pengguna.
Anda mungkin tergoda untuk hanya melakukan pencarian string atau ekspresi reguler, tetapi ada beberapa kelemahan dari pendekatan ini.
Pertama-tama, pencarian string mungkin rentan terhadap kesalahan positif. Sebuah artikel yang menyebutkan Microsoft Excel dapat ditandai sebagai menyebutkan Microsoft, misalnya.
Kedua, bergantung pada konstruksi ekspresi reguler, pencarian ekspresi reguler dapat menghasilkan negatif palsu. Misalnya, artikel yang berisi frasa "Penghasilan kuartalan Luxottica melebihi ekspektasi" mungkin terlewatkan oleh penelusuran ekspresi reguler yang menelusuri "Luxottica" yang dikelilingi spasi.
Terakhir, jika Anda tertarik pada sejumlah besar perusahaan dan sedang memproses sejumlah besar artikel, menelusuri seluruh isi teks untuk setiap perusahaan dalam portofolio pengguna mungkin terbukti sangat memakan waktu, menghasilkan kinerja yang tidak dapat diterima.
Pustaka CoreNLP Stanford memiliki banyak fitur canggih dan menyediakan cara untuk menyelesaikan ketiga masalah ini.
Untuk penganalisis kami, kami akan menggunakan penanda Parts-of-Speech (POS). Secara khusus, kita dapat menggunakan penanda POS untuk menemukan semua kata benda yang tepat dalam artikel dan membandingkannya dengan portofolio saham menarik kita.
Dengan menggabungkan teknologi NLP, kami tidak hanya meningkatkan akurasi penanda kami dan meminimalkan positif dan negatif palsu yang disebutkan di atas, tetapi kami juga secara dramatis meminimalkan jumlah teks yang kami perlukan untuk dibandingkan dengan portofolio saham kami, karena kata benda yang tepat hanya terdiri dari sebagian kecil. dari teks lengkap artikel.

Dengan pra-pemrosesan portofolio kami menjadi struktur data yang memiliki biaya kueri keanggotaan yang rendah, kami dapat secara dramatis mengurangi waktu yang dibutuhkan untuk menganalisis sebuah artikel.
Stanford CoreNLP menyediakan penanda yang sangat nyaman yang disebut MaxentTagger yang dapat menyediakan Penandaan POS hanya dalam beberapa baris kode.
Berikut ini adalah implementasi sederhana:
public class PortfolioNewsAnalyzer { private HashSet<String> 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); }
Fungsi penanda, tagPos
, mengambil string sebagai input dan mengeluarkan string yang berisi kata-kata dalam string asli bersama dengan bagian ucapan yang sesuai. Di fungsi utama Anda, buat instance PortfolioNewsAnalyzer
dan masukkan output scraper ke dalam fungsi tagger dan Anda akan melihat sesuatu seperti ini:
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 am_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...
Memproses Output Tagged menjadi Set
Sejauh ini, kami telah membangun fungsi untuk mengunduh, membersihkan, dan menandai artikel berita. Tetapi kita masih perlu menentukan apakah artikel tersebut menyebutkan salah satu perusahaan yang menarik bagi pengguna.
Untuk melakukan ini, kita perlu mengumpulkan semua kata benda yang tepat dan memeriksa apakah saham dari portofolio kita termasuk dalam kata benda yang tepat itu.
Untuk menemukan semua kata benda yang tepat, pertama-tama kita ingin membagi output string yang ditandai menjadi token (menggunakan spasi sebagai pembatas), kemudian membagi setiap token pada garis bawah ( _
) dan memeriksa apakah bagian ucapan adalah kata benda yang tepat .
Setelah kita memiliki semua kata benda yang tepat, kita akan ingin menyimpannya dalam struktur data yang lebih dioptimalkan untuk tujuan kita. Untuk contoh kita, kita akan menggunakan HashSet
. Sebagai imbalan untuk melarang entri duplikat dan tidak melacak urutan entri, HashSet
memungkinkan kueri keanggotaan yang sangat cepat. Karena kami hanya tertarik untuk menanyakan keanggotaan, HashSet
sangat cocok untuk tujuan kami.
Di bawah ini adalah fungsi yang mengimplementasikan pemisahan dan penyimpanan kata benda yang tepat. Tempatkan fungsi ini di kelas PortfolioNewsAnalyzer
Anda:
public static HashSet<String> extractProperNouns(String taggedOutput) { HashSet<String> propNounSet = new HashSet<String>(); String[] split = taggedOutput.split(" "); for (String token: split ){ String[] splitTokens = token.split("_"); if(splitTokesn[1].equals("NNP")){ propNounSet.add(splitTokens[0]); } } return propNounSet; }
Namun ada masalah dengan implementasi ini. Jika nama perusahaan terdiri dari beberapa kata, (misalnya, Carl Zeiss dalam contoh Luxottica) implementasi ini tidak akan dapat menangkapnya. Dalam contoh Carl Zeiss, "Carl" dan "Zeiss" akan dimasukkan ke dalam himpunan secara terpisah, dan karena itu tidak akan pernah berisi string tunggal "Carl Zeiss."
Untuk mengatasi masalah ini, kita dapat mengumpulkan semua kata benda tepat yang berurutan dan menggabungkannya dengan spasi. Berikut adalah implementasi yang diperbarui yang menyelesaikan ini:
public static HashSet<String> extractProperNouns(String taggedOutput) { HashSet<String> propNounSet = new HashSet<String>(); String[] split = taggedOutput.split(" "); List<String> propNounList = new ArrayList<String>(); 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; }
Sekarang fungsi tersebut harus mengembalikan satu set dengan masing-masing kata benda dan kata benda yang berurutan (yaitu, digabungkan dengan spasi). Jika Anda mencetak propNounSet
, Anda akan melihat sesuatu seperti berikut:
[... 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, ...]
Membandingkan Portofolio dengan PropNouns Set
Kami hampir selesai!
Di bagian sebelumnya, kami membuat scraper yang dapat mengunduh dan mengekstrak isi artikel, tagger yang dapat mengurai isi artikel dan mengidentifikasi kata benda yang tepat, dan prosesor yang mengambil output yang ditandai dan mengumpulkan kata benda yang tepat ke dalam HashSet
. Sekarang yang tersisa untuk dilakukan adalah mengambil HashSet
dan membandingkannya dengan daftar perusahaan yang kami minati.
Implementasinya sangat sederhana. Tambahkan kode berikut di kelas PortfolioNewsAnalyzer
Anda:
private HashSet<String> portfolio; public PortfolioNewsAnalyzer() { portfolio = new HashSet<String>(); } public void addPortfolioCompany(String company) { portfolio.add(company); } public boolean arePortfolioCompaniesMentioned(HashSet<String> articleProperNouns){ return !Collections.disjoint(articleProperNouns, portfolio); }
Menyatukan Semuanya
Sekarang kita dapat menjalankan seluruh aplikasi—pengikisan, pembersihan, penandaan, pengumpulan, dan perbandingan. Berikut adalah fungsi yang berjalan melalui seluruh aplikasi. Tambahkan fungsi ini ke kelas PortfolioNewsAnalyzer
Anda:
public boolean analyzeArticle(String urlString) throws IOException, SAXException, BoilerpipeProcessingException { String articleText = extractFromUrl(urlString); String tagged = tagPos(articleText); HashSet<String> properNounsSet = extractProperNouns(tagged); return arePortfolioCompaniesMentioned(properNounsSet); }
Akhirnya, kita bisa menggunakan aplikasi!
Berikut adalah contoh menggunakan artikel yang sama seperti di atas dan Luxottica sebagai perusahaan portofolio:
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-ma-luxottica-group-idUSKBN14Z110"); if (mentioned) { System.out.println("Article mentions portfolio companies"); } else { System.out.println("Article does not mention portfolio companies"); } }
Jalankan ini, dan aplikasi akan mencetak "Artikel menyebutkan perusahaan portofolio."
Ubah perusahaan portofolio dari Luxottica menjadi perusahaan yang tidak disebutkan dalam artikel (seperti "Microsoft"), dan aplikasi harus mencetak "Artikel tidak menyebutkan perusahaan portofolio."
Membangun Aplikasi NLP Tidak Perlu Sulit
Dalam artikel ini, kami melangkah melalui proses membangun aplikasi yang mengunduh artikel dari URL, membersihkannya menggunakan Boilerpipe, memprosesnya menggunakan Stanford NLP, dan memeriksa apakah artikel tersebut membuat referensi tertentu yang menarik (dalam kasus kami, perusahaan di portofolio). Seperti yang ditunjukkan, memanfaatkan rangkaian teknologi ini membuat apa yang sebelumnya menjadi tugas yang menakutkan menjadi tugas yang relatif mudah.
Saya harap artikel ini memperkenalkan Anda pada konsep dan teknik yang berguna dalam pemrosesan bahasa alami dan menginspirasi Anda untuk menulis aplikasi bahasa alami Anda sendiri.
[Catatan: Anda dapat menemukan salinan kode yang dirujuk dalam artikel ini di sini.]