中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

維基百科中的數(shù)據(jù)科學(xué):手把手教你用Python讀懂全球最大百科全書

2018-10-31    來源:raincent

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

沒人否認(rèn),維基百科是現(xiàn)代最令人驚嘆的人類發(fā)明之一。

幾年前誰能想到,匿名貢獻(xiàn)者們的義務(wù)工作竟創(chuàng)造出前所未有的巨大在線知識(shí)庫?維基百科不僅是你寫大學(xué)論文時(shí)最好的信息渠道,也是一個(gè)極其豐富的數(shù)據(jù)源。

從自然語言處理到監(jiān)督式機(jī)器學(xué)習(xí),維基百科助力了無數(shù)的數(shù)據(jù)科學(xué)項(xiàng)目。

維基百科的規(guī)模之大,可稱為世上最大的百科全書,但也因此稍讓數(shù)據(jù)工程師們感到頭疼。當(dāng)然,有合適的工具的話,數(shù)據(jù)量的規(guī)模就不是那么大的問題了。

本文將介紹“如何編程下載和解析英文版維基百科”。

在介紹過程中,我們也會(huì)提及以下幾個(gè)數(shù)據(jù)科學(xué)中重要的問題:

1、從網(wǎng)絡(luò)中搜索和編程下載數(shù)據(jù)

2、運(yùn)用Python庫解析網(wǎng)絡(luò)數(shù)據(jù)(HTML, XML, MediaWiki格式)

3、多進(jìn)程處理、并行化處理

這個(gè)項(xiàng)目最初是想要收集維基百科上所有的書籍信息,但我之后發(fā)現(xiàn)項(xiàng)目中使用的解決方法可以有更廣泛的應(yīng)用。這里提到的,以及在Jupyter Notebook里展示的技術(shù),能夠高效處理維基百科上的所有文章,同時(shí)還能擴(kuò)展到其它的網(wǎng)絡(luò)數(shù)據(jù)源中。

本文中運(yùn)用的Python代碼的筆記放在GitHub,靈感來源于Douwe Osinga超棒的《深度學(xué)習(xí)手冊》。前面提到的Jupyter Notebooks也可以免費(fèi)獲取。

GitHub鏈接:https://github.com/WillKoehrsen/wikipedia-data-science/blob/master/notebooks/Downloading%20and%20Parsing%20Wikipedia%20Articles.ipynb

免費(fèi)獲取地址:

https://github.com/DOsinga/deep_learning_cookbook

編程搜索和下載數(shù)據(jù)

任何一個(gè)數(shù)據(jù)科學(xué)項(xiàng)目第一步都是獲取數(shù)據(jù)。我們當(dāng)然可以一個(gè)個(gè)進(jìn)入維基百科頁面打包下載搜索結(jié)果,但很快就會(huì)下載受限,而且還會(huì)給維基百科的服務(wù)器造成壓力。還有一種辦法,我們通過dumps.wikimedia.org這個(gè)網(wǎng)站獲取維基百科所有數(shù)據(jù)的定期快照結(jié)果,又稱dump。

用下面這段代碼,我們可以看到數(shù)據(jù)庫的可用版本:

import requests
# Library for parsing HTML
from bs4 import BeautifulSoup
base_url = 'https://dumps.wikimedia.org/enwiki/'
index = requests.get(base_url).text
soup_index = BeautifulSoup(index, 'html.parser')
# Find the links on the page
dumps = [a['href'] for a in soup_index.find_all('a') if
a.has_attr('href')]
dumps
['../',
'20180620/',
'20180701/',
'20180720/',
'20180801/',
'20180820/',
'20180901/',
'20180920/',
'latest/']

這段代碼使用了BeautifulSoup庫來解析HTML。由于HTML是網(wǎng)頁的標(biāo)準(zhǔn)標(biāo)識(shí)語言,因此就處理網(wǎng)絡(luò)數(shù)據(jù)來說,這個(gè)庫簡直是無價(jià)瑰寶。

本項(xiàng)目使用的是2018年9月1日的dump(有些dump數(shù)據(jù)不全,請確保選擇一個(gè)你所需的數(shù)據(jù))。我們使用下列代碼來找到dump里所有的文件。

