本節(jié)中,我將介紹操作Series和DataFrame中的數(shù)據(jù)的基本手段。后續(xù)章節(jié)將更加深入地挖掘pandas在數(shù)據(jù)分析和處理方面的功能。本書不是pandas庫的詳盡文檔,主要關(guān)注的是最重要的功能。
重新索引
pandas對象的一個重要方法是reindex,其作用是創(chuàng)建一個新對象,它的數(shù)據(jù)符合新的索引??聪旅娴睦樱?/p>
In [91]: obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
In [92]: obj
Out[92]:
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
用該Series的reindex將會根據(jù)新索引進(jìn)行重排。如果某個索引值當(dāng)前不存在,就引入缺失值:
In [93]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
In [94]: obj2
Out[94]:
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
對于時間序列這樣的有序數(shù)據(jù),重新索引時可能需要做一些插值處理。method選項(xiàng)即可達(dá)到此目的,例如,使用ffill可以實(shí)現(xiàn)前向值填充:
In [95]: obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
In [96]: obj3
Out[96]:
0 blue
2 purple
4 yellow
dtype: object
In [97]: obj3.reindex(range(6), method='ffill')
Out[97]:
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object
借助DataFrame,reindex可以修改(行)索引和列。只傳遞一個序列時,會重新索引結(jié)果的行:
In [98]: frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
....: index=['a', 'c', 'd'],
....: columns=['Ohio', 'Texas', 'California'])
In [99]: frame
Out[99]:
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
In [100]: frame2 = frame.reindex(['a', 'b', 'c', 'd'])
In [101]: frame2
Out[101]:
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關(guān)鍵字重新索引:
In [102]: states = ['Texas', 'Utah', 'California']
In [103]: frame.reindex(columns=states)
Out[103]:
Texas Utah California
a 1 NaN 2
c 4 NaN 5
d 7 NaN 8
表5-3列出了reindex函數(shù)的各參數(shù)及說明。

