5.2 pandas的基本功能

本節(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)算符仍然可用,但并不推薦。

表5-4 DataFrame的索引選項(xiàng).png

整數(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
表5-5 算術(shù)方法.png

與此類似,在對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
表5-6 排名時用于破壞平級關(guān)系的方法.png

筆記:
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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容