dump_url = base_url + '20180901/'
# Retrieve the html
dump_html = requests.get(dump_url).text
# Convert to a soup
soup_dump = BeautifulSoup(dump_html, 'html.parser')
# Find list elements with the class file
soup_dump.find_all('li', {'class': 'file'})[:3]
[<li><a href="/enwiki/20180901/enwiki-20180901-pages-articles-multistream.xml.bz2">enwiki-20180901-pages-articles-multistream.xml.bz2</a> 15.2 GB</li>,
<li><a href="/enwiki/20180901/enwiki-20180901-pages-articles-multistream-index.txt.bz2">enwiki-20180901-pages-articles-multistream-index.txt.bz2</a> 195.6 MB</li>,
<li><a href="/enwiki/20180901/enwiki-20180901-pages-meta-history1.xml-p10p2101.7z">enwiki-20180901-pages-meta-history1.xml-p10p2101.7z</a> 320.6 MB</li>]

 

我們再一次使用BeautifulSoup來解析網(wǎng)絡(luò)找尋文件。我們可以在https://dumps.wikimedia.org/enwiki/20180901/頁面里手工下載文件,但這就不夠效率了。網(wǎng)絡(luò)數(shù)據(jù)如此龐雜,懂得如何解析HTML和在程序中與網(wǎng)頁交互是非常有用的——學(xué)點(diǎn)網(wǎng)站檢索知識(shí),龐大的新數(shù)據(jù)源便觸手可及。

考慮好下載什么

上述代碼把dump里的所有文件都找出來了,你也就有了一些下載的選擇:文章當(dāng)前版本,文章頁以及當(dāng)前討論列表,或者是文章所有歷史修改版本和討論列表。如果你選擇最后一個(gè),那就是萬億字節(jié)的數(shù)據(jù)量了!本項(xiàng)目只選用文章最新版本。

所有文章的當(dāng)前版本能以單個(gè)文檔的形式獲得,但如果我們下載解析這個(gè)文檔,就得非常費(fèi)勁地一篇篇文章翻看,非常低效。更好的辦法是,下載多個(gè)分區(qū)文檔,每個(gè)文檔內(nèi)容是文章的一個(gè)章節(jié)。之后,我們可以通過并行化一次解析多個(gè)文檔,顯著提高效率。

“當(dāng)我處理文檔時(shí),我更喜歡多個(gè)小文檔而非一個(gè)大文檔,這樣我就可以并行化運(yùn)行多個(gè)文檔了。”

分區(qū)文檔格式為bz2壓縮的XML(可擴(kuò)展標(biāo)識(shí)語言),每個(gè)分區(qū)大小300~400MB,全部的壓縮包大小15.4GB。無需解壓,但如果你想解壓,大小約58GB。這個(gè)大小對于人類的全部知識(shí)來說似乎并不太大。

 

維基百科壓縮文件大小

下載文件

 

Keras 中的get_file語句在實(shí)際下載文件中非常好用。下面的代碼可通過鏈接下載文件并保存到磁盤中:

from keras.utils import get_file
saved_file_path = get_file(file, url)

下載的文件保存在~/.keras/datasets/,也是Keras默認(rèn)保存設(shè)置。一次性下載全部文件需2個(gè)多小時(shí)(你可以試試并行下載,但我試圖同時(shí)進(jìn)行多個(gè)下載任務(wù)時(shí)被限速了)

解析數(shù)據(jù)

我們首先得解壓文件。但實(shí)際我們發(fā)現(xiàn),想獲取全部文章數(shù)據(jù)根本不需要這樣。我們可以通過一次解壓運(yùn)行一行內(nèi)容來迭代文檔。當(dāng)內(nèi)存不夠運(yùn)行大容量數(shù)據(jù)時(shí),在文件間迭代通常是唯一選擇。我們可以使用bz2庫對bz2壓縮的文件迭代。

不過在測試過程中,我發(fā)現(xiàn)了一個(gè)更快捷(雙倍快捷)的方法,用的是system utility bzcat以及Python模塊的subprocess。以上揭示了一個(gè)重要的觀點(diǎn):解決問題往往有很多種辦法,而找到最有效辦法的唯一方式就是對我們的方案進(jìn)行基準(zhǔn)測試。這可以很簡單地通過%%timeit Jupyter cell magic來對方案計(jì)時(shí)評價(jià)。

迭代解壓文件的基本格式為:

data_path = '~/.keras/datasets/enwiki-20180901-pages-articles15.xml-p7744803p9244803.bz2

# Iterate through compressed file one line at a time
for line in subprocess.Popen(['bzcat'],
stdin = open(data_path),
stdout = subprocess.PIPE).stdout:
# process line

 

如果簡單地讀取XML數(shù)據(jù),并附為一個(gè)列表,我們得到看起來像這樣的東西:

 

 

維基百科文章的源XML