丟棄指定軸上的項(xiàng)
丟棄某條軸上的一個或多個項(xiàng)很簡單,只要有一個索引數(shù)組或列表即可。由于需要執(zhí)行一些數(shù)據(jù)整理和集合邏輯,所以drop方法返回的是一個在指定軸上刪除了指定值的新對象:
In [105]: obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
In [106]: obj
Out[106]:
a 0.0
b 1.0
c 2.0
d 3.0
e 4.0
dtype: float64
In [107]: new_obj = obj.drop('c')
In [108]: new_obj
Out[108]:
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
In [109]: obj.drop(['d', 'c'])
Out[109]:
a 0.0
b 1.0
e 4.0
dtype: float64
對于Dataframe,可以刪除任意軸上的索引值。為了演示,先新建一個Dataframe例子:
In [110]: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
.....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
.....: columns=['one', 'two', 'three', 'four'])
In [111]: data
Out[111]:
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
用標(biāo)簽序列調(diào)用drop會從行標(biāo)簽(axis=0)刪除值:
In [112]: data.drop(['Colorado', 'Ohio'])
Out[112]:
one two three four
Utah 8 9 10 11
New York 12 13 14 15
通過傳遞axis=1或axis='columns'可以刪除列的值:
In [113]: data.drop('two', axis=1)
Out[113]:
one three four
Ohio 0 2 3
Colorado 4 6 7
Utah 8 10 11
New York 12 14 15
In [114]: data.drop(['two', 'four'], axis='columns')
Out[114]:
one three
Ohio 0 2
Colorado 4 6
Utah 8 10
New York 12 14
許多函數(shù),比如drop,會修改Series或DataFrame的大小或形狀,可以就地修改對象,不會返回新的對象:
In [115]: obj.drop('c', inplace=True)
In [116]: obj
Out[116]:
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
小心使用inplace,它會銷毀所有被刪除的數(shù)據(jù)。
索引、選取和過濾
Series索引(obj[...])的工作方式類似于Numpy數(shù)組的索引,只不過Series的索引值不只是整數(shù)。下面是幾個例子:
In [117]: obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
In [118]: obj
Out[118]:
a 0.0
b 1.0
c 2.0
d 3.0
dtype: float64
In [119]: obj['b']
Out[119]: 1.0
In [120]: obj[1]
Out[120]: 1.0
In [121]: obj[2:4]
Out[121]:
c 2.0
d 3.0
dtype: float64
In [122]: obj[['b', 'a', 'd']]
Out[122]:
b 1.0
a 0.0
d 3.0
dtype: float64
In [123]: obj[[1, 3]]
Out[123]:
b 1.0
d 3.0
dtype: float64
In [124]: obj[obj < 2]
Out[124]:
a 0.0
b 1.0
dtype: float64
利用標(biāo)簽的切片運(yùn)算與普通的Python切片運(yùn)算不同,其末端是包含的:
In [125]: obj['b':'c']
Out[125]:
b 1.0
c 2.0
dtype: float64
用切片可以對Series的相應(yīng)部分進(jìn)行設(shè)置:
In [126]: obj['b':'c'] = 5
In [127]: obj
Out[127]:
a 0.0
b 5.0
c 5.0
d 3.0
dtype: float64
用一個值或序列對DataFrame進(jìn)行索引其實(shí)就是獲取一個或多個列:
In [128]: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
.....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
.....: columns=['one', 'two', 'three', 'four'])
In [129]: data
Out[129]:
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 [130]: data['two']
Out[130]:
Ohio 1
Colorado 5
Utah 9
New York 13
Name: two, dtype: int64
In [131]: data[['three', 'one']]
Out[131]:
three one
Ohio 2 0
Colorado 6 4
Utah 10 8
New York 14 12
這種索引方式有幾個特殊的情況。首先通過切片或布爾型數(shù)組選取數(shù)據(jù):
In [132]: data[:2]
Out[132]:
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
In [133]: data[data['three'] > 5]
Out[133]:
one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
選取行的語法data[:2]十分方便。向[]傳遞單一的元素或列表,就可選擇列。
另一種用法是通過布爾型DataFrame(比如下面這個由標(biāo)量比較運(yùn)算得出的)進(jìn)行索引:
In [134]: data < 5
Out[134]:
one two three four
Ohio True True True True
Colorado True False False False
Utah False False False False
New York False False False False
In [135]: data[data < 5] = 0
In [136]: data
Out[136]:
one two three four
Ohio 0 0 0 0
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
這使得DataFrame的語法與Numpy二維數(shù)組的語法很像。
用loc和iloc進(jìn)行選取
對于DataFrame的行的標(biāo)簽索引,我引入了特殊的標(biāo)簽運(yùn)算符loc和iloc。它們可以讓你用類似Numpy的標(biāo)記,使用軸標(biāo)簽(loc)或整數(shù)索引(iloc),從DataFrame選擇行和列的子集。
作為一個初步示例,讓我們通過標(biāo)簽選擇一行和多列:
In [137]: data.loc['Colorado', ['two', 'three']]
Out[137]:
two 5
three 6
Name: Colorado, dtype: int64
然后用iloc和整數(shù)進(jìn)行選?。?/p>
In [138]: data.iloc[2, [3, 0, 1]]
Out[138]:
four 11
one 8
two 9
Name: Utah, dtype: int64
In [139]: data.iloc[2]
Out[139]:
one 8
two 9
three 10
four 11
Name: Utah, dtype: int64
In [140]: data.iloc[[1, 2], [3, 0, 1]]
Out[140]:
four one two
Colorado 7 0 5
Utah 11 8 9
這兩個索引函數(shù)也適用于一個標(biāo)簽或多個標(biāo)簽的切片:
In [141]: data.loc[:'Utah', 'two']
Out[141]:
Ohio 0
Colorado 5
Utah 9
Name: two, dtype: int64
In [142]: data.iloc[:, :3][data.three > 5]
Out[142]:
one two three
Colorado 0 5 6
Utah 8 9 10
New York 12 13 14
所以,在pandas中,有多個方法可以選取和重新組合數(shù)據(jù)。對于DataFrame,表5-4進(jìn)行了總結(jié)。后面會看到,還有更多的方法進(jìn)行層級化索引。
筆記:在一開始設(shè)計(jì)pandas時,我覺得用DataFrame[:, col]選取列過于繁瑣(也容易出錯),因?yàn)榱械倪x擇是非常常見的操作。我做了些取舍,將花式索引的功能(標(biāo)簽和整數(shù))放到了ix運(yùn)算符中。在實(shí)踐中,這會導(dǎo)致許多邊緣情況,數(shù)據(jù)的軸標(biāo)簽是整數(shù),所以pandas團(tuán)隊(duì)決定創(chuàng)造loc和iloc運(yùn)算符分別處理嚴(yán)格基于標(biāo)簽和整數(shù)的索引。
ix運(yùn)算符仍然可用,但并不推薦。

整數(shù)索引
處理整數(shù)索引的pandas對象常常難住新手,因?yàn)樗cpandas內(nèi)置的列表和元祖的索引語法不同。例如,你可能不認(rèn)為下面的代碼會出錯:
ser = pd.Series(np.arange(3.))
ser
ser[-1]
這里,pandas可以勉強(qiáng)進(jìn)行整數(shù)索引,但是會導(dǎo)致小bug。我們有包含0,1,2的索引,但是引用用戶想要的東西(基于標(biāo)簽或位置的索引)很難:
In [144]: ser
Out[144]:
0 0.0
1 1.0
2 2.0
dtype: float64
另外,對于非整數(shù)索引,不會產(chǎn)生歧義:
In [145]: ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c'])
In [146]: ser2[-1]
Out[146]: 2.0
為了進(jìn)行統(tǒng)一,如果軸索引含有整數(shù),數(shù)據(jù)選取總會使用標(biāo)簽。為了更準(zhǔn)確,請使用loc(標(biāo)簽)或iloc(整數(shù)):
In [147]: ser[:1]
Out[147]:
0 0.0
dtype: float64
In [148]: ser.loc[:1]
Out[148]:
0 0.0
1 1.0
dtype: float64
In [149]: ser.iloc[:1]
Out[149]:
0 0.0
dtype: float64
算術(shù)運(yùn)算和數(shù)據(jù)對齊
pandas最重要的一個功能是,它可以對不同索引的對象進(jìn)行算術(shù)運(yùn)算。在將對象相加時,如果存在不同的索引對,則結(jié)果的索引就是該索引對的并集。對于有數(shù)據(jù)庫經(jīng)驗(yàn)的用戶,這就像在索引標(biāo)簽上進(jìn)行自動外連接??匆粋€簡單的例子:
In [150]: s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
In [151]: s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1],
.....: index=['a', 'c', 'e', 'f', 'g'])
In [152]: s1
Out[152]:
a 7.3
c -2.5
d 3.4
e 1.5
dtype: float64
In [153]: s2
Out[153]:
a -2.1
c 3.6
e -1.5
f 4.0
g 3.1
dtype: float64
將它們相加就會產(chǎn)生:
In [154]: s1 + s2
Out[154]:
a 5.2
c 1.1
d NaN
e 0.0
f NaN
g NaN
dtype: float64
自動的數(shù)據(jù)對齊操作在不重疊的索引處引入了NA值。缺失值會在算術(shù)運(yùn)算過程中傳播。
對于DataFrame,對齊操作會同時發(fā)生在行和列上:
In [155]: df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'),
.....: index=['Ohio', 'Texas', 'Colorado'])
In [156]: df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'),
.....: index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [157]: df1
Out[157]:
b c d
Ohio 0.0 1.0 2.0
Texas 3.0 4.0 5.0
Colorado 6.0 7.0 8.0
In [158]: df2
Out[158]:
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
把它們相加后將會返回一個新的DataFrame,其索引和列為原來那兩個DataFrame的并集:
In [159]: df1 + df2
Out[159]:
b c d e
Colorado NaN NaN NaN NaN
Ohio 3.0 NaN 6.0 NaN
Oregon NaN NaN NaN NaN
Texas 9.0 NaN 12.0 NaN
Utah NaN NaN NaN NaN
因?yàn)椤甤’和‘e’列均不在兩個DataFrame對象中,在結(jié)果中以缺省值呈現(xiàn)。行也是同樣。
如果DataFrame對象相加,沒有共用的列或行標(biāo)簽,結(jié)果都會是空:
In [160]: df1 = pd.DataFrame({'A': [1, 2]})
In [161]: df2 = pd.DataFrame({'B': [3, 4]})
In [162]: df1
Out[162]:
A
0 1
1 2
In [163]: df2
Out[163]:
B
0 3
1 4
In [164]: df1 - df2
Out[164]:
A B
0 NaN NaN
1 NaN NaN
在算術(shù)方法中填充值
在對不同索引的對象進(jìn)行算術(shù)運(yùn)算時,你可能希望當(dāng)一個對象中某個軸標(biāo)簽在另一個對象中找不到時填充一個特殊值(比如0):
In [165]: df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)),
.....: columns=list('abcd'))
In [166]: df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)),
.....: columns=list('abcde'))
In [167]: df2.loc[1, 'b'] = np.nan
In [168]: df1
Out[168]:
a b c d
0 0.0 1.0 2.0 3.0
1 4.0 5.0 6.0 7.0
2 8.0 9.0 10.0 11.0
In [169]: df2
Out[169]:
a b c d e
0 0.0 1.0 2.0 3.0 4.0
1 5.0 NaN 7.0 8.0 9.0
2 10.0 11.0 12.0 13.0 14.0
3 15.0 16.0 17.0 18.0 19.0
當(dāng)它們相加時,沒有重疊的位置就會產(chǎn)生NA值:
In [170]: df1 + df2
Out[170]:
a b c d e
0 0.0 2.0 4.0 6.0 NaN
1 9.0 NaN 13.0 15.0 NaN
2 18.0 20.0 22.0 24.0 NaN
3 NaN NaN NaN NaN NaN
使用df1的add方法,傳入df2以及一個fill_value參數(shù):
In [171]: df1.add(df2, fill_value=0)
Out[171]:
a b c d e
0 0.0 2.0 4.0 6.0 4.0
1 9.0 5.0 13.0 15.0 9.0
2 18.0 20.0 22.0 24.0 14.0
3 15.0 16.0 17.0 18.0 19.0
表5-5列出了Series和DataFrame的算術(shù)方法。它們每個都有一個副本,以字母r開頭,它會翻轉(zhuǎn)參數(shù)。因此這兩個語句是等價的:
In [172]: 1 / df1
Out[172]:
a b c d
0 inf 1.000000 0.500000 0.333333
1 0.250000 0.200000 0.166667 0.142857
2 0.125000 0.111111 0.100000 0.090909
In [173]: df1.rdiv(1)
Out[173]:
a b c d
0 inf 1.000000 0.500000 0.333333
1 0.250000 0.200000 0.166667 0.142857
2 0.125000 0.111111 0.100000 0.090909

