pandas是本書(shū)后續(xù)內(nèi)容的首選庫(kù)篙骡。
它含有使數(shù)據(jù)清洗和分析工作變得更快更簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)和操作工具。pandas經(jīng)常和其它工具一同使用蝶桶,如數(shù)值計(jì)算工具NumPy和SciPy耍贾,分析庫(kù)statsmodels和scikit-learn,和數(shù)據(jù)可視化庫(kù)matplotlib挟伙。pandas是基于NumPy數(shù)組構(gòu)建的楼雹,特別是基于數(shù)組的函數(shù)和不使用for循環(huán)的數(shù)據(jù)處理模孩。
http://nbviewer.jupyter.org/github/LearnXu/pydata-notebook/tree/master/
雖然pandas采用了大量的NumPy編碼風(fēng)格,但二者最大的不同是pandas是專(zhuān)門(mén)為處理表格和混雜數(shù)據(jù)設(shè)計(jì)的贮缅。而NumPy更適合處理統(tǒng)一的數(shù)值數(shù)組數(shù)據(jù)榨咐。
自從2010年pandas開(kāi)源以來(lái),pandas逐漸成長(zhǎng)為一個(gè)非常大的庫(kù)谴供,應(yīng)用于許多真實(shí)案例块茁。開(kāi)發(fā)者社區(qū)已經(jīng)有了800個(gè)獨(dú)立的貢獻(xiàn)者,他們?cè)诮鉀Q日常數(shù)據(jù)問(wèn)題的同時(shí)為這個(gè)項(xiàng)目提供貢獻(xiàn)桂肌。
在本書(shū)后續(xù)部分中数焊,我將使用下面這樣的pandas引入約定:
In [1]: import pandas as pd
因此,只要你在代碼中看到pd.崎场,就得想到這是pandas佩耳。因?yàn)镾eries和DataFrame用的次數(shù)非常多,所以將其引入本地命名空間中會(huì)更方便:
In [2]: from pandas import Series, DataFrame
5.1 pandas的數(shù)據(jù)結(jié)構(gòu)介紹
數(shù)據(jù)結(jié)構(gòu)其實(shí)就是Series和DataFrame谭跨。
1 Series
Series是一種類(lèi)似于一維數(shù)組的對(duì)象干厚,它由一組數(shù)據(jù)(各種NumPy數(shù)據(jù)類(lèi)型)以及一組與之相關(guān)的index(即索引)組成。僅由一組數(shù)據(jù)即可產(chǎn)生最簡(jiǎn)單的Series:
In [11]: obj = pd.Series([4, 7, -5, 3])
In [12]: obj
Out[12]:
0 4
1 7
2 -5
3 3 #前面一列就是索引
dtype: int64
可以看到螃宙,左邊表示index蛮瞄,右邊表示對(duì)應(yīng)的value∽辉可以通過(guò)value和index屬性查看:
In [13]: obj.values
Out[13]: array([ 4, 7, -5, 3])
In [14]: obj.index # like range(4)
Out[14]: RangeIndex(start=0, stop=4, step=1)
當(dāng)然我們也可以自己指定index的label:
In [15]: obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
In [16]: obj2
Out[16]:
d 4
b 7
a -5
c 3
dtype: int64
In [17]: obj2.index
Out[17]: Index(['d', 'b', 'a', 'c'], dtype='object')
可以用index的label來(lái)選擇:
In [18]: obj2['a']
Out[18]: -5
In [19]: obj2['d'] = 6
In [20]: obj2[['c', 'a', 'd']]
Out[20]:
c 3
a -5
d 6
dtype: int64
這里['c', 'a', 'd']其實(shí)被當(dāng)做了索引挂捅,盡管這個(gè)索引是用string構(gòu)成的。
使用numpy函數(shù)或類(lèi)似的操作燕酷,會(huì)保留index-value的關(guān)系:
In [21]: obj2[obj2 > 0]
Out[21]:
d 6
b 7
c 3
dtype: int64
In [22]: obj2 * 2
Out[22]:
d 12
b 14
a -10
c 6
dtype: int64
In [23]: np.exp(obj2)
Out[23]:
d 403.428793
b 1096.633158
a 0.006738
c 20.085537
dtype: float64
另一種看待series的方法籍凝,它是一個(gè)長(zhǎng)度固定,有順序的dict苗缩,從index映射到value饵蒂。在很多場(chǎng)景下,可以當(dāng)做dict來(lái)用:
In [24]: 'b' in obj2
Out[24]: True
In [25]: 'e' in obj2
Out[25]: False
還可以直接用現(xiàn)有的dict來(lái)創(chuàng)建series:
In [26]: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
In [27]: obj3 = pd.Series(sdata)
In [28]: obj3
Out[28]:
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64
series中的index其實(shí)就是dict中排好序的keys酱讶。我們也可以傳入一個(gè)自己想要的順序:
In [29]: states = ['California', 'Ohio', 'Oregon', 'Texas']
In [30]: obj4 = pd.Series(sdata, index=states)
In [31]: obj4
Out[31]:
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
在這個(gè)例子中退盯,sdata中跟states索引相匹配的那3個(gè)值會(huì)被找出來(lái)并放到相應(yīng)的位置上,但由于"California"所對(duì)應(yīng)的sdata值找不到泻肯,所以其結(jié)果就為NaN(即“非數(shù)字”(not a number)渊迁,在pandas中,它用于表示缺失或NA值)灶挟。因?yàn)椤甎tah’不在states中琉朽,它被從結(jié)果中除去。
我將使用缺失(missing)或NA表示缺失數(shù)據(jù)稚铣。pandas的isnull和notnull函數(shù)可用于檢測(cè)缺失數(shù)據(jù):
In [32]: pd.isnull(obj4)
Out[32]:
California True
Ohio False
Oregon False
Texas False
dtype: bool
In [33]: pd.notnull(obj4)
Out[33]:
California False
Ohio True
Oregon True
Texas True
dtype: bool
Series也有類(lèi)似的實(shí)例方法:
In [34]: obj4.isnull()
Out[34]:
California True
Ohio False
Oregon False
Texas False
dtype: bool
關(guān)于缺失數(shù)據(jù)箱叁,在第七章還會(huì)講得更詳細(xì)一些墅垮。
series中一個(gè)有用的特色自動(dòng)按index label來(lái)排序(Data alignment features):
In [35]: obj3
Out[35]:
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64
In [36]: obj4
Out[36]:
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
In [37]: obj3 + obj4
Out[37]:
California NaN
Ohio 70000.0
Oregon 32000.0
Texas 142000.0
Utah NaN
dtype: float64
這個(gè)Data alignment features(數(shù)據(jù)對(duì)齊特色)和數(shù)據(jù)庫(kù)中的join相似。
serice自身和它的index都有一個(gè)叫name的屬性耕漱,這個(gè)能和其他pandas的函數(shù)進(jìn)行整合:
In [38]: obj4.name = 'population'
In [39]: obj4.index.name = 'state'
In [40]: obj4
Out[40]:
state
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
Name: population, dtype: float64
series的index能被直接更改:
In [41]: obj
Out[41]:
0 4
1 7
2 -5
3 3
dtype: int64
In [42]: obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
In [43]: obj
Out[43]:
Bob 4
Steve 7
Jeff -5
Ryan 3
dtype: int64
2 DataFrame
DataFrame表示一個(gè)長(zhǎng)方形表格算色,并包含排好序的列,每一列都可以是不同的數(shù)值類(lèi)型(數(shù)字螟够,字符串灾梦,布爾值)。DataFrame有行索引和列索引(row index, column index)妓笙;可以看做是分享所有索引的由series組成的字典若河。數(shù)據(jù)是保存在一維以上的區(qū)塊里的。
(其實(shí)我是把dataframe當(dāng)做excel里的那種表格來(lái)用的给郊,這樣感覺(jué)更直觀一些)
構(gòu)建一個(gè)dataframe的方法牡肉,用一個(gè)dcit,dict里的值是list:
In [2]: import pandas as pd
In [3]: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
...: 'year': [2000, 2001, 2002, 2001, 2002, 2003],
...: 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
...:
...: frame = pd.DataFrame(data)
...:
...: frame
...:
Out[3]: #結(jié)果DataFrame會(huì)自動(dòng)加上索引(跟Series一樣)淆九,且全部列會(huì)被有序排列
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
5 Nevada 2003 3.2
如果你使用的是Jupyter notebook,pandas DataFrame對(duì)象會(huì)以對(duì)瀏覽器友好的HTML表格的方式呈現(xiàn)毛俏。
對(duì)于一個(gè)較大的DataFrame炭庙,用head方法會(huì)返回前5行(注:這個(gè)函數(shù)在數(shù)據(jù)分析中經(jīng)常使用,用來(lái)查看表格里有什么東西):
In [46]: frame.head()
Out[46]:
pop state year
0 1.5 Ohio 2000
1 1.7 Ohio 2001
2 3.6 Ohio 2002
3 2.4 Nevada 2001
4 2.9 Nevada 2002
如果指定一列的話煌寇,會(huì)自動(dòng)按列排序:
In [47]: pd.DataFrame(data, columns=['year', 'state', 'pop'])
Out[47]:
year state pop
0 2000 Ohio 1.5
1 2001 Ohio 1.7
2 2002 Ohio 3.6
3 2001 Nevada 2.4
4 2002 Nevada 2.9
5 2003 Nevada 3.2
如果你導(dǎo)入一個(gè)不存在的列名焕蹄,那么會(huì)顯示為缺失數(shù)據(jù):
In [48]: frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
....: index=['one', 'two', 'three', 'four',
....: 'five', 'six'])
In [49]: frame2
Out[49]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 NaN
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 NaN
five 2002 Nevada 2.9 NaN
six 2003 Nevada 3.2 NaN
In [50]: frame2.columns
Out[50]: Index(['year', 'state', 'pop', 'debt'], dtype='object')
從DataFrame里提取一列的話會(huì)返回series格式,可以以屬性或是dict一樣的形式來(lái)提确堋:
In [51]: frame2['state']
Out[51]:
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
six Nevada
Name: state, dtype: object
In [52]: frame2.year
Out[52]:
one 2000
two 2001
three 2002
four 2001
five 2002
six 2003
Name: year, dtype: int64
筆記:frame2[column]適用于任何列的名腻脏,但是frame2.column只有在列名存在才適用。
返回的series有DataFrame種同樣的index银锻,而且name屬性也是對(duì)應(yīng)的永品。
對(duì)于行,要用在loc屬性里用 位置或名字(就第幾行:
In [53]: frame2.loc['three']
Out[53]:
year 2002
state Ohio
pop 3.6
debt NaN
Name: three, dtype: object
列值也能通過(guò)賦值改變击纬。比如給debt賦值:
In [54]: frame2['debt'] = 16.5
In [55]: frame2
Out[55]:
year state pop debt
one 2000 Ohio 1.5 16.5
two 2001 Ohio 1.7 16.5
three 2002 Ohio 3.6 16.5
four 2001 Nevada 2.4 16.5
five 2002 Nevada 2.9 16.5
six 2003 Nevada 3.2 16.5
In [56]: frame2['debt'] = np.arange(6.)
In [57]: frame2
Out[57]:
year state pop debt
one 2000 Ohio 1.5 0.0
two 2001 Ohio 1.7 1.0
three 2002 Ohio 3.6 2.0
four 2001 Nevada 2.4 3.0
five 2002 Nevada 2.9 4.0
six 2003 Nevada 3.2 5.0
如果把list或array賦給column的話鼎姐,長(zhǎng)度必須符合DataFrame的長(zhǎng)度。如果把一二series賦給DataFrame更振,會(huì)按DataFrame的index來(lái)賦值炕桨,不夠的地方用缺失數(shù)據(jù)來(lái)表示:
In [58]: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
In [59]: frame2['debt'] = val
In [60]: frame2
Out[60]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7
six 2003 Nevada 3.2 NaN
如果列不存在,賦值會(huì)創(chuàng)建一個(gè)新列肯腕。而del也能像刪除字典關(guān)鍵字一樣献宫,刪除列:
In [61]: frame2['eastern'] = frame2.state == 'Ohio'
In [62]: frame2
Out[62]:
year state pop debt eastern
one 2000 Ohio 1.5 NaN True
two 2001 Ohio 1.7 -1.2 True
three 2002 Ohio 3.6 NaN True
four 2001 Nevada 2.4 -1.5 False
five 2002 Nevada 2.9 -1.7 False
six 2003 Nevada 3.2 NaN False
然后用del刪除這一列:
In [63]: del frame2['eastern']
In [64]: frame2.columns
Out[64]: Index(['year', 'state', 'pop', 'debt'], dtype='object')
注意:columns返回的是一個(gè)view,而不是新建了一個(gè)copy实撒。因此姊途,任何對(duì)series的改變帖池,會(huì)反映在DataFrame上。除非我們用copy方法來(lái)新建一個(gè)吭净。
另一種常見(jiàn)的格式是dict中的dict:
In [65]: pop = {'Nevada': {2001: 2.4, 2002: 2.9},
....: 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
把上面這種嵌套dcit傳給DataFrame睡汹,pandas會(huì)把外層dcit的key當(dāng)做列,內(nèi)層key當(dāng)做行索引:
In [66]: frame3 = pd.DataFrame(pop)
In [67]: frame3
Out[67]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
你也可以使用類(lèi)似NumPy數(shù)組的方法寂殉,對(duì)DataFrame進(jìn)行轉(zhuǎn)置(交換行和列):
In [68]: frame3.T
Out[68]:
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6
指定index:
In [69]: pd.DataFrame(pop, index=[2001, 2002, 2003])
Out[69]:
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN
series組成的dict:
In [70]: pdata = {'Ohio': frame3['Ohio'][:-1],
....: 'Nevada': frame3['Nevada'][:2]}
In [71]: pd.DataFrame(pdata)
Out[71]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
表5-1列出了DataFrame構(gòu)造函數(shù)所能接受的各種數(shù)據(jù)囚巴。
如果設(shè)置了DataFrame的index和columns的name屬性,則這些信息也會(huì)被顯示出來(lái):
In [72]: frame3.index.name = 'year'; frame3.columns.name = 'state'
In [73]: frame3
Out[73]:
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
values屬性會(huì)返回二維數(shù)組:
In [74]: frame3.values
Out[74]:
array([[ nan, 1.5],
[ 2.4, 1.7],
[ 2.9, 3.6]])
如果column有不同的類(lèi)型友扰,dtype會(huì)適應(yīng)所有的列(如果DataFrame各列的數(shù)據(jù)類(lèi)型不同彤叉,則值數(shù)組的dtype就會(huì)選用能兼容所有列的數(shù)據(jù)類(lèi)型:
In [75]: frame2.values
Out[75]:
array([[2000, 'Ohio', 1.5, nan],
[2001, 'Ohio', 1.7, -1.2],
[2002, 'Ohio', 3.6, nan],
[2001, 'Nevada', 2.4, -1.5],
[2002, 'Nevada', 2.9, -1.7],
[2003, 'Nevada', 3.2, nan]], dtype=object)
3 Index Objects (索引對(duì)象)
pandas的Index Objects (索引對(duì)象)負(fù)責(zé)保存axis labels和其他一些數(shù)據(jù)(比如axis name或names)。一個(gè)數(shù)組或其他一個(gè)序列標(biāo)簽村怪,只要被用來(lái)做構(gòu)建series或DataFrame秽浇,就會(huì)被自動(dòng)轉(zhuǎn)變?yōu)閕ndex:
In [76]: obj = pd.Series(range(3), index=['a', 'b', 'c'])
In [77]: index = obj.index
In [78]: index
Out[78]: Index(['a', 'b', 'c'], dtype='object')
In [79]: index[1:]
Out[79]: Index(['b', 'c'], dtype='object')
index object是不可更改的:
In [3]: obj = pd.Series(range(3), index=['a', 'b', 'c'])
In [4]: index = obj.index
In [5]: index[1] = 'd'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-a452e55ce13b> in <module>()
----> 1 index[1] = 'd'
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in __setitem__(self, key, value)
2063
2064 def __setitem__(self, key, value):
-> 2065 raise TypeError("Index does not support mutable operations")
2066
2067 def __getitem__(self, key):
TypeError: Index does not support mutable operations
正因?yàn)椴豢尚薷模詃ata structure中分享index object是很安全的:
In [80]: labels = pd.Index(np.arange(3))
In [81]: labels
Out[81]: Int64Index([0, 1, 2], dtype='int64')
In [82]: obj2 = pd.Series([1.5, -2.5, 0], index=labels)
In [83]: obj2
Out[83]:
0 1.5
1 -2.5
2 0.0
dtype: float64
In [84]: obj2.index is labels
Out[84]: True
注意:雖然用戶不需要經(jīng)常使用Index的功能甚负,但是因?yàn)橐恍┎僮鲿?huì)生成包含被索引化的數(shù)據(jù)柬焕,理解它們的工作原理是很重要的。
index除了像數(shù)組梭域,還能像大小一定的set——set是一個(gè)無(wú)序且不重復(fù)的元素集合斑举。(除了類(lèi)似于數(shù)組,Index的功能也類(lèi)似一個(gè)固定大小的集合:
In [85]: frame3
Out[85]:
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
In [86]: frame3.columns
Out[86]: Index(['Nevada', 'Ohio'], dtype='object', name='state')
In [87]: 'Ohio' in frame3.columns
Out[87]: True
In [88]: 2003 in frame3.index
Out[88]: False
與python里的set不同病涨,pandas的index可以有重復(fù)的labels:
In [89]: dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])
In [90]: dup_labels
Out[90]: Index(['foo', 'foo', 'bar', 'bar'], dtype='object')
在這種重復(fù)的標(biāo)簽中選擇的話富玷,會(huì)選中所有相同的標(biāo)簽。
Index還有一些方法和屬性: