1. 程式人生 > >第五篇 pandas??

第五篇 pandas??

orm port stat ron 整數 sort 組成 似的 修改列

pandas含有使數據清洗和分析?作變得更快更簡單的數據結構和操作?具。
pandas經常和其它?具?同使?,如數值計算?具NumPy和SciPy,分析庫
statsmodels和scikit-learn,和數據可視化庫matplotlib。pandas
是基於NumPy數組構建的,特別是基於數組的函數和不使?for循環的數據處理。

pandas與NumPy的不同:pandas采?了?量的NumPy編碼?格,不同是pandas是專?為處理表格和混雜數據設計的。?NumPy更適合處理統?的數值數組數據。

從2010年pandas開源以來,pandas逐漸成?為?個?常?的庫,應?於許多真實案例。開發者社區已經有了800個獨?的貢獻者。

pandas導?約定:import pandas as pd
Series和DataFrame?的次數多,可將其引?本地命名空間中會更?便:
from pandas import Series, DataFram

一、pandas的數據結構介紹
兩個主要數據結構:SeriesDataFrame。雖不能解決所有問題,但它們為?多數應?提供了?種可靠的、易於使?的基礎。

1、Series
Series是?種類似於?維數組的對象,它由?組數據(各種NumPy數據類型)以及?組與之相關的數據標簽(即索引)組成。僅由?組數據即可產?最簡單的Series:
obj = pd.Series([4, 7, -5, 3])
obj       # 輸出如下:包含元素索引、元素,以及數據類型
0    4
1    7
2    -5
3   3
dtype: int64
Series的字符串表現形式為:索引在左邊,值在右邊。未指定索引,於是會?動創建?個0到N-1(N為數據的?度)的整數型索引。可通過Series 的values和index

屬性獲取其數組表示形式和索引對象:
obj.values      # 輸出:array([ 4, 7, -5, 3], dtype=int64)
obj.index      # 輸出:RangeIndex(start=0, stop=4, step=1),(like range(4))

通常,希望所創建的Series帶有?個可以對各個數據點進?標記的索引:
obj2 = pd.Series([4, 7, -5, 3], index=[‘d‘, ‘b‘, ‘a‘, ‘c‘])  # 指定行索引
obj2   # 輸出如下:
d    4
b    7
a    -5
c    3
dtype: int64
obj2.index # 輸出:Index([‘d‘, ‘b‘, ‘a‘, ‘c‘], dtype=‘object‘)
與普通NumPy數組相?,你可以通過索引的?式選取Series中的單個或?組值:
obj2[‘a‘]      # 輸出:-5
obj2[‘d‘] = 6    # 設定索引‘d‘的值
obj2[[‘c‘, ‘a‘, ‘d‘]] # 輸出:(註意參數是列表)
c    3
a    -5
d    6
dtype: int64
[‘c‘, ‘a‘, ‘d‘]是索引列表,即使它包含的是字符串?不是整數。

使?NumPy函數或類似NumPy的運算(如根據布爾型數組進?過濾、標量乘法、應?數學函數等)都會保留索引值的鏈接:
obj2[obj2 > 0]     # 輸出:(布爾運算)
d    6
b    7
c    3
dtype: int64
obj2 * 2        # 輸出:(標量乘法)
d    12
b    14
a    -10
c    6
dtype: int64
np.exp(obj2)     # 輸出:(運用於數學函數)
d    403.428793
b    1096.633158
a    0.006738
c    20.085537
dtype: float64

還可以將Series看成是?個定?的有序字典,因為它是索引值到數據值的?個映射。它可以?在許多原本需要字典參數的函數中:
‘b‘ in obj2    # 輸出:True
‘e‘ in obj2    # 輸出:False

如果數據被存放在?個Python字典中,也可以直接通過這個字典來創建Series
sdata = {‘Ohio‘: 35000, ‘Texas‘: 71000, ‘Oregon‘: 16000, ‘Utah‘: 5000}
obj3 = pd.Series(sdata)
obj3        # 輸出:
Ohio    35000
Texas   71000
Oregon  16000
Utah    5000
dtype: int64
如果只傳??個字典,則結果Series中的索引就是原字典的鍵(有序排列)。你可以傳?排好序的字典的鍵以改變順序:
states = [‘California‘, ‘Ohio‘, ‘Oregon‘, ‘Texas‘]
obj4 = pd.Series(sdata, index=states)
obj4        # 輸出:
California    NaN
Ohio      35000.0
Oregon    16000.0
Texas     71000.0
dtype: float64
在這個例?中,sdata中跟states索引相匹配的那3個值會被找出來並放到相應的位置上,但由於"California"所對應的sdata值找不到,所以其結果就為NaN(即“?數字”(not a number),在pandas中,它?於表示缺失或NA值)。因為‘Utah’不在states中,它被從結果中除去。

