Pandas 是基于 NumPy 的一個非常好用的庫,正如名字一樣,人見人愛。之所以如此,就在于不論是讀取、處理數(shù)據(jù),用它都非常簡單。
Pandas 有兩種自己獨有的基本數(shù)據(jù)結構。讀者應該注意的是,它固然有著兩種數(shù)據(jù)結構,因為它依然是 Python 的一個庫,所以,Python 中有的數(shù)據(jù)類型在這里依然適用,也同樣還可以使用類自己定義數(shù)據(jù)類型。只不過,Pandas 里面又定義了兩種數(shù)據(jù)類型:Series 和 DataFrame,它們讓數(shù)據(jù)操作更簡單了。
以下操作都是基于:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31101.png" alt="" />
為了省事,后面就不在顯示了。并且如果你跟我一樣是使用 ipython notebook,只需要開始引入模塊即可。
Series 就如同列表一樣,一系列數(shù)據(jù),每個數(shù)據(jù)對應一個索引值。比如這樣一個列表:[9, 3, 8],如果跟索引值寫到一起,就是:
data | 9 | 3 | 8 |
---|---|---|---|
index | 0 | 1 | 2 |
這種樣式我們已經(jīng)熟悉了,不過,在有些時候,需要把它豎過來表示:
index | data |
---|---|
0 | 9 |
1 | 3 |
2 | 8 |
上面兩種,只是表現(xiàn)形式上的差別罷了。
Series 就是“豎起來”的 list:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31102.png" alt="" />
另外一點也很像列表,就是里面的元素的類型,由你任意決定(其實是由需要來決定)。
這里,我們實質上創(chuàng)建了一個 Series 對象,這個對象當然就有其屬性和方法了。比如,下面的兩個屬性依次可以顯示 Series 對象的數(shù)據(jù)值和索引:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31103.png" alt="" />
列表的索引只能是從 0 開始的整數(shù),Series 數(shù)據(jù)類型在默認情況下,其索引也是如此。不過,區(qū)別于列表的是,Series 可以自定義索引:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31104.png" alt="" />
http://wiki.jikexueyuan.com/project/start-learning-python/images/31105.png" alt="" />
自定義索引,的確比較有意思。就憑這個,也是必須的。
每個元素都有了索引,就可以根據(jù)索引操作元素了。還記得 list 中的操作嗎?Series 中,也有類似的操作。先看簡單的,根據(jù)索引查看其值和修改其值:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31106.png" alt="" />
這是不是又有點類似 dict 數(shù)據(jù)了呢?的確如此??聪旅婢屠斫饬?。
讀者是否注意到,前面定義 Series 對象的時候,用的是列表,即 Series() 方法的參數(shù)中,第一個列表就是其數(shù)據(jù)值,如果需要定義 index,放在后面,依然是一個列表。除了這種方法之外,還可以用下面的方法定義 Series 對象:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31108.png" alt="" />
現(xiàn)在是否理解為什么前面那個類似 dict 了?因為本來就是可以這樣定義的。
這時候,索引依然可以自定義。Pandas 的優(yōu)勢在這里體現(xiàn)出來,如果自定義了索引,自定的索引會自動尋找原來的索引,如果一樣的,就取原來索引對應的值,這個可以簡稱為“自動對齊”。
http://wiki.jikexueyuan.com/project/start-learning-python/images/31110.png" alt="" />
在 sd 中,只有'python':8000, 'c++':8100, 'c#':4000
,沒有"java",但是在索引參數(shù)中有,于是其它能夠“自動對齊”的照搬原值,沒有的那個"java",依然在新 Series 對象的索引中存在,并且自動為其賦值 NaN
。在 Pandas 中,如果沒有值,都對齊賦給 NaN
。來一個更特殊的:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31109.png" alt="" />
新得到的 Series 對象索引與 sd 對象一個也不對應,所以都是 NaN
。
Pandas 有專門的方法來判斷值是否為空。
http://wiki.jikexueyuan.com/project/start-learning-python/images/31111.png" alt="" />
此外,Series 對象也有同樣的方法:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31112.png" alt="" />
其實,對索引的名字,是可以從新定義的:
http://wiki.jikexueyuan.com/project/start-learning-python/images/31117.png" alt="" />
對于 Series 數(shù)據(jù),也可以做類似下面的運算(關于運算,后面還要詳細介紹):
http://wiki.jikexueyuan.com/project/start-learning-python/images/31107.png" alt="" />
http://wiki.jikexueyuan.com/project/start-learning-python/images/31113.png" alt="" />
上面的演示中,都是在 ipython notebook 中進行的,所以截圖了。在學習 Series 數(shù)據(jù)類型同時了解了 ipyton notebook。對于后面的所有操作,讀者都可以在 ipython notebook 中進行。但是,我的講述可能會在 Python 交互模式中進行。
DataFrame 是一種二維的數(shù)據(jù)結構,非常接近于電子表格或者類似 mysql 數(shù)據(jù)庫的形式。它的豎行稱之為 columns,橫行跟前面的 Series 一樣,稱之為 index,也就是說可以通過 columns 和 index 來確定一個主句的位置。(有人把 DataFrame 翻譯為“數(shù)據(jù)框”,是不是還可以稱之為“筐”呢?向里面裝數(shù)據(jù)嘛。)
http://wiki.jikexueyuan.com/project/start-learning-python/images/31118.png" alt="" />
下面的演示,是在 Python 交互模式下進行,讀者仍然可以在 ipython notebook 環(huán)境中測試。
>>> import pandas as pd
>>> from pandas import Series, DataFrame
>>> data = {"name":["yahoo","google","facebook"], "marks":[200,400,800], "price":[9, 3, 7]}
>>> f1 = DataFrame(data)
>>> f1
marks name price
0 200 yahoo 9
1 400 google 3
2 800 facebook 7
這是定義一個 DataFrame 對象的常用方法——使用 dict 定義。字典的“鍵”("name","marks","price")就是 DataFrame 的 columns 的值(名稱),字典中每個“鍵”的“值”是一個列表,它們就是那一豎列中的具體填充數(shù)據(jù)。上面的定義中沒有確定索引,所以,按照慣例(Series 中已經(jīng)形成的慣例)就是從 0 開始的整數(shù)。從上面的結果中很明顯表示出來,這就是一個二維的數(shù)據(jù)結構(類似 excel 或者 mysql 中的查看效果)。
上面的數(shù)據(jù)顯示中,columns 的順序沒有規(guī)定,就如同字典中鍵的順序一樣,但是在 DataFrame 中,columns 跟字典鍵相比,有一個明顯不同,就是其順序可以被規(guī)定,向下面這樣做:
>>> f2 = DataFrame(data, columns=['name','price','marks'])
>>> f2
name price marks
0 yahoo 9 200
1 google 3 400
2 facebook 7 800
跟 Series 類似的,DataFrame 數(shù)據(jù)的索引也能夠自定義。
>>> f3 = DataFrame(data, columns=['name', 'price', 'marks', 'debt'], index=['a','b','c','d'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/pymodules/python2.7/pandas/core/frame.py", line 283, in __init__
mgr = self._init_dict(data, index, columns, dtype=dtype)
File "/usr/lib/pymodules/python2.7/pandas/core/frame.py", line 368, in _init_dict
mgr = BlockManager(blocks, axes)
File "/usr/lib/pymodules/python2.7/pandas/core/internals.py", line 285, in __init__
self._verify_integrity()
File "/usr/lib/pymodules/python2.7/pandas/core/internals.py", line 367, in _verify_integrity
assert(block.values.shape[1:] == mgr_shape[1:])
AssertionError
報錯了。這個報錯信息就太不友好了,也沒有提供什么線索。這就是交互模式的不利之處。修改之,錯誤在于 index 的值——列表——的數(shù)據(jù)項多了一個,data 中是三行,這里給出了四個項(['a','b','c','d'])。
>>> f3 = DataFrame(data, columns=['name', 'price', 'marks', 'debt'], index=['a','b','c'])
>>> f3
name price marks debt
a yahoo 9 200 NaN
b google 3 400 NaN
c facebook 7 800 NaN
讀者還要注意觀察上面的顯示結果。因為在定義 f3 的時候,columns 的參數(shù)中,比以往多了一項('debt'),但是這項在 data 這個字典中并沒有,所以 debt 這一豎列的值都是空的,在 Pandas 中,空就用 NaN 來代表了。
定義 DataFrame 的方法,除了上面的之外,還可以使用“字典套字典”的方式。
>>> newdata = {"lang":{"firstline":"python","secondline":"java"}, "price":{"firstline":8000}}
>>> f4 = DataFrame(newdata)
>>> f4
lang price
firstline python 8000
secondline java NaN
在字典中就規(guī)定好數(shù)列名稱(第一層鍵)和每橫行索引(第二層字典鍵)以及對應的數(shù)據(jù)(第二層字典值),也就是在字典中規(guī)定好了每個數(shù)據(jù)格子中的數(shù)據(jù),沒有規(guī)定的都是空。
>>> DataFrame(newdata, index=["firstline","secondline","thirdline"])
lang price
firstline python 8000
secondline java NaN
thirdline NaN NaN
如果額外確定了索引,就如同上面顯示一樣,除非在字典中有相應的索引內(nèi)容,否則都是 NaN。
前面定義了 DataFrame 數(shù)據(jù)(可以通過兩種方法),它也是一種對象類型,比如變量 f3 引用了一個對象,它的類型是 DataFrame。承接以前的思維方法:對象有屬性和方法。
>>> f3.columns
Index(['name', 'price', 'marks', 'debt'], dtype=object)
DataFrame 對象的 columns 屬性,能夠顯示素有的 columns 名稱。并且,還能用下面類似字典的方式,得到某豎列的全部內(nèi)容(當然包含索引):
>>> f3['name']
a yahoo
b google
c facebook
Name: name
這是什么?這其實就是一個 Series,或者說,可以將 DataFrame 理解為是有一個一個的 Series 組成的。
一直耿耿于懷沒有數(shù)值的那一列,下面的操作是統(tǒng)一給那一列賦值:
>>> f3['debt'] = 89.2
>>> f3
name price marks debt
a yahoo 9 200 89.2
b google 3 400 89.2
c facebook 7 800 89.2
除了能夠統(tǒng)一賦值之外,還能夠“點對點”添加數(shù)值,結合前面的 Series,既然 DataFrame 對象的每豎列都是一個 Series 對象,那么可以先定義一個 Series 對象,然后把它放到 DataFrame 對象中。如下:
>>> sdebt = Series([2.2, 3.3], index=["a","c"]) #注意索引
>>> f3['debt'] = sdebt
將 Series 對象(sdebt 變量所引用) 賦給 f3['debt']列,Pandas 的一個重要特性——自動對齊——在這里起做用了,在 Series 中,只有兩個索引("a","c"),它們將和 DataFrame 中的索引自動對齊。于是乎:
>>> f3
name price marks debt
a yahoo 9 200 2.2
b google 3 400 NaN
c facebook 7 800 3.3
自動對齊之后,沒有被復制的依然保持 NaN。
還可以更精準的修改數(shù)據(jù)嗎?當然可以,完全仿照字典的操作:
>>> f3["price"]["c"]= 300
>>> f3
name price marks debt
a yahoo 9 200 2.2
b google 3 400 NaN
c facebook 300 800 3.3
這些操作是不是都不陌生呀,這就是 Pandas 中的兩種數(shù)據(jù)對象。
總目錄 | 上節(jié):為計算做準備 | 下節(jié):Pandas 使用 (2)
如果你認為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。