Pandas入門
pandas的數據結構介紹
我們將使用下面的方式導入pandas:
import pandas as pd
from pandas import
Series,
DataFrame
Series
Series是一種類似於一維數組的對象,它由一組數據(各種NumPy數據類型)以及一組與之相關的數據標籤(即索引)組成。由一組數據就可產生最簡單的Series:
In
[6]: obj = pd.Series([4,7,-5,3])
In
[7]: obj
Out[7]:
0
4
1
7
2
-5
3
3
dtype: int64
Series的字元串表現為:索引在左邊,值在右邊。由於沒有為數據指定索引,於是會自動創建一個0到N-1(N為數據的長度)的整數索引。可以通過Series的values和index屬性獲取其數組表示形式和索引對象:
In
[8]: obj.values
Out[8]: array([
4,
7,
-5,
3], dtype=int64)
In
[9]: obj.index
Out[9]:
RangeIndex(start=0, stop=4, step=1)
通常,我們希望創建的Series帶有一個可以對各個數據點進行標記的索引:
In
[10]: obj2 = pd.Series([4,7,-5,3],index=[d,b,a,c])
In
[12]: obj2
Out[12]:
d 4
b 7
a -5
c 3
dtype: int64
與普通NumPy數組相比,可以通過索引的方式選取Series中的單個或一組值:
In
[13]: obj2[a]
Out[13]:
-5
In
[15]: obj2[d]
=
7
In
[18]: obj2[[c,a,d]]
Out[18]:
c 3
a -5
d 7
dtype: int64
NumPy數組運算(如根據布爾型數組進行過濾、標量乘法、應用數學函數等)都會保留索引和值之間的連接:
In
[19]: obj2
Out[19]:
d 7
b 7
a -5
c 3
dtype: int64
In
[21]: obj2[obj2>0]
Out[21]:
d 7
b 7
c 3
dtype: int64
In
[22]: obj2*2
Out[22]:
d 14
b 14
a -10
c 6
dtype: int64
In
[23]: np.exp(obj2)
Out[23]:
d 1096.633158
b 1096.633158
a 0.006738
c 20.085537
dtype: float64
還可以將Series看成是一個定長的有序字典,因為它是索引值到數據值的一個映射。
In
[24]:
b
in obj2
Out[24]:
True
In
[25]:
e
in obj2
Out[25]:
False
如果數據放在一個字典中,也可以通過這個字典來創建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
再看一個例子:
In
[30]: states =
[California,Ohio,Oregon,Texas]
In
[31]: obj4 = pd.Series(sdata,index=states)
In
[32]: obj4
Out[32]:
California
NaN
Ohio
35000.0
Oregon
16000.0
Texas
71000.0
dtype: float64
在這個例子中,sdata跟states索引相匹配的那3個值會被找出來並放到相應的位置上,但由於「California」所對應的sdata值找不到,所以其結果就為NaN(即「非數字」,在pandas中,它用於表示缺失或NA值)。pandas的 isnulll
和 notnull
函數可用於檢測缺失數據:
In
[33]: pd.isnull(obj4)
Out[33]:
California
True
Ohio
False
Oregon
False
Texas
False
dtype:
bool
In
[34]: pd.notnull(obj4)
Out[34]:
California
False
Ohio
True
Oregon
True
Texas
True
dtype:
bool
對於許多應用而言,Series最重要的一個功能是:它在算術運算中會自動對齊不同索引的數據。
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
Series對象本身及其索引都有一個name屬性,該屬性跟pandas其他的關鍵功能關係非常密切:
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的索引可以通過賦值的方式就地修改:
In
[43]: obj.index =
[Bob,Steve,Jeff,Ryan]
In
[44]: obj
Out[44]:
Bob
4
Steve
7
Jeff
-5
Ryan
3
dtype: int64
DataFrame
DataFrame是一個表格型的數據結構,它含有一組有序的列,每列可以是不同的值類型(數值、字元串、布爾值等)。DataFrame既有行索引也有列索引,它可以被看作由Series組成的字典(共用同一個索引)。
構造DataFrame的方法有很多,最常用的一種是直接傳入一個由等長列表或NumPy數組組成的字典:
In
[49]: data =
{state:[Ohio,Ohio,Ohio,Nevada,Nevada],
...:
...:
year:[2000,2001,2002,2001,2002],
...:
...:
pop:[1.5,1.7,3.6,2.4,2.9]}
In
[50]: frame = pd.DataFrame(data)
DataFrame會自動加上索引(和Series一樣),且全部列會被有序排列:
In
[51]: frame
Out[51]:
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
如果指定了列序列,則DataFrame的列就會按照指定順序進行排列:
In
[52]: pd.DataFrame(data,columns=[year,state,pop])
Out[52]:
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
和Series一樣,如果傳入的列在數據中找不到,就會產生NA值:
In
[56]: frame2 = pd.DataFrame(data,columns=[year,state,pop,
...:
debt],index=[one,two,three,four,five])
In
[57]: frame2
Out[57]:
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
In
[58]: frame2.columns
Out[58]:
Index([year,
state,
pop,
debt], dtype=object)
通過類似字典標記的方式或屬性的方式,可以將DataFrame的列獲取為一個Series:
In
[59]: frame2[state]
Out[59]:
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
Name: state, dtype:
object
In
[60]: frame2.year
Out[60]:
one 2000
two 2001
three 2002
four 2001
five 2002
Name: year, dtype: int64
返回的Series擁有原DataFrame相同的索引,且其name屬性也已經被相應地設置好了。行也可以通過位置或名稱地方式進行獲取、比如用索引欄位loc。
In
[62]: frame2.loc[three]
Out[62]:
year 2002
state Ohio
pop 3.6
debt NaN
Name: three, dtype:
object
In
[64]: frame2.iloc[0]
Out[64]:
year 2000
state Ohio
pop 1.5
debt NaN
Name: one, dtype:
object
列可以通過賦值的方式進行修改。例如,我們可以給空的"debt"列賦上一個標量值或一組值:
In
[65]: frame2[debt]
=
16.5
In
[66]: frame2
Out[66]:
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
In
[67]: frame2[debt]
= np.arange(5)
In
[68]: frame2
Out[68]:
year state pop debt
one 2000
Ohio
1.5
0
two 2001
Ohio
1.7
1
three 2002
Ohio
3.6
2
four 2001
Nevada
2.4
3
five 2002
Nevada
2.9
4
將列表或數組賦值給某個列時,其長度必須跟DataFrame的長度相匹配。若賦值的是一個Series,就會精確匹配DataFrame的索引,所有的空位都會被填上缺失值:
In
[71]: val = pd.Series([-1.2,-1.5,-1.7],index=[two,four,five])
In
[72]: frame2[debt]
= val
In
[73]: frame2
Out[73]:
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
為不存在的列賦值會創建出一個新列。關鍵字del用於刪除列:
In
[82]: frame2[eastern]
= frame2.state ==
Ohio
In
[83]: frame2
Out[83]:
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
In
[84]:
del frame2[eastern]
In
[85]: frame2.columns
Out[85]:
Index([year,
state,
pop,
debt], dtype=object)
通過索引方式返回的列是相應數據的視圖,不是副本。
另一種常見的數據形式是嵌套字典:
In
[86]: pop =
{Nevada:{2001:2.4,2002:2.9},
...:
Ohio:{2000:1.5,2001:1.7,2002:3.6}}
In
[87]: frame3 = pd.DataFrame(pop)
In
[88]: frame3
Out[88]:
Nevada
Ohio
2000
NaN
1.5
2001
2.4
1.7
2002
2.9
3.6
外層字典的鍵作為列,內層鍵作為行索引。
由Series組成的字典差不多也是一樣的用法:
In
[95]: pdata =
{Ohio:frame3[Ohio][:-1],
...:
Nevada:frame3[Nevada][:2]}
In
[96]: pd.DataFrame(pdata)
Out[96]:
Nevada
Ohio
2000
NaN
1.5
2001
2.4
1.7
可以輸入給DataFrame構造器的數據:
如果設置了DataFrame的index和columns的name屬性,這些信息也會被顯示出來:
In
[97]: frame3.index.name =
year
In
[98]: frame3.columns.name =
state
In
[99]: frame3
Out[99]:
state Nevada
Ohio
year
2000
NaN
1.5
2001
2.4
1.7
2002
2.9
3.6
跟Series一樣,values屬性也會以二維ndarray的形式返回DataFrame中的數據。
索引對象
pandas的索引對象負責管理軸標籤和其他元數據(比如軸名稱等)。構建Series或DataFrame時,所用到的任何數組或其他序列的標籤都會被轉換成一個Index:
In
[4]: obj = pd.Series(range(3),index=[a,b,c])
In
[5]: index = obj.index
In
[6]: index
Out[6]:
Index([a,
b,
c], dtype=object)
In
[7]: index[1:]
Out[7]:
Index([b,
c], dtype=object)
Index對象時不可修改的,因此用戶不能對其進行修改。
除了長得像數組,Index的功能也類似一個固定大小的集合。
Index的方法和屬性:
基本功能
介紹操作Series和DataFrame中的數據的基本手段。
重新索引
pandas對象的一個重要方法是reindex,其作用是創建一個適應新索引的新對象。
In
[11]: obj = pd.Series([-4.5,7.2,-5.3,3.6],index=[d,b,a,c])
In
[12]: obj
Out[12]:
d -4.5
b 7.2
a -5.3
c 3.6
dtype: float64
In
[13]: obj2 = obj.reindex([a,b,c,d,e])
In
[14]: obj2
Out[14]:
a -5.3
b 7.2
c 3.6
d -4.5
e NaN
dtype: float64
In
[15]: obj.reindex([a,b,c,d,e],fill_value=0)
Out[15]:
a -5.3
b 7.2
c 3.6
d -4.5
e 0.0
dtype: float64
如果某個索引值當前不存在,就引入缺失值。
對於時間序列這樣的有序數據,重新索引時可能需要做一些插值處理,method選項即可達到此目的。
In
[16]: obj3 = pd.Series([blue,purple,yellow],index=[0,2,4])
In
[17]: obj3.reindex(range(6),method=ffill)
Out[17]:
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype:
object
reindex的(插值)method選項:
參數說明ffill或pad前向填充(或搬運)值bfill或backfill後向填充(或搬運)值
對於DataFrame,reindex可以修改(行)索引、列,或兩個都修改。如果僅傳入一個序列則會重新索引行:
In
[25]: frame2 = frame.reindex([a,b,c,d])
In
[26]: frame = pd.DataFrame(np.arange(9).reshape((3,3)),index=[a,c,d],
...: columns=[Ohio,Texas,California])
In
[27]: frame2 = frame.reindex([a,b,c,d])
In
[29]: frame2
Out[29]:
Ohio
Texas
California
a 0.0
1.0
2.0
b NaN
NaN
NaN
c 3.0
4.0
5.0
d 6.0
7.0
8.0
用columns關鍵字即可重新索引列,也可同時對行和列進行重新索引,而插值則只能按行應用(即軸0)。
利用loc的標籤索引功能,重新索引任務可以變得更簡潔:
In
[33]: states =
[Texas,Utah,California]
In
[34]: frame.loc[[a,b,c,d],states]
Out[34]:
Texas
Utah
California
a 1.0
NaN
2.0
b NaN
NaN
NaN
c 4.0
NaN
5.0
d 7.0
NaN
8.0
reindex函數的參數:
丟棄指定軸上的項
丟棄某條軸上一個或多個項很簡單,只要一個索引數組或列表即可。使用drop方法返回的是一個在指定軸上刪除了指定值得新對象:
In
[37]: obj = pd.Series(np.arange(5),index=[a,b,c,d,e])
In
[38]: obj
Out[38]:
a 0
b 1
c 2
d 3
e 4
dtype: int32
In
[39]: new_obj = obj.drop(c)
In
[40]: new_obj
Out[40]:
a 0
b 1
d 3
e 4
dtype: int32
In
[41]: obj.drop([d,c])
Out[41]:
a 0
b 1
e 4
dtype: int32
對於DataFrame,可以刪除任意軸上的索引值:
In
[42]: data = pd.DataFrame(np.arange(16).reshape((4,4)),
...: index=[Ohio,Colorado,Utah,New York],
...: columns=[one,two,three,four])
In
[43]: data
Out[43]:
one two three four
Ohio
0
1
2
3
Colorado
4
5
6
7
Utah
8
9
10
11
New
York
12
13
14
15
In
[44]: data.drop([Colorado,Ohio])
Out[44]:
one two three four
Utah
8
9
10
11
New
York
12
13
14
15
In
[45]: data.drop(two,axis=1)
Out[45]:
one three four
Ohio
0
2
3
Colorado
4
6
7
Utah
8
10
11
New
York
12
14
15
In
[46]: data.drop([two,four],axis=1)
Out[46]:
one three
Ohio
0
2
Colorado
4
6
Utah
8
10
New
York
12
14
函數應用和映射
NumPy的ufuncs(元素級數組方法)也可以用於pandas對象:
In
[254]:frame = pd.DataFrame(np.random.randn(4,3),columns=list(bde),index=[Utah,Ohio,Texas,Oregon])
In
[255]:frame
Out[255]:
b d e
Utah
0.990385
-0.544831
-1.963969
Ohio
1.031441
-0.072482
-1.041419
Texas
-0.152213
1.202226
-2.117903
Oregon
-0.265797
0.199725
1.618044
In
[255]:np.abs(frame)
Out[256]:
b d e
Utah
0.990385
0.544831
1.963969
Ohio
1.031441
0.072482
1.041419
Texas
0.152213
1.202226
2.117903
Oregon
0.265797
0.199725
1.618044
另一個常見的操作是,將函數應用到由列或行形成的一維數組上。DataFrame的apply方法即可實現此功能。
In
[257]:f =
lambda x:x.max()
- x.min()
In
[258]:frame.apply(f)
Out[258]:
b 1.297238
d 1.747057
e 3.735947
dtype: float64
In
[259]:frame.apply(f,axis=1)
Out[259]:
Utah
2.954354
Ohio
2.072860
Texas
3.320129
Oregon
1.883841
dtype: float64
許多常見的數組統計功能都被實現成DataFrame的方法(如sum和mean),因此無需使用apply方法。
除標量值外,傳遞給apply的函數還可以返回由多個值組成的Series:
In
[260]:
def f(x):
...:
return pd.Series([x.max(), x.min()],index=[max,min])
...:
In
[261]: frame.apply(f)
Out[261]:
b d e
max 1.031441
1.202226
1.618044
min -0.265797
-0.544831
-2.117903
元素級Python函數也是可以用的。假如你想得到frame中各個浮點值的格式化字元串,使用applymap即可:
In
[262]: format =
lambda x:
%.2f
% x
In
[263]: frame.applymap(format)
Out[263]:
b d e
Utah
0.99
-0.54
-1.96
Ohio
1.03
-0.07
-1.04
Texas
-0.15
1.20
-2.12
Oregon
-0.27
0.20
1.62
之所以叫applymap是因為Series有一個應用於元素級函數的map方法:
In
[265]: frame[e].map(format)
Out[265]:
Utah
-1.96
Ohio
-1.04
Texas
-2.12
Oregon
1.62
Name: e, dtype:
object
排序和排名
根據條件對數據集排序,要對行或列索引進行排序(按字典排序)可使用sort_index方法,其返回一個已排序的新對象:
In
[266]: obj = pd.Series(np.arange(4),index=[d,a,b,c])
In
[267]: obj
Out[267]:
d 0
a 1
b 2
c 3
dtype: int32
In
[268]: obj.sort_index()
Out[268]:
a 1
b 2
c 3
d 0
dtype: int32
對於DataFrame,則可以根據任意一個軸上的索引進行排序:
In
[273]: frame = pd.DataFrame(np.arange(8).reshape(2,4),index=[three,one],columns=[d,a,b,c])
In
[274]: frame
Out[274]:
d a b c
three 0
1
2
3
one 4
5
6
7
In
[275]: frame.sort_index()
Out[275]:
d a b c
one 4
5
6
7
three 0
1
2
3
In
[276]: frame.sort_index(axis=1)
Out[276]:
a b c d
three 1
2
3
0
one 5
6
7
4
數據默認是按升序排序,但也可以降序排序:
In
[277]: frame.sort_index(axis=1,ascending=False)
Out[277]:
d c b a
three 0
3
2
1
one 4
7
6
5
若要按值對Series進行排序,可使用sort_values方法:
In
[285]: obj = pd.Series([4,7,-3,2])
In
[286]: obj.sort_values()
Out[286]:
2
-3
3
2
0
4
1
7
dtype: int64
排序時,缺失值默認會被放到Series的末尾:
In
[287]: obj = pd.Series([4,7,np.nan,-3,2])
In
[288]: obj.sort_values()
Out[288]:
3
-3.0
4
2.0
0
4.0
1
7.0
2
NaN
dtype: float64
在DataFrame上,你可能希望根據一個或多個列中的值進行排序。將一個或多個列的名字傳給by選項即可達到目的:
In
[289]: frame = pd.DataFrame({b:[4,7,-3,2],a:[0,1,0,1]})
In
[290]: frame
Out[290]:
a b
0
0
4
1
1
7
2
0
-3
3
1
2
In
[291]: frame.sort_values(by=b)
Out[291]:
a b
2
0
-3
3
1
2
0
0
4
1
1
7
要給多個列進行排序,傳入名稱列表即可:
In
[292]: frame.sort_values(by=[a,b])
Out[292]:
a b
2
0
-3
0
0
4
3
1
2
1
1
7
排名(ranking)跟排序關係密切,它會增設一個排名值(從1開始,一直到數組中有效數據的數量)。Series和DataFrame的rank方法。默認情況是通過「為各組分配一個平均排名」的方式破壞平級關係的。
In
[300]: obj = pd.Series([7,-5,7,4,2,0,4])
In
[301]: obj.rank()
Out[301]:
0
6.5
1
1.0
2
6.5
3
4.5
4
3.0
5
2.0
6
4.5
dtype: float64
也可以根據值在原數據中出現的順序給出排名:
In
[304]: obj.rank(method=first)
Out[304]:
0
6.0
1
1.0
2
7.0
3
4.0
4
3.0
5
2.0
6
5.0
dtype: float64
method選項
method說明average默認:在相等分組中,為各個值分配平均排名min使用整個分組的最小排名max使用整個分組的最大排名first按值在原始數據中的出現順序分配排名
帶有重複值的軸索引
雖然許多pandas函數(如reindex)都要求標籤唯一,但並不是強制性的。
In
[306]: obj
Out[306]:
a 0
a 1
b 2
b 3
c 4
dtype: int32
索引的is_unique屬性可以告訴你它的值是否是唯一的:
obj.index.is_unique
Out[307]:
False
對於帶有重複值索引,數據選取的行為將會有些不同。如果某個索引對應多個值,則返回一個Series,而對應單個值得,則返回一個標量值。
In
[308]: obj[a]
Out[308]:
a 0
a 1
dtype: int32
In
[309]: obj[c]
Out[309]:
4
對DataFram的行進行索引亦是如此:
df = pd.DataFrame(np.random.randn(4,3),index=[a,a,b,b])
In
[315]: df
Out[315]:
0
1
2
a 1.003668
-2.084179
0.230573
a 0.405376
0.677472
-0.489013
b 0.674649
0.366657
0.026477
b -1.128948
0.664332
0.792995
In
[316]: df.loc[a]
Out[316]:
0
1
2
a 1.003668
-2.084179
0.230573
a 0.405376
0.677472
-0.489013
匯總和計算描述統計
方法說明count非NA值的數量describe針對Series或各DataFrame列計算匯總統計max,min計算最小值和最大值argmin,argmax計算能夠獲取到最小值和最大值的索引位置(整數)idxmin,idxmax計算能夠獲取到最小值和最大值的索引值quantile計算樣本的分位數(0到1)sum值的總和mean值的平均數median值的算術中位數mad根據平均值計算平均絕對離差var樣本值的方差std樣本值得標準差skew樣本值的偏度(三階矩)kurt樣本值得峰度(四階矩)cumsum樣本值的累計和cummin,cummax樣本值的累計最大值和累計最小值cumprod樣本的累計積diff計算一階差分pct_change計算百分數變化
唯一值、值計數以及成員資格
還有一類方法可以從一維Series的值中抽取信息。以下面這個Series為例:
In
[8]: obj = pd.Series([c,a,d,a,a,b,b,c,c])
第一個函數是 unique
,可以得到Series中的唯一值數組:
In
[9]: uniques = obj.unique()
In
[10]: uniques
Out[10]: array([c,
a,
d,
b], dtype=object)
返回的唯一值是未排序的,需要的話,可以對結果再次進行排序( uniques.sort()
原地排序)。 value_counts()
用於計算一個Series中各值出現的頻率:
In
[13]: obj.value_counts()
Out[13]:
c 3
a 3
b 2
d 1
dtype: int64
value_counts
是一個頂級pandas方法,可用於任何數組或序列:
In
[14]: pd.value_counts(obj.values,sort=False)
Out[14]:
b 2
d 1
a 3
c 3
dtype: int64
最後是 isin
,用於判斷矢量化集合的成員資格,可用於選取Series中或DataFrame列中數據的子集:
In
[18]: mask = obj.isin([b,c])
In
[19]: mask
Out[19]:
0
True
1
False
2
False
3
False
4
False
5
True
6
True
7
True
8
True
dtype:
bool
In
[20]: obj[mask]
Out[20]:
0 c
5 b
6 b
7 c
8 c
dtype:
object
唯一值、值計數、成員資格方法
方法說明isin計算一個表示「Series各值是否包含於傳入的值序列中」的布爾型數組unique計算Series中的唯一值數組,按發現的順序返回value_counts返回一個Series,其索引為唯一值,其值為頻率,按計數值降序排列
有時,你可能希望得到DataFrame中多個相關列的一張柱狀圖,例如:
In
[21]: data = pd.DataFrame({Qu1:[1,3,4,3,4],
...:
Qu2:[2,3,1,2,3],
...:
Qu3:[1,5,2,4,4]})
In
[22]: data
Out[22]:
Qu1
Qu2
Qu3
0
1
2
1
1
3
3
5
2
4
1
2
3
3
2
4
4
4
3
4
將 pandas.value_counts
傳給該DataFrame的apply函數,就會出現:
In
[23]: result = data.apply(pd.value_counts).fillna(0)
In
[24]: result
Out[24]:
Qu1
Qu2
Qu3
1
1.0
1.0
1.0
2
0.0
2.0
1.0
3
2.0
2.0
0.0
4
2.0
0.0
2.0
5
0.0
0.0
1.0
處理缺失數據
pandas使用浮點值NaN(Not a Number)表示浮點和非浮點數組中的缺失數據。它只是一個便於被檢測出來的標記而已:
In
[26]: string_data = pd.Series([aardvark,artichoke,np.nan,avocado])
In
[27]: string_data
Out[27]:
0 aardvark
1 artichoke
2
NaN
3 avocado
dtype:
object
In
[28]: string_data.isnull()
Out[28]:
0
False
1
False
2
True
3
False
dtype:
bool
Python內置的None值也會被當做NA處理:
In
[30]: string_data[0]
=
None
In
[31]: string_data.isnull()
Out[31]:
0
True
1
False
2
True
3
False
dtype:
bool
NA處理方法
方法說明dropna根據各標籤的值中是否存在缺失數據對軸標籤進行過濾,可通過閾值調節對缺失值的容忍度fillna用指定值或者插值法(如ffill或bfill)填充缺失數據isnull返回一個含有布爾值的對象,這些布爾值表示哪些值是缺失值/NA,該對象類型與源類型一樣notnullisnull的否定式
濾除缺失數據
過濾掉缺失數據的辦法由很多種,純手工操作永遠都是一個辦法,但dropna可能會更實用一些。對於一個Series,dropna返回一個僅含非空數據和索引值的Series:
In
[32]:
from numpy import nan as NA
...:
In
[33]: data = pd.Series([1,NA,3.5,NA,7])
In
[34]: data
Out[34]:
0
1.0
1
NaN
2
3.5
3
NaN
4
7.0
dtype: float64
In
[35]: data.dropna()
Out[35]:
0
1.0
2
3.5
4
7.0
dtype: float64
也可以通過布爾型索引達到這個目的:
In
[36]: data[data.notnull()]
Out[36]:
0
1.0
2
3.5
4
7.0
dtype: float64
而對於DataFrame對象,事情就有點複雜了。你可能希望丟棄全NA或含有NA的行或列。 dropna
默認丟棄任何含有缺失值的行:
In
[37]: data = pd.DataFrame([[1,6.5,3],[1,NA,NA],[NA,NA,NA],
...:
[NA,6.5,3]])
In
[38]: cleaned = data.dropna()
In
[39]: cleaned
Out[39]:
0
1
2
0
1.0
6.5
3.0
In
[40]: data
Out[40]:
0
1
2
0
1.0
6.5
3.0
1
1.0
NaN
NaN
2
NaN
NaN
NaN
3
NaN
6.5
3.0
傳入 how=all
將只丟棄全為NA的那些行:
In
[41]: data.dropna(how=all)
Out[41]:
0
1
2
0
1.0
6.5
3.0
1
1.0
NaN
NaN
3
NaN
6.5
3.0
要用這種方式丟棄列,只需傳入axis=1即可:
In
[42]: data[4]
= NA
In
[43]: data
Out[43]:
0
1
2
4
0
1.0
6.5
3.0
NaN
1
1.0
NaN
NaN
NaN
2
NaN
NaN
NaN
NaN
3
NaN
6.5
3.0
NaN
In
[44]: data.dropna(axis=1,how=all)
Out[44]:
0
1
2
0
1.0
6.5
3.0
1
1.0
NaN
NaN
2
NaN
NaN
NaN
3
NaN
6.5
3.0
另一個濾除DataFrame行的問題涉及時間序列數據。假設你只想留下一部分觀測數據,可以用thresh參數實現此目的:
In
[45]: df = pd.DataFrame(np.random.randn(7,3))
In
[46]: df.iloc[:4,1]
= NA
In
[47]: df.iloc[:2,2]
= NA
In
[48]: df
Out[48]:
0
1
2
0
0.104567
NaN
NaN
1
0.518986
NaN
NaN
2
-0.142659
NaN
1.049138
3
-0.384427
NaN
-0.313821
4
0.298793
0.428673
-0.504281
5
-1.708273
0.550135
-0.573248
6
0.939368
0.931789
1.381717
In
[49]: df.dropna(thresh=3)
Out[49]:
0
1
2
4
0.298793
0.428673
-0.504281
5
-1.708273
0.550135
-0.573248
6
0.939368
0.931789
1.381717
填充缺失數據
你可能不想過濾缺失數據(有可能會捨棄與它相關的其他數據),而希望補填那些「空洞」。 fillna
函數就是最主要的函數,通過一個常數調用 fillna
就會將缺失值替換為那個常數值:
In
[52]: df.fillna(0)
Out[52]:
0
1
2
0
0.104567
0.000000
0.000000
1
0.518986
0.000000
0.000000
2
-0.142659
0.000000
1.049138
3
-0.384427
0.000000
-0.313821
4
0.298793
0.428673
-0.504281
5
-1.708273
0.550135
-0.573248
6
0.939368
0.931789
1.381717
若是通過一個字典調用fillna,就可以實現對不同列填充不同的值:
In
[53]: df.fillna({1:0.5,3:-1})
Out[53]:
0
1
2
0
0.104567
0.500000
NaN
1
0.518986
0.500000
NaN
2
-0.142659
0.500000
1.049138
3
-0.384427
0.500000
-0.313821
4
0.298793
0.428673
-0.504281
5
-1.708273
0.550135
-0.573248
6
0.939368
0.931789
1.381717
fillna
默認會返回新對象,也可以對現有對象進行就地修改:
In
[59]: _ = df.fillna(0,inplace=True)
In
[60]: df
Out[60]:
0
1
2
0
0.104567
0.000000
0.000000
1
0.518986
0.000000
0.000000
2
-0.142659
0.000000
1.049138
3
-0.384427
0.000000
-0.313821
4
0.298793
0.428673
-0.504281
5
-1.708273
0.550135
-0.573248
6
0.939368
0.931789
1.381717
對 reindex
有效的那些插值方法也可用於 fillna
:
In
[64]: df = pd.DataFrame(np.random.randn(6,3))
In
[65]: df.iloc[2:,1]
= NA
In
[66]: df.iloc[4:,2]
= NA
In
[67]: df
Out[67]:
0
1
2
0
1.271795
2.199552
0.013219
1
-0.976690
-0.139820
0.084507
2
-0.757627
NaN
-1.986518
3
-0.169319
NaN
0.912791
4
0.488452
NaN
NaN
5
0.870533
NaN
NaN
In
[68]: df.fillna(method=ffill)
Out[68]:
0
1
2
0
1.271795
2.199552
0.013219
1
-0.976690
-0.139820
0.084507
2
-0.757627
-0.139820
-1.986518
3
-0.169319
-0.139820
0.912791
4
0.488452
-0.139820
0.912791
5
0.870533
-0.139820
0.912791
In
[69]: df.fillna(method=ffill,limit=2)
Out[69]:
0
1
2
0
1.271795
2.199552
0.013219
1
-0.976690
-0.139820
0.084507
2
-0.757627
-0.139820
-1.986518
3
-0.169319
-0.139820
0.912791
4
0.488452
NaN
0.912791
5
0.870533
NaN
0.912791
fillna函數的參數
參數說明value用於填充缺失值的標量值或字典對象method插值方式。默認為「ffill」axis待填充的軸,默認axis=0inplace修改調用者而不產生副本limit(對於前向和後向填充)可以連續填充的最大數量
層次化索引
層次化索引是pandas一項重要功能,它使你能在一個軸上擁有多個(兩個以上)索引級別。抽象點說,它使你能以低維度形式處理高緯度數據。先看一個簡單的例子:創建一個Series,並用一個由列表或數組組成列表作為索引。
In
[70]: data = pd.Series(np.random.randn(10),
...: index=[[a,a,a,b,b,b,c,c,d,
...:
d],[1,2,3,1,2,3,1,2,2,3]])
In
[71]: data
Out[71]:
a 1
-0.774308
2
-1.116404
3
0.956191
b 1
-0.744595
2
-1.806086
3
0.471932
c 1
0.989313
2
0.532067
d 2
0.964238
3
0.129724
dtype: float64
這就是帶有MultiIndex索引的Series的格式化輸出形式。索引之間的「間隔」表示「直接使用上面的標籤」:
In
[72]: data.index
Out[72]:
MultiIndex(levels=[[a,
b,
c,
d],
[1,
2,
3]],
labels=[[0,
0,
0,
1,
1,
1,
2,
2,
3,
3],
[0,
1,
2,
0,
1,
2,
0,
1,
1,
2]])
對於也給層次化索引的對象,選取數據子集的操作很簡單:
In
[73]: data[b]
Out[73]:
1
-0.744595
2
-1.806086
3
0.471932
dtype: float64
In
[74]: data[b:c]
Out[74]:
b 1
-0.744595
2
-1.806086
3
0.471932
c 1
0.989313
2
0.532067
dtype: float64
In
[75]: data.loc[[b,d]]
Out[75]:
b 1
-0.744595
2
-1.806086
3
0.471932
d 2
0.964238
3
0.129724
dtype: float64
有時甚至還可以在「內層」中進行選取:
In
[76]: data[:,2]
Out[76]:
a -1.116404
b -1.806086
c 0.532067
d 0.964238
dtype: float64
層次化索引在數據重塑和基於分組的操作(如透視表生成)中扮演著重要的角色。比如說,這段數據可以通過 unstack
方法被重新安排到一個DataFrame中:
In
[78]: data.unstack()
Out[78]:
1
2
3
a -0.774308
-1.116404
0.956191
b -0.744595
-1.806086
0.471932
c 0.989313
0.532067
NaN
d NaN
0.964238
0.129724
unstack
的逆運算是 stack
:
In
[80]: data.unstack().stack()
Out[80]:
a 1
-0.774308
2
-1.116404
3
0.956191
b 1
-0.744595
2
-1.806086
3
0.471932
c 1
0.989313
2
0.532067
d 2
0.964238
3
0.129724
dtype: float64
對於也給DataFrame,每條軸都可以有分層索引:
In
[81]: frame = pd.DataFrame(np.arange(12).reshape(4,3),
...: index=[[a,a,b,b],[1,2,1,2]],
...: columns =
[[Ohio,Ohio,Colorado],
...:
[Green,Red,Green]])
In
[82]: frame
Out[82]:
Ohio
Colorado
Green
Red
Green
a 1
0
1
2
2
3
4
5
b 1
6
7
8
2
9
10
11
各層都可以有名字(可以是字元串,也可以是別的Python對象)。如果指定了名稱,就會顯示在控制台輸出中:
In
[83]: frame.index.names =
[key1,key2]
In
[84]: frame.columns.names =
[state,color]
In
[85]: frame
Out[85]:
state Ohio
Colorado
color Green
Red
Green
key1 key2
a 1
0
1
2
2
3
4
5
b 1
6
7
8
2
9
10
11
有了分部的列索引,就可以輕鬆選取分組:
In
[86]: frame[Ohio]
Out[86]:
color Green
Red
key1 key2
a 1
0
1
2
3
4
b 1
6
7
2
9
10
以及:
In
[88]: frame.loc[a]
Out[88]:
state Ohio
Colorado
color Green
Red
Green
key2
1
0
1
2
2
3
4
5
In
[89]: frame.loc[a,Ohio]
Out[89]:
color Green
Red
key2
1
0
1
2
3
4
可以單獨創建MultiIndex然後復用。上面那個DataFrame中的(分級的)可以這樣創建:
In
[94]:
from pandas import
MultiIndex
In
[95]:
MultiIndex.from_arrays([[Ohio,Ohio,Colorado],
...:
[Green,Red,Green]],names=[state,color])
Out[95]:
MultiIndex(levels=[[Colorado,
Ohio],
[Green,
Red]],
labels=[[1,
1,
0],
[0,
1,
0]],
names=[state,
color])
In
[96]: frame
Out[96]:
state Ohio
Colorado
color Green
Red
Green
key1 key2
a 1
0
1
2
2
3
4
5
b 1
6
7
8
2
9
10
11
重排分級順序
有時,你需要重新調整某條軸上各級別的順序,或根據指定級別上的值對數據進行排序。 swaplevel
接受兩個級別編號或名稱,並返回一個互換了級別的新對象(但數據不會發生變化):
In
[98]: frame.swaplevel(key1,key2)
Out[98]:
state Ohio
Colorado
color Green
Red
Green
key2 key1
1 a 0
1
2
2 a 3
4
5
1 b 6
7
8
2 b 9
10
11
而 sort_index
則根據單個級別中的值對數據進行排序(穩定的)。交換級別時,常常也會用到 sort_index
,這樣最終結果就是有序的了:
In
[104]: frame.sort_index(level=1)
Out[104]:
state Ohio
Colorado
color Green
Red
Green
key1 key2
a 1
0
1
2
b 1
6
7
8
a 2
3
4
5
b 2
9
10
11
In
[105]: frame.swaplevel(0,1).sort_index(level=0)
Out[105]:
state Ohio
Colorado
color Green
Red
Green
key2 key1
1 a 0
1
2
b 6
7
8
2 a 3
4
5
b 9
10
11
根據級別匯總統計
許多對DataFrame和Series的描述和匯總統計都有一個level選項,用於指定在某條軸上求和級別。以上面那個DataFrame為例,我們可以根據行或列上的級別來進行求和,如下所示:
In
[106]: frame
Out[106]:
state Ohio
Colorado
color Green
Red
Green
key1 key2
a 1
0
1
2
2
3
4
5
b 1
6
7
8
2
9
10
11
In
[107]: frame.sum(level=key2)
Out[107]:
state Ohio
Colorado
color Green
Red
Green
key2
1
6
8
10
2
12
14
16
In
[108]: frame.sum(level=color,axis=1)
Out[108]:
color Green
Red
key1 key2
a 1
2
1
2
8
4
b 1
14
7
2
20
10
這其實利用了pandas的groupby功能。
使用DataFrame的列
人們經常想要將DataFrame的一個或多個列當作行索引來用,或者可能希望將行索引變成DataFrame的列,舉個例子:
In
[113]: frame = pd.DataFrame({a:np.arange(7),b:range(7,0,-1),
...:
c:[one,one,one,two,two,two,two],
...:
d:[0,1,2,0,1,2,3]})
In
[114]: frame
Out[114]:
a b c d
0
0
7 one 0
1
1
6 one 1
2
2
5 one 2
3
3
4 two 0
4
4
3 two 1
5
5
2 two 2
6
6
1 two 3
DataFrame的 set_index
函數會將其一個或多個列轉換為行索引,並創建一個新DataFrame:
In
[115]: frame2 = frame.set_index([c,d])
In
[116]: frame2
Out[116]:
a b
c d
one 0
0
7
1
1
6
2
2
5
two 0
3
4
1
4
3
2
5
2
3
6
1
默認情況下,那些列會從DataFrame中移除,但也可以保留下來:
In
[117]: frame.set_index([c,d],drop=False)
Out[117]:
a b c d
c d
one 0
0
7 one 0
1
1
6 one 1
2
2
5 one 2
two 0
3
4 two 0
1
4
3 two 1
2
5
2 two 2
3
6
1 two 3
reset_index
的功能和 set_index
剛好相反,層次化索引的級別會被轉移到列裡面:
In
[119]: frame2.reset_index()
Out[119]:
c d a b
0 one 0
0
7
1 one 1
1
6
2 one 2
2
5
3 two 0
3
4
4 two 1
4
3
5 two 2
5
2
6 two 3
6
1
推薦閱讀:
※擴散方程
※Python有哪些可以做帶約束的二次線性規劃的包?
※如何正確地/有趣地使用Matlab手機版?
※Windows下有什麼辦法提高conda install的速度?
※Python裡面的scipy庫如何計算線性規劃問題呢?