Python 數(shù)據(jù)處理系列博客來(lái)啦亦鳞!
本系列將以《Python數(shù)據(jù)處理》這本書(shū)為基礎(chǔ)馍忽,以書(shū)中每章一篇博客的形式帶大家一起學(xué)習(xí) Python 數(shù)據(jù)處理棒坏。書(shū)中有些地方講的不太詳細(xì),我會(huì)查閱其他資料來(lái)補(bǔ)充遭笋,力爭(zhēng)每篇博客都把知識(shí)點(diǎn)涵蓋全且通俗易懂坝冕。
這本書(shū)主要講了如何用 Python 處理各種類(lèi)型的文件,如 JSON瓦呼、XML喂窟、CSV、Excel央串、PDF 等磨澡。后面幾章還會(huì)講數(shù)據(jù)清洗、網(wǎng)頁(yè)抓取质和、自動(dòng)化和規(guī)奈壬悖化等使用技能。我也是 Python 初學(xué)者饲宿,將以初學(xué)者的角度寫(xiě)文章厦酬,所以博客對(duì)初學(xué)者比較友好。
100
多位經(jīng)驗(yàn)豐富的開(kāi)發(fā)者參與瘫想,在 Github 上獲得了近1000
個(gè)star
的全棧全平臺(tái)開(kāi)源項(xiàng)目想了解或參與嗎仗阅?
項(xiàng)目地址:https://github.com/cachecats/coderiver
前言
以易于機(jī)器理解的方式來(lái)存儲(chǔ)數(shù)據(jù)的文件格式,通常被稱(chēng)作機(jī)器可讀的 (machine readable)国夜。常見(jiàn)的機(jī)器可讀格式包括:
- 逗號(hào)分隔值(Comma-Separated Values霹菊,CSV)
- JavaScript 對(duì)象符號(hào)(JavaScript Object Notation,JSON)
- 可擴(kuò)展標(biāo)記語(yǔ)言(eXtensible Markup Language支竹,XML)
在口語(yǔ)和書(shū)面語(yǔ)中旋廷,提到這些數(shù)據(jù)格式時(shí)通常使用它們的短名字(如 CSV)。 我們將使用這些縮寫(xiě) 礼搁。
一饶碘、CSV數(shù)據(jù)
CSV 文件(簡(jiǎn)稱(chēng)為 CSV)是指將數(shù)據(jù)列用逗號(hào)分隔的文件。文件的擴(kuò)展名是 .csv馒吴。
另一種數(shù)據(jù)類(lèi)型扎运,叫作制表符分隔值(tab-separated values,TSV)數(shù)據(jù)饮戳,有時(shí)也與 CSV歸為一類(lèi)豪治。TSV 與 CSV 唯一的不同之處在于,數(shù)據(jù)列之間的分隔符是制表符(tab)扯罐,而不是逗號(hào)负拟。文件的擴(kuò)展名通常是 .tsv,但有時(shí)也用 .csv 作為擴(kuò)展名歹河。從本質(zhì)上來(lái)看掩浙,.tsv 文件與 .csv 文件在Python 中的作用是相同的花吟。
我們采用的數(shù)據(jù)源是從世界衛(wèi)生組織(https://www.who.int/zh/home)中下載的數(shù)據(jù)。
打開(kāi)世衛(wèi)組織官網(wǎng)后厨姚,點(diǎn)擊“健康主題”衅澈,“數(shù)據(jù)和統(tǒng)計(jì)” 就能找到很多數(shù)據(jù)。
這里下載了關(guān)于嬰幼兒護(hù)理的統(tǒng)計(jì)數(shù)據(jù)谬墙,并重命名為 data.csv
今布。
csv 文件可以直接用 Excel 打開(kāi)直觀(guān)的看到,我們用 Excel 打開(kāi)如下圖:
接下來(lái)就要用 Python 來(lái)簡(jiǎn)單的處理這些數(shù)據(jù)拭抬。
以列表的形式讀取csv數(shù)據(jù)
編寫(xiě)一個(gè)讀取 csv 文件的程序:
import csv
csvfile = open('./data.csv', 'r')
reader = csv.reader(csvfile)
for row in reader:
print(row)
import csv
將導(dǎo)入 Python 自帶的 csv 模塊险耀。csvfile = open('./data.csv', 'r')
以只讀的形式打開(kāi)數(shù)據(jù)文件并存儲(chǔ)到變量 csvfile
中。然后調(diào)用 csv 的 reader()
方法將輸出保存在 reader
變量中玖喘,再用 for 循環(huán)將數(shù)據(jù)輸出。
運(yùn)行程序蘑志,控制臺(tái)輸出:
可以看到跟 Excel 打開(kāi)的內(nèi)容一致累奈。
以字典的形式讀取csv數(shù)據(jù)
改一下代碼,以字典的形式讀取 csv
import csv
csvfile = open('./data.csv', 'r')
reader = csv.DictReader(csvfile)
for row in reader:
print(row)
控制臺(tái)輸出:
二急但、JSON數(shù)據(jù)
同樣在世衛(wèi)組織官網(wǎng)下載數(shù)據(jù)源澎媒,重命名為 data.json
。用格式化工具打開(kāi) json
文件如下:
編寫(xiě)程序?qū)?json 進(jìn)行解析
import json
# 將 json 文件讀取成字符串
json_data = open('./data.json').read()
# 對(duì)json數(shù)據(jù)解碼
data = json.loads(json_data)
# data 的類(lèi)型是 字典dict
print(type(data))
# 直接打印 data
print(data)
# 遍歷字典
for k, v in data.items():
print(k + ':' + str(v))
控制臺(tái)輸出:
Python3 中可以使用 json 模塊來(lái)對(duì) JSON 數(shù)據(jù)進(jìn)行編解碼波桩,它包含了兩個(gè)函數(shù):
- json.dumps(): 對(duì)數(shù)據(jù)進(jìn)行編碼戒努。
- json.loads(): 對(duì)數(shù)據(jù)進(jìn)行解碼。
在json的編解碼過(guò)程中镐躲,python 的原始類(lèi)型與json類(lèi)型會(huì)相互轉(zhuǎn)換储玫,具體的轉(zhuǎn)化對(duì)照如下:
Python 編碼為 JSON 類(lèi)型轉(zhuǎn)換對(duì)應(yīng)表:
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float, int- & float-derived Enums | number |
True | true |
False | false |
None | null |
JSON 解碼為 Python 類(lèi)型轉(zhuǎn)換對(duì)應(yīng)表:
JSON | Python |
---|---|
object | dict |
array | list |
string | str |
number (int) | int |
number (real) | float |
true | True |
false | False |
null | None |
三、XML 數(shù)據(jù)
XML 格式的數(shù)據(jù)既便于機(jī)器讀取萤皂,也便于人工讀取撒穷。但是對(duì)于本章的數(shù)據(jù)集來(lái)說(shuō),預(yù)覽并理解 CSV 文件和 JSON 文件要比 XML 文件容易得多裆熙。
xml 格式說(shuō)明:
- Tag: 使用<和>包圍的部分端礼;
- Element:被Tag包圍的部分,如 2003入录,可以認(rèn)為是一個(gè)節(jié)點(diǎn)蛤奥,它可以有子節(jié)點(diǎn);
- Attribute:在Tag中可能存在的 name/value 對(duì)僚稿,如示例中的 title="Enemy Behind"凡桥,一般表示屬性。
世衛(wèi)組織的數(shù)據(jù)不好理解蚀同,咱們用個(gè)簡(jiǎn)單的能看得懂的電影數(shù)據(jù)來(lái)做演示:
<?xml version="1.0" encoding="UTF-8"?>
<collection shelf="New Arrivals">
<movie title="Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title="Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
<movie title="Trigun">
<type>Anime, Action</type>
<format>DVD</format>
<episodes>4</episodes>
<rating>PG</rating>
<stars>10</stars>
<description>Vash the Stampede!</description>
</movie>
<movie title="Ishtar">
<type>Comedy</type>
<format>VHS</format>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom</description>
</movie>
</collection>
這個(gè)數(shù)據(jù)相對(duì)來(lái)說(shuō)比較簡(jiǎn)單唬血,只有三層望蜡。但原理掌握了,幾層數(shù)據(jù)都能搞定拷恨。
下面編寫(xiě)代碼對(duì)上面的 xml 進(jìn)行解析脖律,解析之后再分別格式化成字典和 json 格式的數(shù)據(jù)輸出:
from xml.etree import ElementTree as ET
import json
tree = ET.parse('./resource/movie.xml')
root = tree.getroot()
all_data = []
for movie in root:
# 存儲(chǔ)電影數(shù)據(jù)的字典
movie_data = {}
# 存儲(chǔ)屬性的字典
attr_data = {}
# 取出 type 標(biāo)簽的值
movie_type = movie.find('type')
attr_data['type'] = movie_type.text
# 取出 format 標(biāo)簽的值
movie_format = movie.find('format')
attr_data['format'] = movie_format.text
# 取出 year 標(biāo)簽的值
movie_year = movie.find('year')
if movie_year:
attr_data['year'] = movie_year.text
# 取出 rating 標(biāo)簽的值
movie_rating = movie.find('rating')
attr_data['rating'] = movie_rating.text
# 取出 stars 標(biāo)簽的值
movie_stars = movie.find('stars')
attr_data['stars'] = movie_stars.text
# 取出 description 標(biāo)簽的值
movie_description = movie.find('description')
attr_data['description'] = movie_description.text
# 獲取電影名字,以電影名為字典的鍵腕侄,屬性信息為字典的值
movie_title = movie.attrib.get('title')
movie_data[movie_title] = attr_data
# 存入列表中
all_data.append(movie_data)
print(all_data)
# all_data 此時(shí)是一個(gè)列表對(duì)象小泉,用 json.dumps() 將python對(duì)象轉(zhuǎn)換為 json 字符串
json_str = json.dumps(all_data)
print(json_str)
注釋寫(xiě)的比較詳細(xì),下面介紹下 ElementTree
提供的方法冕杠。
3.1 解析的三種方法
ElementTree
解析 xml 有三種方法:
-
調(diào)用parse()方法微姊,返回解析樹(shù)
tree = ET.parse('./resource/movie.xml') root = tree.getroot()
-
調(diào)用from_string(),返回解析樹(shù)的根元素
data = open('./resource/movie.xml').read() root = ET.fromstring(data)
-
調(diào)用 ElementTree 類(lèi)的
ElementTree(self, element=None, file=None)
方法tree = ET.ElementTree(file="./resource/movie.xml") root = tree.getroot()
3.2 Element 對(duì)象
class xml.etree.ElementTree.Element(tag, attrib={}, **extra)
Element 對(duì)象的屬性
- tag: 標(biāo)簽
- text: 去除標(biāo)簽,獲得標(biāo)簽中的內(nèi)容分预。
- attrib: 獲取標(biāo)簽中的屬性和屬性值兢交。
- tail: 這個(gè)屬性可以用來(lái)保存與元素相關(guān)聯(lián)的附加數(shù)據(jù)。它的值通常是字符串笼痹,但可能是特定于應(yīng)用程序的對(duì)象配喳。
Element 對(duì)象的方法
clear()
:清除所有子元素和所有屬性,并將文本和尾部屬性設(shè)置為None凳干。get(attribute_name, default=None)
:通過(guò)指定屬性名獲取屬性值晴裹。items()
:以鍵值對(duì)的形式返回元素屬性。keys()
:以列表的方式返回元素名救赐。set(attribute_name,attribute_value)
:在某標(biāo)簽中設(shè)置屬性和屬性值涧团。append(subelement)
:將元素子元素添加到元素的子元素內(nèi)部列表的末尾。extend(subelements)
:追加子元素经磅。find(match, namespaces=None)
:找到第一個(gè)匹配的子元素泌绣,match可以是標(biāo)簽名或者path。返回Elememt實(shí)例或None预厌。findall(match, namespaces=None)
:找到所有匹配的子元素赞别,返回的是一個(gè)元素列表。findtext(match, default=None, namespaces=None)
:找到匹配第一個(gè)子元素的文本配乓。返回的是匹配元素中的文本內(nèi)容仿滔。getchildren()
:Python3.2后使用list(elem)
或 iteration.getiterator(tag=None)
:Python3.2后使用Element.iter()
iter(tag=None)
:以當(dāng)前元素為根創(chuàng)建樹(shù)迭代器。迭代器遍歷這個(gè)元素和它下面的所有元素(深度優(yōu)先級(jí))犹芹。如果標(biāo)簽不是None或’*’崎页,那么只有標(biāo)簽等于標(biāo)簽的元素才會(huì)從迭代器返回。如果在迭代過(guò)程中修改樹(shù)結(jié)構(gòu)腰埂,則結(jié)果是未定義的飒焦。iterfind(match, namespaces=None)
: 匹配滿(mǎn)足條件的子元素,返回元素。
3.3 ElementTree 對(duì)象
class xml.etree.ElementTree.ElementTree(element=None, file=None)
ElementTree是一個(gè)包裝器類(lèi)牺荠,這個(gè)類(lèi)表示一個(gè)完整的元素層次結(jié)構(gòu)翁巍,并為標(biāo)準(zhǔn)XML的序列化添加了一些額外的支持。
setroot(element)
:替換根元素休雌,原來(lái)的根元素中的內(nèi)容會(huì)消失灶壶。find(match, namespaces=None)
:從根元素開(kāi)始匹配和 Element.find()作用一樣。findall(match, namespaces=None)
:從根元素開(kāi)始匹配和 Element.findall()作用一樣杈曲。findtext(match, default=None, namespaces=None)
:從根元素開(kāi)始匹配和 Element.findtext()作用一樣驰凛。getiterator(tag=None)
:Python3.2后使用 ElementTree.iter() 代替。iter(tag=None)
:迭代所有元素iterfind(match, namespaces=None)
:從根元素開(kāi)始匹配和 Element.iterfind()作用一樣担扑。parse(source, parser=None)
:解析xml文本恰响,返回根元素。write(file, encoding=”us-ascii”, xml_declaration=None, default_namespace=None, method=”xml”, *, short_empty_elements=True)
:寫(xiě)出XML文本涌献。
對(duì) JSON胚宦、XML、CSV三種格式數(shù)據(jù)的處理就講完啦燕垃,下期講如何處理 Excel 文件枢劝,歡迎關(guān)注。
全棧全平臺(tái)開(kāi)源項(xiàng)目 CodeRiver
CodeRiver 是一個(gè)免費(fèi)的項(xiàng)目協(xié)作平臺(tái)利术,愿景是打通 IT 產(chǎn)業(yè)上下游,無(wú)論你是產(chǎn)品經(jīng)理低矮、設(shè)計(jì)師印叁、程序員或是測(cè)試情屹,還是其他行業(yè)人員溅蛉,只要有好的創(chuàng)意、想法收壕,都可以來(lái) CodeRiver 免費(fèi)發(fā)布項(xiàng)目蝗锥,召集志同道合的隊(duì)友一起將夢(mèng)想變?yōu)楝F(xiàn)實(shí)跃洛!
CodeRiver 本身還是一個(gè)大型開(kāi)源項(xiàng)目,致力于打造全棧全平臺(tái)企業(yè)級(jí)精品開(kāi)源項(xiàng)目终议。涵蓋了 React汇竭、Vue、Angular穴张、小程序细燎、ReactNative、Android皂甘、Flutter玻驻、Java、Node 等幾乎所有主流技術(shù)棧偿枕,主打代碼質(zhì)量璧瞬。
目前已經(jīng)有近 100
名優(yōu)秀開(kāi)發(fā)者參與户辫,github 上的 star
數(shù)量將近 1000
個(gè)。每個(gè)技術(shù)棧都有多位經(jīng)驗(yàn)豐富的大佬坐鎮(zhèn)嗤锉,更有兩位架構(gòu)師指導(dǎo)項(xiàng)目架構(gòu)渔欢。無(wú)論你想學(xué)什么語(yǔ)言處于什么技術(shù)水平,相信都能在這里學(xué)有所獲档冬。
通過(guò) 高質(zhì)量源碼 + 博客 + 視頻
膘茎,幫助每一位開(kāi)發(fā)者快速成長(zhǎng)。
項(xiàng)目地址:https://github.com/cachecats/coderiver
您的鼓勵(lì)是我們前行最大的動(dòng)力酷誓,歡迎點(diǎn)贊披坏,歡迎送小星星? ~