與此類似,在對Series或DataFrame重新索引時,也可以指定一個填充值:
In [174]: df1.reindex(columns=df2.columns, fill_value=0)
Out[174]:
a b c d e
0 0.0 1.0 2.0 3.0 0
1 4.0 5.0 6.0 7.0 0
2 8.0 9.0 10.0 11.0 0
DataFrame和Series之間的運(yùn)算
跟不同維度的Numpy數(shù)組一樣,DataFrame和Series之間算術(shù)運(yùn)算也是有明確規(guī)定的。先來看一個具有啟發(fā)性的例子,計(jì)算一個二維數(shù)組與其某行之間的差:
In [175]: arr = np.arange(12.).reshape((3, 4))
In [176]: arr
Out[176]:
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
In [177]: arr[0]
Out[177]: array([ 0., 1., 2., 3.])
In [178]: arr - arr[0]
Out[178]:
array([[ 0., 0., 0., 0.],
[ 4., 4., 4., 4.],
[ 8., 8., 8., 8.]])
當(dāng)我們從arr減去arr[0],每一行都會執(zhí)行這個操作。這就叫做廣播(broadcasting),附錄A將對此進(jìn)行詳細(xì)講解。DataFrame和Series之間的運(yùn)算差不多也是如此:
In [179]: frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
.....: columns=list('bde'),
.....: index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [180]: series = frame.iloc[0]
In [181]: frame
Out[181]:
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
In [182]: series
Out[182]:
b 0.0
d 1.0
e 2.0
Name: Utah, dtype: float64
默認(rèn)情況下,DataFrame和Series之間的算術(shù)運(yùn)算會將Series的索引匹配到DataFrame的列,然后沿著行一直向下廣播:
In [183]: frame - series
Out[183]:
b d e
Utah 0.0 0.0 0.0
Ohio 3.0 3.0 3.0
Texas 6.0 6.0 6.0
Oregon 9.0 9.0 9.0
如果某個索引值在DataFrame的列或Series的索引中找不到,則參與運(yùn)算的兩個對象就會被重新索引以形成并集:
In [184]: series2 = pd.Series(range(3), index=['b', 'e', 'f'])
In [185]: frame + series2
Out[185]:
b d e f
Utah 0.0 NaN 3.0 NaN
Ohio 3.0 NaN 6.0 NaN
Texas 6.0 NaN 9.0 NaN
Oregon 9.0 NaN 12.0 NaN
注意:這種情況,使用
frame.add(series2, fill_value=0)會報錯。
如果你希望匹配行且在列上廣播,則必須使用算術(shù)運(yùn)算方法。例如:
In [186]: series3 = frame['d']
In [187]: frame
Out[187]:
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
In [188]: series3
Out[188]:
Utah 1.0
Ohio 4.0
Texas 7.0
Oregon 10.0
Name: d, dtype: float64
In [189]: frame.sub(series3, axis='index')
Out[189]:
b d e
Utah -1.0 0.0 1.0
Ohio -1.0 0.0 1.0
Texas -1.0 0.0 1.0
Oregon -1.0 0.0 1.0
傳入的軸號就是希望匹配的軸。在本例中,我們的目的時匹配DataFrame的行索引(axis='index' or axis=0)并進(jìn)行廣播。
函數(shù)應(yīng)用和映射
Numpy的ufuncs(元素級數(shù)組方法)也可用于操作pandas對象:
In [190]: frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'),
.....: index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [191]: frame
Out[191]:
b d e
Utah -0.204708 0.478943 -0.519439
Ohio -0.555730 1.965781 1.393406
Texas 0.092908 0.281746 0.769023
Oregon 1.246435 1.007189 -1.296221
In [192]: np.abs(frame)
Out[192]:
b d e
Utah 0.204708 0.478943 0.519439
Ohio 0.555730 1.965781 1.393406
Texas 0.092908 0.281746 0.769023
Oregon 1.246435 1.007189 1.296221
另一個常見的操作是,將函數(shù)應(yīng)用到由各列或行所形成的一堆數(shù)組上。DataFrame的apply方法即可實(shí)現(xiàn)此功能:
In [193]: f = lambda x: x.max() - x.min()
In [194]: frame.apply(f)
Out[194]:
b 1.802165
d 1.684034
e 2.689627
dtype: float64
這里的函數(shù)f,計(jì)算了一個Series的最大值和最小值的差,在frame的每列都執(zhí)行了一次。結(jié)果是一個Series,使用frame的列作為索引。
如果傳遞axis='columns' or axis=1到apply,這個函數(shù)將會在每行執(zhí)行:
In [195]: frame.apply(f, axis='columns')
Out[195]:
Utah 0.998382
Ohio 2.521511
Texas 0.676115
Oregon 2.542656
dtype: float64
許多最為常見的數(shù)組統(tǒng)計(jì)功能都被實(shí)現(xiàn)成DataFrame的方法(如sum和mean),因此無需使用apply方法。
傳遞到apply的函數(shù)不是必須返回一個標(biāo)量,還可以返回由多個值組成的Series:
In [196]: def f(x):
.....: return pd.Series([x.min(), x.max()], index=['min', 'max'])
In [197]: frame.apply(f)
Out[197]:
b d e
min -0.555730 0.281746 -1.296221
max 1.246435 1.965781 1.393406
元素級的Python函數(shù)也是可以用的。假如你要得到frame中各個浮點(diǎn)值的格式化字符串,使用applymap即可:
In [198]: format = lambda x: '%.2f' % x
In [199]: frame.applymap(format)
Out[199]:
b d e
Utah -0.20 0.48 -0.52
Ohio -0.56 1.97 1.39
Texas 0.09 0.28 0.77
Oregon 1.25 1.01 -1.30
之所以叫做applymap,是因?yàn)镾eries有一個用于應(yīng)用元素級函數(shù)的map方法:
In [200]: frame['e'].map(format)
Out[200]:
Utah -0.52
Ohio 1.39
Texas 0.77
Oregon -1.30
Name: e, dtype: object
排序和排名
根據(jù)條件對數(shù)據(jù)集排序(sorting)也是一種重要的內(nèi)置運(yùn)算。要對行或列索引進(jìn)行排序(按字典順序),可使用sort_index方法,它將返回一個已排序的新對象:
In [201]: obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])
In [202]: obj.sort_index()
Out[202]:
a 1
b 2
c 3
d 0
dtype: int64
對于DataFrame,則可以根據(jù)任意一個軸上的索引進(jìn)行排序:
In [203]: frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
.....: index=['three', 'one'],
.....: columns=['d', 'a', 'b', 'c'])
In [204]: frame.sort_index()
Out[204]:
d a b c
one 4 5 6 7
three 0 1 2 3
In [205]: frame.sort_index(axis=1)
Out[205]:
a b c d
three 1 2 3 0
one 5 6 7 4
數(shù)據(jù)默認(rèn)是按升序排序的,但也可以降序排序:
In [206]: frame.sort_index(axis=1, ascending=False)
Out[206]:
d c b a
three 0 3 2 1
one 4 7 6 5
若要按值對Series進(jìn)行排序,可使用sort_values方法:
In [207]: obj = pd.Series([4, 7, -3, 2])
In [208]: obj.sort_values()
Out[208]:
2 -3
3 2
0 4
1 7
dtype: int64
在排序時,任何缺失值默認(rèn)都會被放到Series的末尾:
In [209]: obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
In [210]: obj.sort_values()
Out[210]:
4 -3.0
5 2.0
0 4.0
2 7.0
1 NaN
3 NaN
dtype: float64
當(dāng)排序一個DataFrame時,你可能希望根據(jù)一個或多個列中的值進(jìn)行排序。將一個或多個列的名字傳遞給sort_values的by選項(xiàng)即可達(dá)到該目的:
In [211]: frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
In [212]: frame
Out[212]:
a b
0 0 4
1 1 7
2 0 -3
3 1 2
In [213]: frame.sort_values(by='b')
Out[213]:
a b
2 0 -3
3 1 2
0 0 4
1 1 7
要根據(jù)多個列進(jìn)行排序,傳入名稱的列表即可:
In [214]: frame.sort_values(by=['a', 'b'])
Out[214]:
a b
2 0 -3
0 0 4
3 1 2
1 1 7
排名會從1開始一直到數(shù)組中有效數(shù)據(jù)的數(shù)量。接下來介紹Series和DataFrame的rank方法。默認(rèn)情況下,rank是通過“為各組分配一個平均排名”的方式破壞平級關(guān)系的:
In [215]: obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
In [216]: obj.rank()
Out[216]:
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64
rank排序,默認(rèn)升序,從1開始。
也可以根據(jù)值在原數(shù)據(jù)中出現(xiàn)的順序給出排名:
In [217]: obj.rank(method='first')
Out[217]:
0 6.0
1 1.0
2 7.0
3 4.0
4 3.0
5 2.0
6 5.0
dtype: float64
這里,條目0和2沒有使用平均排名6.5,而是被設(shè)成了6和7,因?yàn)閿?shù)據(jù)中標(biāo)簽0位于標(biāo)簽2的前面。也可以按降序進(jìn)行排名:
# Assign tie values the maximum rank in the group
In [218]: obj.rank(ascending=False, method='max')
Out[218]:
0 2.0
1 7.0
2 2.0
3 4.0
4 5.0
5 6.0
6 4.0
dtype: float64
表5-6列出了所有用于破壞平級關(guān)系的method選項(xiàng)。DataFrame可以在行或列上計(jì)算排名:
In [219]: frame = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1],
.....: 'c': [-2, 5, 8, -2.5]})
In [220]: frame
Out[220]:
a b c
0 0 4.3 -2.0
1 1 7.0 5.0
2 0 -3.0 8.0
3 1 2.0 -2.5
In [221]: frame.rank(axis='columns')
Out[221]:
a b c
0 2.0 3.0 1.0
1 1.0 3.0 2.0
2 2.0 1.0 3.0
3 2.0 3.0 1.0