上面展示了一篇維基百科文章的XML文件。每個(gè)文件里面有成千上萬篇文章,因此我們下載的文件里包含百萬行這樣的語句。如果我們真想把事情弄復(fù)雜,我們可以用正則表達(dá)式和字符串匹配跑一遍文檔來找到每篇文章。這就極其低效了,我們可以采取一個(gè)更好的辦法:使用解析XML和維基百科式文章的定制化工具。

解析方法

我們需要在兩個(gè)層面上來解析文檔:

1、從XML中提取文章標(biāo)題和內(nèi)容

2、從文章內(nèi)容中提取相關(guān)信息

好在,Python對這兩個(gè)都有不錯(cuò)的應(yīng)對方法。

解析XML

解決第一個(gè)問題——定位文章,我們使用SAX(Simple API for XML) 語法解析器。BeautifulSoup語句也可以用來解析XML,但需要內(nèi)存載入整個(gè)文檔并且建立一個(gè)文檔對象模型(DOM)。而SAX一次只運(yùn)行XML里的一行字,完美符合我們的應(yīng)用場景。

基本思路就是我們對XML文檔進(jìn)行搜索,在特定標(biāo)簽間提取相關(guān)信息。例如,給出下面這段XML語句:

 

<title>Carroll F. Knicely</title>
<text xml:space="preserve">\'\'\'Carroll F. Knicely\'\'\' (born c. 1929 in [[Staunton, Virginia]] - died November 2, 2006 in [[Glasgow, Kentucky]]) was [[Editing|editor]] and [[Publishing|publisher]] of the \'\'[[Glasgow Daily Times]]\'\' for nearly 20 years (and later, its owner) and served under three [[Governor of Kentucky|Kentucky Governors]] as commissioner and later Commerce Secretary.\n'
</text>

 

我們想篩出在<title>和<text>這兩標(biāo)簽間的內(nèi)容(這個(gè)title就是維基百科文章標(biāo)題,text就是文章內(nèi)容)。SAX能直接讓我們實(shí)現(xiàn)這樣的功能——通過parser和ContentHandler這兩個(gè)語句來控制信息如何通過解析器然后被處理。每次掃一行XML句子進(jìn)解析器,Content Handler則幫我們提取相關(guān)的信息。

如果你不嘗試做一下,可能理解起來有點(diǎn)難度,但是Content handler的思想是尋找開始標(biāo)簽和結(jié)束標(biāo)簽之間的內(nèi)容,將找到的字符添加到緩存中。然后將緩存的內(nèi)容保存到字典中,其中相應(yīng)的標(biāo)簽作為對應(yīng)的鍵。最后我們得到一個(gè)鍵是標(biāo)簽,值是標(biāo)簽中的內(nèi)容的字典。下一步,我們會(huì)將這個(gè)字典傳遞給另一個(gè)函數(shù),它將解析字典中的內(nèi)容。

我們唯一需要編寫的SAX的部分是Content Handler。全文如下:

在這段代碼中,我們尋找標(biāo)簽為title和text的標(biāo)簽。每次解析器遇到其中一個(gè)時(shí),它會(huì)將字符保存到緩存中,直到遇到對應(yīng)的結(jié)束標(biāo)簽(</tag>)。然后它會(huì)保存緩存內(nèi)容到字典中-- self._values。文章由<page>標(biāo)簽區(qū)分,如果Content Handler遇到一個(gè)代表結(jié)束的 </page> 標(biāo)簽,它將添加self._values 到文章列表(self._pages)中。如果感到疑惑了,實(shí)踐觀摩一下可能會(huì)有幫助。

下面的代碼顯示了如何通過XML文件查找文章,F(xiàn)在,我們只是將它們保存到handler._pages中,稍后我們將把文章發(fā)送到另一個(gè)函數(shù)中進(jìn)行解析。

# Object for handling xml
handler = WikiXmlHandler()

# Parsing object
parser = xml.sax.make_parser()
parser.setContentHandler(handler)

# Iteratively process file
for line in subprocess.Popen(['bzcat'],
stdin = open(data_path),
stdout = subprocess.PIPE).stdout:
parser.feed(line)

# Stop when 3 articles have been found
if len(handler._pages) > 2:
break

如果我們觀察 handler._pages,我們將看到一個(gè)列表,其中每個(gè)元素都是一個(gè)包含一篇文章的標(biāo)題和內(nèi)容的元組:

handler._pages[0]