使?缺失(missing)或NA表示缺失數據。pandas的isnullnotnull函數可?於檢測缺失數據:
pd.isnull(obj4)     # 檢測obj4中哪些數據缺失
California    True
Ohio      False
Oregon    False
Texas     False
dtype: bool
pd.notnull(obj4)     # 檢測obj4中哪些數據不缺失
California    False
Ohio      True
Oregon    True
Texas     True
dtype: bool
Series也有類似的實例?法:
obj4.isnull()       # 檢測obj4中哪些數據缺失,obj4.notnull()方法檢測數據不缺失
California    True
Ohio      False
Oregon    False
Texas     False
dtype: bool

對於許多應???,Series最重要的?個功能是,它會根據運算的索引標簽?動對?數據
obj3      # 輸出:
Ohio      35000
Texas     71000
Oregon    16000
Utah      5000
dtype: int64
obj4      # 輸出:
California    NaN
Ohio      35000.0
Oregon    16000.0
Texas    71000.0
dtype: float64
obj3 + obj4     # 輸出:
California    NaN
Ohio      70000.0
Oregon    32000.0
Texas     142000.0
Utah      NaN
dtype: float64
該功能類似於數據庫的join的操作

Series對象本身及其索引都有?個name屬性,該屬性跟pandas其他的關鍵功能關系?常密切:
obj4.name = ‘population‘     # 設置Series對象本身的name屬性
obj4.index.name = ‘state‘     # 設置Series對象索引的name屬性
obj4      # 輸出如下:
state
California    NaN
Ohio      35000.0
Oregon    16000.0
Texas     71000.0
Name: population, dtype: float64

Series的索引可以通過賦值的?式就地修改:
obj     # obj的原始索引及數據
0    4
1    7
2    -5
3    3
dtype: int64
obj.index = [‘Bob‘, ‘Steve‘, ‘Jeff‘, ‘Ryan‘]   # 修改obj的索引
obj     # obj修改後的索引及數據,輸出如下所示:
Bob    4
Steve    7
Jeff    -5
Ryan    3
dtype: int64

2、DataFrame

DataFrame是?個表格型的數據結構,它含有?組有序的列,每列可以是不同的值類型(數值、字符串、布爾值等)。DataFrame既有?索引也有列索引,它可以被看做由Series組成的字典(共?同?個索引)。DataFrame中的數據是以?個或多個?維塊存放的(?不是列表、字典或別的?維數據結構)。

雖然DataFrame是以?維結構保存數據的,仍可以將其表示為更?維度的數據(層次化索引的表格型結構,這是pandas中許多?級數據處理功能的關鍵要素)。

創建DataFrame的辦法很多,最常?的?種是直接傳??個由等?列表或NumPy數組組成的字典
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)
結果DataFrame會?動加上索引(跟Series?樣),且全部列會被有序排列:
frame      # 輸出如下:
   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對象會以對瀏覽器友好的HTML表格的?式呈現。
對於特別?的DataFrame,head?法會選取前五?:
frame.head()     # 輸出如下:
    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
如果指定了列序列,則DataFrame的列就會按照指定順序進?排列:
pd.DataFrame(data, columns=[‘year‘, ‘state‘, ‘pop‘])
    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
如果傳?的列在數據中找不到,就會在結果中產?缺失值:
frame2 = pd.DataFrame(data, columns=[‘year‘, ‘state‘, ‘pop‘, ‘debt‘],
            index=[‘one‘, ‘two‘, ‘three‘, ‘four‘,‘five‘, ‘six‘])
frame2      # 輸出如下:
     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
frame2.columns     # 輸出: Index([‘year‘, ‘state‘, ‘pop‘, ‘debt‘], dtype=‘object‘)
通過類似字典標記的?式或屬性的?式,可以將DataFrame的列獲取為?個Series:
frame2[‘state‘]     # 通過字典的方式獲取列
one    Ohio
two    Ohio
three   Ohio
four    Nevada
five    Nevada
six    Nevada
Name: state, dtype: object

frame2.year     # 通過屬性的方式獲取
one    2000
two    2001
three   2002
four    2001
five    2002
six    2003
Name: year, dtype: int64
註意:IPython提供了類似屬性的訪問(即frame2.year)和tab補全。frame2[column]適?於任何列的名,但是frame2.column只有在列名是?個合理的Python變量名時才適?。返回的Series擁有原DataFrame相同的索引,且其name屬性也已經被相應地設置好了。