筆記:
min:如果按升序排列,有2個最小值,對應(yīng)的排名分別為1,1;倒數(shù)第二個值對應(yīng)的排名為3
max:如果按升序排列,有2個最小值,對應(yīng)的排名分別為2,2;倒數(shù)第二個值對應(yīng)的排名為3
dense:如果按升序排列,有2個最小值,對應(yīng)的排名分別為1,1;倒數(shù)第二個值對應(yīng)的排名為2
帶有重復(fù)標(biāo)簽的軸索引
直到目前為止,所有范例都是唯一的軸標(biāo)簽(索引值)。雖然很多pandas函數(shù)(如reindex)都要求標(biāo)簽唯一,但這并不是強(qiáng)制性的。我們來看看下面這個簡單的帶有重復(fù)索引值的Series:
In [222]: obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
In [223]: obj
Out[223]:
a 0
a 1
b 2
b 3
c 4
dtype: int64
索引的is_unique屬性可以告訴你它的值是否是唯一的:
In [224]: obj.index.is_unique
Out[224]: False
對于帶有重復(fù)值的索引,數(shù)據(jù)選取的行為將會有些不同。如果某個索引對應(yīng)多個值,則返回一個Series;而對應(yīng)單個值得,則返回一個標(biāo)量值:
In [225]: obj['a']
Out[225]:
a 0
a 1
dtype: int64
In [226]: obj['c']
Out[226]: 4
這樣會使代碼變復(fù)雜,因?yàn)樗饕妮敵鲱愋蜁鶕?jù)標(biāo)簽是否有重復(fù)發(fā)生變化。
對DataFrame的行進(jìn)行索引時也是如此:
In [227]: df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b'])
In [228]: df
Out[228]:
0 1 2
a 0.274992 0.228913 1.352917
a 0.886429 -2.001637 -0.371843
b 1.669025 -0.438570 -0.539741
b 0.476985 3.248944 -1.021228
In [229]: df.loc['b']
Out[229]:
0 1 2
b 1.669025 -0.438570 -0.539741
b 0.476985 3.248944 -1.021228