[('Carroll Knicely',
"'''Carroll F. Knicely''' (born c. 1929 in [[Staunton, Virginia]] - died November 2, 2006 in [[Glasgow, Kentucky]]) was [[Editing|editor]] and [[Publishing|publisher]] ...)]

此時(shí),我們已經(jīng)編寫的代碼可以成功地識(shí)別XML中的文章。現(xiàn)在我們完成了解析文件一半的任務(wù),下一步是處理文章以查找特定頁面和信息。再次,我們使用專為這項(xiàng)工作而創(chuàng)建的一個(gè)工具。

解析維基百科文章

維基百科運(yùn)行在一個(gè)叫做MediaWiki的軟件上,該軟件用來構(gòu)建wiki。這使文章遵循一種標(biāo)準(zhǔn)格式,這種格式可以輕易地用編程方式訪問其中的信息。雖然一篇文章的文本看起來可能只是一個(gè)字符串,但由于格式的原因,它實(shí)際上編碼了更多的信息。為了有效地獲取這些信息,我們引進(jìn)了強(qiáng)大的 mwparserfromhell, 一個(gè)為處理MediaWiki內(nèi)容而構(gòu)建的庫。

如果我們將維基百科文章的文本傳遞給 mwparserfromhell,我們會(huì)得到一個(gè)Wikicode 對象,它含有許多對數(shù)據(jù)進(jìn)行排序的方法。例如,以下代碼從文章創(chuàng)建了一個(gè)wikicode對象,并檢索文章中的 wikilinks()。這些鏈接指向維基百科的其他文章:

import mwparserfromhell

# Create the wiki article
wiki = mwparserfromhell.parse(handler._pages[6][1])

# Find the wikilinks
wikilinks = [x.title for x in wiki.filter_wikilinks()]
wikilinks[:5]

['Provo, Utah', 'Wasatch Front', 'Megahertz', 'Contemporary hit radio', 'watt']

有許多有用的方法可以應(yīng)用于wikicode,例如查找注釋或搜索特定的關(guān)鍵字。如果您想獲得文章文本的最終修訂版本,可以調(diào)用:

wiki.strip_code().strip()

'KENZ (94.9 FM, " Power 94.9 " ) is a top 40/CHR radio station broadcasting to Salt Lake City, Utah '

因?yàn)槲业淖罱K目標(biāo)是找到所有關(guān)于書籍的文章,那么是否有一種方法可以使用解析器來識(shí)別某個(gè)類別中的文章呢?幸運(yùn)的是,答案是肯定的——使用MediaWiki templates。

文章模板

模板(templates)是記錄信息的標(biāo)準(zhǔn)方法。維基百科上有無數(shù)的模板,但與我們的目的最相關(guān)的是信息框( Infoboxes)。有些模板編碼文章的摘要信息。例如,戰(zhàn)爭與和平的信息框是:

維基百科上的每一類文章,如電影、書籍或廣播電臺(tái),都有自己的信息框。在書籍的例子中,信息框模板被命名為Infobox book。同樣,wiki對象有一個(gè)名為filter_templates()的方法,它允許我們從一篇文章中提取特定的模板。因此,如果我們想知道一篇文章是否是關(guān)于一本書的,我們可以通過book信息框去過濾。展示如下:

# Filter article for book template
wiki.filter_templates('Infobox book')

如果匹配成功,那我們就找到一本書了!要查找你感興趣的文章類別的信息框模板,請參閱信息框列表。

如何將用于解析文章的mwparserfromhell 與我們編寫的SAX解析器結(jié)合起來?我們修改了Content Handler中的endElement方法,將包含文章標(biāo)題和文本的值的字典,發(fā)送到通過指定模板搜索文章文本的函數(shù)中。如果函數(shù)找到了我們想要的文章,它會(huì)從文章中提取信息,然后返回給handler。首先,我將展示更新后的endElement 。

def endElement(self, name):
"""Closing tag of element"""
if name == self._current_tag:
self._values[name] = ' '.join(self._buffer)

if name == 'page':
self._article_count += 1
# Send the page to the process article function
book = process_article(**self._values,
template = 'Infobox book')
# If article is a book append to the list of books
if book:
self._books.append(book)

一旦解析器到達(dá)文章的末尾,我們將文章傳遞到函數(shù) process_article,如下所示:

def process_article(title, text, timestamp, template = 'Infobox book'):

"""Process a wikipedia article looking for template"""

# Create a parsing object
wikicode = mwparserfromhell.parse(text)

# Search through templates for the template
matches = wikicode.filter_templates(matches = template)

if len(matches) >= 1:
# Extract information from infobox
properties = {param.name.strip_code().strip(): param.value.strip_code().strip()
for param in matches[0].params
if param.value.strip_code().strip()}

# Extract internal wikilinks

雖然我正在尋找有關(guān)書籍的文章,但是這個(gè)函數(shù)可以用來搜索維基百科上任何類別的文章。只需將模板替換為指定類別的模板(例如 Infobox language是用來尋找語言的),它只會(huì)返回符合條件的文章信息。

我們可以在一個(gè)文件上測試這個(gè)函數(shù)和新的ContentHandler 。

Searched through 427481 articles.
Found 1426 books in 1055 seconds.

讓我們看一下查找一本書的結(jié)果:

books[10]

['War and Peace',
{'name': 'War and Peace',
'author': 'Leo Tolstoy',
'language': 'Russian, with some French',
'country': 'Russia',
'genre': 'Novel (Historical novel)',
'publisher': 'The Russian Messenger (serial)',
'title_orig': 'Война и миръ',
'orig_lang_code': 'ru',
'translator': 'The first translation of War and Peace into English was by American Nathan Haskell Dole, in 1899',
'image': 'Tolstoy - War and Peace - first edition, 1869.jpg',
'caption': 'Front page of War and Peace, first edition, 1869 (Russian)',
'release_date': 'Serialised 1865–1867; book 1869',
'media_type': 'Print',
'pages': '1,225 (first published edition)'},
['Leo Tolstoy',
'Novel',
'Historical novel',
'The Russian Messenger',
'Serial (publishing)',
'Category:1869 Russian novels',
'Category:Epic novels',
'Category:Novels set in 19th-century Russia',
'Category:Russian novels adapted into films',
'Category:Russian philosophical novels'],
['https://books.google.com/?id=c4HEAN-ti1MC',
'https://www.britannica.com/art/English-literature',
'https://books.google.com/books?id=xf7umXHGDPcC',
'https://books.google.com/?id=E5fotqsglPEC',
'https://books.google.com/?id=9sHebfZIXFAC'],
'2018-08-29T02:37:35Z']

對于維基百科上的每一本書,我們把信息框中的信息整理為字典、書籍在維基百科中的wikilinks信息、書籍的外部鏈接和最新編輯的時(shí)間戳。(我把精力集中在這些信息上,為我的下一個(gè)項(xiàng)目建立一個(gè)圖書推薦系統(tǒng))。你可以修改process_article 函數(shù)和WikiXmlHandler類,以查找任何你需要的信息和文章!

如果你看一下只處理一個(gè)文件的時(shí)間,1055秒,然后乘以55,你會(huì)發(fā)現(xiàn)處理所有文件的時(shí)間超過了15個(gè)小時(shí)!當(dāng)然,我們可以在一夜之間運(yùn)行,但如果可以的話,我不想浪費(fèi)額外的時(shí)間。這就引出了我們將在本項(xiàng)目中介紹的最后一種技術(shù):使用多處理和多線程進(jìn)行并行化。

并行操作

與其一次一個(gè)解析文件,不如同時(shí)處理其中的幾個(gè)(這就是我們下載分區(qū)的原因)。我們可以使用并行化,通過多線程或多處理來實(shí)現(xiàn)。

多線程與多處理

多線程和多處理是同時(shí)在計(jì)算機(jī)或多臺(tái)計(jì)算機(jī)上執(zhí)行許多任務(wù)的方法。我們磁盤上有許多文件,每個(gè)文件都需要以相同的方式進(jìn)行解析。一個(gè)簡單的方法是一次解析一個(gè)文件,但這并沒有充分利用我們的資源。因此,我們可以使用多線程或多處理同時(shí)解析多個(gè)文件,這將大大加快整個(gè)過程。

通常,多線程對于輸入/輸出綁定任務(wù)(例如讀取文件或發(fā)出請求)更好(更快)。多處理對于cpu密集型任務(wù)更好(更快)。對于解析文章的過程,我不確定哪種方法是最優(yōu)的,因此我再次用不同的參數(shù)對這兩種方法進(jìn)行了基準(zhǔn)測試。

學(xué)習(xí)如何進(jìn)行測試和尋找不同的方法來解決一個(gè)問題,你將會(huì)在數(shù)據(jù)科學(xué)或任何技術(shù)的職業(yè)生涯中走得更遠(yuǎn)。

相關(guān)報(bào)道:https://towardsdatascience.com/wikipedia-data-science-working-with-the-worlds-largest-encyclopedia-c08efbac5f5c

標(biāo)簽: Google 代碼 服務(wù)器 數(shù)據(jù)庫 搜索 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:數(shù)據(jù)科學(xué)家應(yīng)當(dāng)了解的五個(gè)統(tǒng)計(jì)基本概念

下一篇:百年精匠初心之作 夏普二代AQUOS 8K電視震撼發(fā)布