?也可以通過位置或名稱的?式進?獲取,?如?loc屬性
frame2.loc[‘three‘]   # 輸出如下:
year    2002
state    Ohio
pop    3.6
debt    NaN
Name: three, dtype: object

列可以通過賦值的?式進?修改。例如,可以給那個空的"debt"列賦上?個標量值或?組值:
frame2[‘debt‘] = 16.5     # 賦值一個標量值
frame2        # 輸出如下:
     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
frame2[‘debt‘] = np.arange(6.)   # 賦值一組值
frame2        # 輸出如下:
     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

將列表或數組賦值給某個列時,其?度必須跟DataFrame的?度相匹配。如果賦值的是?個Series,就會精確匹配DataFrame的索引,所有的空位都將被填上缺失值:例如:
val = pd.Series([-1.2, -1.5, -1.7], index=[‘two‘, ‘four‘, ‘five‘])
frame2[‘debt‘] = val      # 精確匹配索引
frame2       # 輸出如下:
     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

為不存在的列賦值會創建出?個新列。關鍵字del?於刪除列。作為del的例?,我先添加?個新的布爾值的列,判斷state是否為‘Ohio‘:
frame2[‘eastern‘] = frame2.state == ‘Ohio‘
frame2        # 輸出如下:
     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
註意:不能?frame2.eastern創建新的列。
del?法可以?來刪除這列:
del frame2[‘eastern‘]
frame2.columns     # 輸出:Index([‘year‘, ‘state‘, ‘pop‘, ‘debt‘], dtype=‘object‘)
註意:通過索引?式返回的列只是相應數據的視圖?已,並不是副本。因此,對返回的Series所做的任何就地修改全都會反映到源DataFrame上。通過Series的copy?法即可指定復制列。

另?種常?的數據形式是嵌套字典
pop = {‘Nevada‘: {2001: 2.4, 2002: 2.9}, ‘Ohio‘: {2000: 1.5, 2001: 1.7, 2002: 3.6}}
如果嵌套字典傳給DataFrame,pandas就會被解釋為:外層字典的鍵作為列索引,內層鍵則作為?索引:
frame3 = pd.DataFrame(pop)   # 將字典pop轉換為DataFrame
frame3        # 輸出:
    Nevada   Ohio
2000    NaN    1.5
2001    2.4    1.7
2002    2.9    3.6
也可以使?類似NumPy數組的?法,對DataFrame進?轉置(交換?和列):
frame3.T
      2000   2001   2002
Nevada    NaN    2.4    2.9
Ohio      1.5    1.7    3.6
內層字典的鍵會被合並、排序以形成最終的索引。如果明確指定了索引,則不會這樣:
pd.DataFrame(pop, index=[2001, 2002, 2003])   # 要報錯:AttributeError: ‘list‘ object has no attribute ‘astype‘
frame55 = pd.DataFrame(pop)        # 先將pop數據轉換為DataFrame數據後可指定索引
pd.DataFrame(frame55, index=[2001, 2002, 2003])   # 這樣指定索引排序不會報錯
    Nevada   Ohio
2001    2.4    1.7
2002    2.9    3.6
2003    NaN   NaN

由Series組成的字典差不多也是?樣的?法:
pdata = {‘Ohio‘: frame3[‘Ohio‘][:-1], ‘Nevada‘: frame3[‘Nevada‘][:2]}   # 註意:依次是列標簽,行標簽
pd.DataFrame(pdata)   # 輸出如下:(這裏使用:pd.DataFrame(pdata, index=[2001,2000]),不會報錯)
    Ohio    Nevada
2000    1.5    NaN
2001    1.7    2.4

下面列出了DataFrame構造函數所能接受的各種數據(表5-1):

技術分享圖片

如果設置了DataFrame的index和columns的name屬性,則這些信息也會被顯示出來:
frame3.index.name = ‘year‘; frame3.columns.name = ‘state‘
frame3    # 輸出如下:
state    Nevada   Ohio
year
2000    NaN    1.5
2001    2.4    1.7
2002    2.9    3.6

跟Series?樣,values屬性也會以?維ndarray的形式返回DataFrame中的數據:
frame3.values     # 輸出如下:
array([[nan, 1.5],
   [2.4, 1.7],
   [2.9, 3.6]])

如果DataFrame各列的數據類型不同,則值數組的dtype就會選?能兼容所有列的數據類型:
frame2.values     # 輸出如下:
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)

1、索引對象
pandas的索引對象負責管理軸標簽和其他元數據(?如軸名稱等)。構建Series或DataFrame時,所?到的任何數組或其他序列的標簽都會被轉換成?個Index:
obj = pd.Series(range(3), index=[‘a‘, ‘b‘, ‘c‘])
index = obj.index     # 將obj的索引賦值給另一個變量
index       # 輸出:Index([‘a‘, ‘b‘, ‘c‘], dtype=‘object‘)
index[1:]    # 輸出:Index([‘b‘, ‘c‘], dtype=‘object‘)

Index對象是不可變的,因此?戶不能對其進?修改:
index[1] = ‘d‘   # 提示錯誤:TypeError: Index does not support mutable operations
不可變可以使Index對象在多個數據結構之間安全共享:
labels = pd.Index(np.arange(3))    # 創建一個索引
labels      # 輸出:Int64Index([0, 1, 2], dtype=‘int64‘)
obj2 = pd.Series([1.5, -2.5, 0], index=labels)   # 創建對象時指定索引
obj2      # 輸出可以看出索引是創建時指定的索引
0    1.5
1    -2.5
2    0.0
dtype: float64
obj2.index is labels   # 輸出:True(驗證是否是同一個索引)
雖然Index功能不經常使用,但一些操作會生成包含索引化的數據,理解它的工作原理很重要。

除了類似於數組,Index的功能也類似?個固定??的集合:
frame3    # 先看下面前的frame3的輸出:
state    Nevada   Ohio
year
2000    NaN    1.5
2001    2.4    1.7
2002    2.9    3.6
‘Ohio‘ in frame3.columns   # 輸出:True(判斷是否在列索引)
2003 in frame3.index    # 輸出:False(判斷是否在行索引)

與python的集合不同,pandas的Index可以包含重復的標簽:
dup_labels = pd.Index([‘foo‘, ‘foo‘, ‘bar‘, ‘bar‘])   # 包含重復索引
dup_labels   # 輸出:Index([‘foo‘, ‘foo‘, ‘bar‘, ‘bar‘], dtype=‘object‘)
選擇重復的標簽,會顯示所有的結果。
每個索引都有?些?法和屬性,它們可?於設置邏輯並回答有關該索引所包含的數據的常?問題。下面列出了Index的方法和屬性(表5-2)
技術分享圖片

二、基本功能
下面介紹操作Series和DataFrame中的數據的基本?段。


1、重新索引(reindex)
pandas對象的?個重要?法是reindex,其作?是創建?個新對象,它的數據符合新的索引。例:
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=[‘d‘, ‘b‘,‘a‘, ‘c‘])
obj   # 輸出:
d    4.5
b    7.2
a    -5.3
c    3.6
dtype: float64
?該Series的reindex將會根據新索引進?重排。如果某個索引值當前不存在,就引?缺失值:
obj2 = obj.reindex([‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘])   # 重建索引
obj2     # 輸出:
a    -5.3
b    7.2
c    3.6
d    4.5
e    NaN
dtype: float64

對於時間序列這樣的有序數據,重新索引時可能需要做?些插值處理。method選項即可達到此?的,例如,使?ffill可以實現前向值填充:
obj3 = pd.Series([‘blue‘, ‘purple‘, ‘yellow‘], index=[0, 2, 4])
obj3      # 輸出:
0    blue
2   purple
4    yellow
dtype: object
obj3.reindex(range(6), method=‘ffill‘)   # 輸出如下
0    blue
1    blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object
借助DataFrame,reindex可以修改(?和列)索引。只傳遞?個序列時,會重新索引結果的?:
frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
          index=[‘a‘, ‘c‘, ‘d‘],
          columns=[‘Ohio‘, ‘Texas‘, ‘California‘])
frame    # 輸出:
  Ohio Texas California
a    0    1    2
c    3    4    5
d    6    7    8
frame2 = frame.reindex([‘a‘, ‘b‘, ‘c‘, ‘d‘])   # 只傳遞一個序列,修改行索引
frame2      # 輸出
   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關鍵字重新索引

states = [‘Texas‘, ‘Utah‘, ‘California‘]
frame.reindex(columns=states)    # 指定columns關鍵字,修改列索引
  Texas   Utah California
a    1    NaN    2
c    4    NaN    5
d    7    NaN    8

下面列出了reindex函數的各參數及說明(表5-3)

技術分享圖片

2、丟棄指定軸上的項
丟棄某條軸上的?個或多個項很簡單,只要有?個索引數組或列表即可。由於需要執??些數據整理和集合邏輯,所以drop?法返回的是?個在指定軸上刪除了指定值的新對象:
obj = pd.Series(np.arange(5.), index=[‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘])   # 假設有這個Series序列
obj      # 輸出如下
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64
new_obj = obj.drop(‘c‘)   # 刪除傳入的值,並得到新的Index
new_obj
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64
obj.drop([‘d‘, ‘c‘])      # 刪除傳入的值,註意參數是列表
a    0.0
b    1.0
e    4.0
dtype: float64

對於DataFrame,可以刪除任意軸上的索引值。先新建?個DataFrame例?:
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
          index=[‘Ohio‘, ‘Colorado‘, ‘Utah‘, ‘New York‘],
          columns=[‘one‘, ‘two‘, ‘three‘, ‘four‘])
data    # 輸出如下:
    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
?標簽序列調?drop會從?標簽(axis 0)刪除值:
data.drop([‘Colorado‘, ‘Ohio‘])    # 輸出如下:
    one   two   three   four
Utah    8    9    10    11
New York 12   13    14    15
通過傳遞axis=1或axis=‘columns‘可以刪除列的值:
data.drop(‘two‘, axis=1)    # 輸出如下:
    one  three four
Ohio    0    2    3
Colorado 4    6    7
Utah    8   10    11
New York 12   14    15
data.drop([‘two‘, ‘four‘], axis=‘columns‘)   # 輸出如下:
    one three
Ohio    0    2
Colorado 4    6
Utah    8    10
New York 12   14

許多函數,如drop,會修改Series或DataFrame的??或形狀,可就地修改對象,不會返回新的對象:
obj.drop(‘c‘, inplace=True)   # ??使?inplace,它會銷毀所有被刪除的數據。
obj    # 輸出如下:
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

3、索引、選取和過濾
Series索引(obj[...])的?作?式類似於NumPy數組的索引,只不過Series的索引值不只是整數。例如:
obj = pd.Series(np.arange(4.), index=[‘a‘, ‘b‘, ‘c‘, ‘d‘])
obj   # 輸出如下:
a    0.0
b    1.0
c    2.0
d    3.0
dtype: float64
obj[‘b‘]    # 輸出:1.0
obj[1]    # 輸出:1.0
obj[2:4]    # 輸出如下:
c    2.0
d    3.0
dtype: float64
obj[[‘b‘, ‘a‘, ‘d‘]]   # 輸出如下:
b    1.0
a    0.0
d    3.0
dtype: float64
obj[[1, 3]]      # 輸出如下:(參數是列表)
b    1.0
d    3.0
dtype: float64
obj[obj < 2]    # 輸出如下:(按條件索引,布爾索引)
a    0.0
b    1.0
dtype: float64
利?標簽的切?運算與普通的Python切?運算不同,其末端是包含的:
obj[‘b‘:‘c‘]    # 輸出如下:
b   1.0
c    2.0
dtype: float64
?切?可以對Series的相應部分進?設置
obj[‘b‘:‘c‘] = 5
obj    # 輸出如下:
a    0.0
b    5.0
c    5.0
d    3.0
dtype: float64

??個值或序列對DataFrame進?索引其實就是獲取?個或多個列
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
          index=[‘Ohio‘, ‘Colorado‘, ‘Utah‘, ‘New York‘],
          columns=[‘one‘, ‘two‘, ‘three‘, ‘four‘])
data    # 輸出如下:
    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
data[‘two‘]   # 輸出如下
Ohio    1
Colorado 5
Utah    9
New York 13
Name: two, dtype: int32
data[[‘three‘, ‘one‘]]   # 輸出如下:
    three   one
Ohio    2    0
Colorado 6    4
Utah    10    8
New York 14    12
data[:2]    # 輸出如下:(選取前2行)
    one   two   three four
Ohio    0    1    2    3
Colorado 4    5    6    7
data[data[‘three‘] > 5]   # 輸出如下:(選取滿足條件的行)
    one   two three four
Colorado 4    5    6    7
Utah    8    9   10    11
New York 12   13   14    15
選取?的語法data[:2]?分?便。向[ ]傳遞單?的元素或列表,就可選擇列

另?種?法是通過布爾型DataFrame進?索引:?如下?這個由標量?較運算得出的
data < 5    # 輸出如下:
     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
data[data < 5] = 0   # 輸出如下:(改變滿足條件的值)
data
    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?維數組的語法很像。

4、?loc和iloc進?選取

DataFrame?標簽索引,引?特殊的標簽運算符loc和iloc。它們可以像?類似NumPy的標記,使?軸標簽(loc)或整數索引(iloc),從DataFrame選擇?和列的?集。先看?個初步示例,通過標簽選擇??和多列:
data.loc[‘Colorado‘, [‘two‘, ‘three‘]]   # 選取‘Colorado‘行,和 [‘two‘, ‘three‘]列,輸出如下:
two    5
three    6
Name: Colorado, dtype: int32
然後?iloc和整數進?選取:
data.iloc[2, [3, 0, 1]]    # 輸出如下:
four    11
one    8
two    9
Name: Utah, dtype: int32
data.iloc[2]   # 輸出如下:(選取第三行數據)
one    8
two    9
three   10
four    11
Name: Utah, dtype: int32
data.iloc[[1, 2], [3, 0, 1]]   # 輸出如下:(選取多行和多列)
      four    one two
Colorado    7    0    5
Utah      11    8    9

這兩個索引函數也適?於?個標簽或多個標簽的切?:
data.loc[:‘Utah‘, ‘two‘]     # 輸出如下:
Ohio    0
Colorado 5
Utah    9
Name: two, dtype: int32
data.iloc[:, :3][data.three > 5]   # 輸出如下:(選取滿足多種條件的數據)
      one    two three
Colorado    0    5    6
Utah      8    9    10
New York    12    13   14
在pandas中,有多個?法可以選取和重新組合數據。當然還有更多的方法進行層級化索引。

DataFrame的索引選項如下所示(表5-4):

技術分享圖片

5、整數索引
pandas整數索引與Python內置的列表和元組的索引語法不同
例如,你可能不認為下?的代碼會出錯:
ser = pd.Series(np.arange(3.))
ser   # 輸出如下:
0   0.0
1   1.0
2   2.0
dtype: float64
ser[-1]   # 索引會報錯,KeyError: -1,因為軸索引含有整數
ser有包含0,1,2的索引,但是引??戶想要的東?(基於標簽或位置的索引)很難:

另外,對於?整數索引,不會產?歧義:
ser2 = pd.Series(np.arange(3.), index=[‘a‘, ‘b‘, ‘c‘])
ser2[-1]    # 輸出:2.0
為了進?統?,如果軸索引含有整數,數據選取總會使?標簽。為了更準確,請使?loc(標簽)或iloc(整數)
ser[:1]   # 整數索引,註意看與下面2個索引的區別,輸出如下:
0    0.0
dtype: float64
ser.loc[:1]    # 標簽索引,輸出如下:
0    0.0
1    1.0
dtype: float64
ser.iloc[:1]    # 整數索引,輸出如下:
0    0.0
dtype: float64

6、算術運算和數據對?
pandas最重要的?個功能是,它可以對不同索引的對象進?算術運算在將對象相加時,如果存在不同的索引對,則結果的索引就是該索引對的並集。對於有數據庫經驗的話,這就像在索引標簽上進??動外連接。看?個簡單的例?:
s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=[‘a‘, ‘c‘, ‘d‘, ‘e‘])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1],
        index=[‘a‘, ‘c‘, ‘e‘, ‘f‘, ‘g‘])
s1    # 輸出如下:
a    7.3
c    -2.5
d    3.4
e    1.5
dtype: float64
s2    # 輸出如下:
a    -2.1
c    3.6
e    -1.5
f    4.0
g    3.1
dtype: float64
s1 + s2    # 輸出如下:
a    5.2
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64
?動的數據對?操作在不重疊的索引處引?了NA值。缺失值會在算術運算過程中傳播。

對於DataFrame,對?操作會同時發?在?和列上:
df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list(‘bcd‘), index=[‘Ohio‘, ‘Texas‘, ‘Colorado‘])
df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list(‘bde‘), index=[‘Utah‘, ‘Ohio‘, ‘Texas‘, ‘Oregon‘])
df1    # 輸出如下:
      b     c    d
Ohio    0.0    1.0    2.0
Texas    3.0    4.0    5.0
Colorado 6.0    7.0    8.0
df2    # 輸出如下:
       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的並集:
df1 + df2    # 輸出如下:
        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
因為‘c‘和‘e‘列均不在兩個DataFrame對象中,在結果中以缺省值呈現。?也是同樣。

如果DataFrame對象相加,沒有共?的列或?標簽,結果都會是空
df1 = pd.DataFrame({‘A‘: [1, 2]})
df2 = pd.DataFrame({‘B‘: [3, 4]})
df1    # 輸出如下:
   A
0    1
1    2
df2    # 輸出如下:
   B
0    3
1    4
df1 - df2    # 輸出如下:(沒有共?的列或?標簽,結果都會是空)
    A     B
0   NaN   NaN
1   NaN   NaN

7、在算術?法中填充值
在對不同索引的對象進?算術運算時,你可能希望當?個對象中某個軸標簽在另?個對象中找不到時填充?個特殊值(?如0):
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list(‘abcd‘))
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list(‘abcde‘))
df2.loc[1, ‘b‘] = np.nan
df1    # 輸出如下:
    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
df2    # 輸出如下:
     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
將它們相加時,沒有重疊的位置就會產?NA值:
df1 + df2    # 輸出如下:
    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參數
df1.add(df2, fill_value=0)   # 輸出如下:(參數fill_value指定缺失的話用替代)
     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

下面列出了Series和DataFrame的算術?法。它們每個都有?個副本,以字?r開頭,
它會翻轉參數。因此這兩個語句是等價的:
1 / df1    # 輸出如下:
       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
df1.rdiv(1)    # 輸出如下:
      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的算術?法)(表5-5):

技術分享圖片

與此類似,在對Series或DataFrame重新索引時,也可以指定?個填充值
df1.reindex(columns=df2.columns, fill_value=0)     # 輸出如下:
    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

8、DataFrame和Series之間的運算

DataFrame和Series之間算術運算也是有明確規定的。先來看?個例?,計算?個?維數組與其某?之間的差:
arr = np.arange(12.).reshape((3, 4))
arr    # 輸出如下:
array([[ 0., 1., 2., 3.],
  [ 4., 5., 6., 7.],
  [ 8., 9., 10., 11.]])
arr[0]      # 輸出:array([0., 1., 2., 3.])
arr - arr[0]    # 輸出如下:
array([[0., 0., 0., 0.],
  [4., 4., 4., 4.],
  [8., 8., 8., 8.]])
當從arr減去arr[0],每??都會執?這個操作。這就叫做?播(broadcasting)。DataFrame和Series之間的運算差不多也是如此:
frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list(‘bde‘), index=[‘Utah‘, ‘Ohio‘, ‘Texas‘, ‘Oregon‘])
series = frame.iloc[0]
frame   # 輸出如下:
      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
series    # 輸出如下:
b    0.0
d    1.0
e    2.0
Name: Utah, dtype: float64
默認情況下,DataFrame和Series之間的算術運算會將Series的索引匹配到DataFrame的列,然後沿著??直向下?播:
frame - series   # 輸出如下:
      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的索引中找不到,則參與運算的兩個對象就會被重新索引以形成並集:
series2 = pd.Series(range(3), index=[‘b‘, ‘e‘, ‘f‘])
frame + series2   # 輸出如下:
      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    # 輸出如下:
     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
series3    # 輸出如下:
Utah    1.0
Ohio    4.0
Texas   7.0
Oregon  10.0
Name: d, dtype: float64
frame.sub(series3, axis=‘index‘)    # 輸出如下:
       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)並進??播。

9、函數應?和映射
NumPy的ufuncs(元素級數組?法)也可?於操作pandas對象:
frame = pd.DataFrame(np.random.randn(4, 3), columns=list(‘bde‘), index=[‘Utah‘, ‘Ohio‘, ‘Texas‘, ‘Oregon‘])
frame    # 輸出如下:
         b        d      e
Utah    -0.238758   -1.228157   -0.433499
Ohio    0.281959    0.229944    1.908042
Texas   -1.180401   -0.234310   -0.264257
Oregon  0.635323   -1.248893    1.319811
np.abs(frame)   # 輸出如下:
        b        d       e
Utah    0.238758    1.228157    0.433499
Ohio    0.281959    0.229944    1.908042
Texas   1.180401    0.234310    0.264257
Oregon 0.635323    1.248893    1.319811

另?個常?的操作是,將函數應?到由各列或?所形成的?維數組上。DataFrame的apply?法即可實現此功能:
f = lambda x: x.max() - x.min()
frame.apply(f)   # 輸出如下:
b    1.815723
d    1.478837
e    2.341541
dtype: float64
這?的函數f,計算了?個Series的最?和雖?的差,在frane的每列都執?了?次。結果是?個Series,使?frame的列作為索引。

如果傳遞axis=‘columns‘到apply,這個函數會在每?執?:
frame.apply(f, axis=‘columns‘)   # 輸出如下:
Utah    0.989399
Ohio    1.678098
Texas   0.946090
Oregon   2.568704
dtype: float64
許多常?的數組統計功能都被實現成DataFrame的?法(如sum和mean),因此?需使?apply?法。傳遞到apply的函數不是必須返回?個標量,還可以返回由多個值組成的Series:
def f(x):
  return pd.Series([x.min(), x.max()], index=[‘min‘, ‘max‘])
frame.apply(f)    # 輸出如下:
        b       d       e
min   -1.180401   -1.248893   -0.433499
max   0.635323    0.229944    1.908042

元素級的Python函數也是可以?的。假如你想得到frame中各個浮點值的格式化字符串,使?applymap即可:
format = lambda x: ‘%.2f‘ % x
frame.applymap(format)   # 輸出如下:
      b      d     e
Utah    -0.24    -1.23   -0.43
Ohio    0.28    0.23    1.91
Texas  -1.18    -0.23    -0.26
Oregon  0.64    -1.25    1.32
之所以叫做applymap,是因為Series有?個?於應?元素級函數的map?法
frame[‘e‘].map(format)   # 輸出如下:
Utah    -0.43
Ohio    1.91
Texas   -0.26
Oregon   1.32
Name: e, dtype: object

10、排序和排名
根據條件對數據集排序(sorting)也是?種重要的內置運算。要對?或列索引進?排序(按字典順序),可使?sort_index?法,它將返回?個已排序的新對象:
obj = pd.Series(range(4), index=[‘d‘, ‘a‘, ‘b‘, ‘c‘])
obj.sort_index()    # 輸出如下:
a    1
b    2
c    3
d    0
dtype: int64

對於DataFrame,則可以根據任意?個軸上的索引進?排序:
frame = pd.DataFrame(np.arange(8).reshape((2, 4)), index=[‘three‘, ‘one‘], columns=[‘d‘, ‘a‘, ‘b‘, ‘c‘])
frame.sort_index()    # 輸出如下:(行索引排序)
     d    a    b    c
one    4    5    6    7
three    0    1   2    3
frame.sort_index(axis=1)   # 輸出如下:(指定參數axis=1按列標簽排序)
     a    b    c    d
three    1    2    3    0
one    5    6    7    4
數據默認是按升序排序的,但也可以降序排序:
frame.sort_index(axis=1, ascending=False)   # 輸出如下:(列標簽降序排序)
     d   c    b    a
three    0    3    2   1
one    4    7   6    5

若要按值對Series進?排序,可使?其sort_values?法:
obj = pd.Series([4, 7, -3, 2])
obj.sort_values()     # 輸出如下:
2    -3
3    2
0    4
1    7
dtype: int64
在排序時,任何缺失值默認都會被放到Series的末尾:
obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
obj.sort_values()   # 輸出如下:
4    -3.0
5    2.0
0    4.0
2    7.0
1   NaN
3    NaN
dtype: float64

當排序?個DataFrame時,你可能希望根據?個或多個列中的值進?排序。將?個或多個列的名字傳遞給sort_values的by選項即可達到該?的:
frame = pd.DataFrame({‘b‘: [4, 7, -3, 2], ‘a‘: [0, 1, 0, 1]})
frame.sort_values(by=‘b‘)   # 輸出如下:(對b列排序)
   b    a
2   -3    0
3    2    1
0    4    0
1   7    1
要根據多個列進?排序,傳?名稱的列表即可:
frame.sort_values(by=[‘a‘, ‘b‘])   # 輸出如下:(參數是列表)
   b    a
2   -3    0
0    4    0
3    2    1
1    7    1

排名會從1開始?直到數組中有效數據的數量。接下來介紹Series和DataFrame的rank?法
默認情況下,rank是通過“為各組分配?個平均排名”的?式破壞平級關系的:
obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
obj.rank()    # 輸出如下:
0    6.5
1    1.0
2    6.5
3    4.5
4    3.0
5    2.0
6    4.5
dtype: float64
也可以根據值在原數據中出現的順序給出排名:
obj.rank(method=‘first‘)   # 輸出如下:
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,它們被設成了6和7,因為數據中標簽0位於標簽2的前?。
也可以按降序進?排名:
obj.rank(ascending=False, method=‘max‘)   # 輸出如下:
0    2.0
1    7.0
2    2.0
3    4.0
4    5.0
5    6.0
6    4.0
dtype: float64

DataFrame可以在?或列上計算排名:
frame = pd.DataFrame({‘b‘: [4.3, 7, -3, 2], ‘a‘: [0, 1, 0, 1], ‘c‘: [-2, 5, 8, -2.5]})

frame    # 輸出如下:
    b    a   c
0    4.3    0   -2.0
1    7.0    1    5.0
2   -3.0    0    8.0
3    2.0    1   -2.5
frame.rank(axis=‘columns‘)   # 輸出如下:
    b    a     c
0    3.0    2.0    1.0
1    3.0    1.0    2.0
2    1.0    2.0    3.0
3    3.0    2.0    1.0

下面是所有?於破壞平級關系的method選項(排名時?於破壞平級關系的?法)(表5-6)

技術分享圖片

(未完待續)

第五篇 pandas??