<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 第 5 章 pandas 入門 pandas是本書后續內容的首選庫。它含有使數據清洗和分析工作變得更快更簡單的數據結構和操作工具。pandas經常和其它工具一同使用,如數值計算工具NumPy和SciPy,分析庫statsmodels和scikit-learn,和數據可視化庫matplotlib。pandas是基于NumPy數組構建的,特別是基于數組的函數和不使用for循環的數據處理。 雖然pandas采用了大量的NumPy編碼風格,但二者最大的不同是pandas是專門為處理表格和混雜數據設計的。而NumPy更適合處理統一的數值數組數據。 自從2010年pandas開源以來,pandas逐漸成長為一個非常大的庫,應用于許多真實案例。開發者社區已經有了800個獨立的貢獻者,他們在解決日常數據問題的同時為這個項目提供貢獻。 在本書后續部分中,我將使用下面這樣的pandas引入約定: ```python In [1]: import pandas as pd ``` 因此,只要你在代碼中看到pd.,就得想到這是pandas。因為Series和DataFrame用的次數非常多,所以將其引入本地命名空間中會更方便: ```python In [2]: from pandas import Series, DataFrame ``` # 5.1 pandas的數據結構介紹 要使用pandas,你首先就得熟悉它的兩個主要數據結構:Series和DataFrame。雖然它們并不能解決所有問題,但它們為大多數應用提供了一種可靠的、易于使用的基礎。 ## Series Series是一種類似于一維數組的對象,它由一組數據(各種NumPy數據類型)以及一組與之相關的數據標簽(即索引)組成。僅由一組數據即可產生最簡單的Series: ```python In [11]: obj = pd.Series([4, 7, -5, 3]) In [12]: obj Out[12]: 0 4 1 7 2 -5 3 3 dtype: int64 ``` Series的字符串表現形式為:索引在左邊,值在右邊。由于我們沒有為數據指定索引,于是會自動創建一個0到N-1(N為數據的長度)的整數型索引。你可以通過Series 的values和index屬性獲取其數組表示形式和索引對象: ```python In [13]: obj.values Out[13]: array([ 4, 7, -5, 3]) In [14]: obj.index # like range(4) Out[14]: RangeIndex(start=0, stop=4, step=1) ``` 通常,我們希望所創建的Series帶有一個可以對各個數據點進行標記的索引: ```python In [15]: obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) In [16]: obj2 Out[16]: d 4 b 7 a -5 c 3 dtype: int64 In [17]: obj2.index Out[17]: Index(['d', 'b', 'a', 'c'], dtype='object') ``` 與普通NumPy數組相比,你可以通過索引的方式選取Series中的單個或一組值: ```python In [18]: obj2['a'] Out[18]: -5 In [19]: obj2['d'] = 6 In [20]: obj2[['c', 'a', 'd']] Out[20]: c 3 a -5 d 6 dtype: int64 ``` ['c', 'a', 'd']是索引列表,即使它包含的是字符串而不是整數。 使用NumPy函數或類似NumPy的運算(如根據布爾型數組進行過濾、標量乘法、應用數學函數等)都會保留索引值的鏈接: ```python In [21]: obj2[obj2 > 0] Out[21]: d 6 b 7 c 3 dtype: int64 In [22]: obj2 * 2 Out[22]: d 12 b 14 a -10 c 6 dtype: int64 In [23]: np.exp(obj2) Out[23]: d 403.428793 b 1096.633158 a 0.006738 c 20.085537 dtype: float64 ``` 還可以將Series看成是一個定長的有序字典,因為它是索引值到數據值的一個映射。它可以用在許多原本需要字典參數的函數中: ```python In [24]: 'b' in obj2 Out[24]: True In [25]: 'e' in obj2 Out[25]: False ``` 如果數據被存放在一個Python字典中,也可以直接通過這個字典來創建Series: ```python 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 ``` 如果只傳入一個字典,則結果Series中的索引就是原字典的鍵(有序排列)。你可以傳入排好序的字典的鍵以改變順序: ```python In [29]: states = ['California', 'Ohio', 'Oregon', 'Texas'] In [30]: obj4 = pd.Series(sdata, index=states) In [31]: obj4 Out[31]: 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的isnull和notnull函數可用于檢測缺失數據: ```python In [32]: pd.isnull(obj4) Out[32]: California True Ohio False Oregon False Texas False dtype: bool In [33]: pd.notnull(obj4) Out[33]: California False Ohio True Oregon True Texas True dtype: bool ``` Series也有類似的實例方法: ```python In [34]: obj4.isnull() Out[34]: California True Ohio False Oregon False Texas False dtype: bool ``` 我將在第7章詳細講解如何處理缺失數據。 對于許多應用而言,Series最重要的一個功能是,它會根據運算的索引標簽自動對齊數據: ```python 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 ``` 數據對齊功能將在后面詳細講解。如果你使用過數據庫,你可以認為是類似join的操作。 Series對象本身及其索引都有一個name屬性,該屬性跟pandas其他的關鍵功能關系非常密切: ```python 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的索引可以通過賦值的方式就地修改: ```python In [41]: obj Out[41]: 0 4 1 7 2 -5 3 3 dtype: int64 In [42]: obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] In [43]: obj Out[43]: Bob 4 Steve 7 Jeff -5 Ryan 3 dtype: int64 ``` ## DataFrame DataFrame是一個表格型的數據結構,它含有一組有序的列,每列可以是不同的值類型(數值、字符串、布爾值等)。DataFrame既有行索引也有列索引,它可以被看做由Series組成的字典(共用同一個索引)。DataFrame中的數據是以一個或多個二維塊存放的(而不是列表、字典或別的一維數據結構)。有關DataFrame內部的技術細節遠遠超出了本書所討論的范圍。 >筆記:雖然DataFrame是以二維結構保存數據的,但你仍然可以輕松地將其表示為更高維度的數據(層次化索引的表格型結構,這是pandas中許多高級數據處理功能的關鍵要素,我們會在第8章討論這個問題)。 建DataFrame的辦法有很多,最常用的一種是直接傳入一個由等長列表或NumPy數組組成的字典: ```python 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一樣),且全部列會被有序排列: ```python In [45]: frame Out[45]: 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 5 3.2 Nevada 2003 ``` 如果你使用的是Jupyter notebook,pandas DataFrame對象會以對瀏覽器友好的HTML表格的方式呈現。 對于特別大的DataFrame,head方法會選取前五行: ```python In [46]: frame.head() Out[46]: 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的列就會按照指定順序進行排列: ```python In [47]: pd.DataFrame(data, columns=['year', 'state', 'pop']) Out[47]: 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 ``` 如果傳入的列在數據中找不到,就會在結果中產生缺失值: ```python In [48]: frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], ....: index=['one', 'two', 'three', 'four', ....: 'five', 'six']) In [49]: frame2 Out[49]: 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 In [50]: frame2.columns Out[50]: Index(['year', 'state', 'pop', 'debt'], dtype='object') ``` 通過類似字典標記的方式或屬性的方式,可以將DataFrame的列獲取為一個Series: ```python In [51]: frame2['state'] Out[51]: one Ohio two Ohio three Ohio four Nevada five Nevada six Nevada Name: state, dtype: object In [52]: frame2.year Out[52]: 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屬性(稍后將對此進行詳細講解): ```python In [53]: frame2.loc['three'] Out[53]: year 2002 state Ohio pop 3.6 debt NaN Name: three, dtype: object ``` 列可以通過賦值的方式進行修改。例如,我們可以給那個空的"debt"列賦上一個標量值或一組值: ```python In [54]: frame2['debt'] = 16.5 In [55]: frame2 Out[55]: 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 In [56]: frame2['debt'] = np.arange(6.) In [57]: frame2 Out[57]: 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的索引,所有的空位都將被填上缺失值: ```python In [58]: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five']) In [59]: frame2['debt'] = val In [60]: frame2 Out[60]: 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': ```python In [61]: frame2['eastern'] = frame2.state == 'Ohio' In [62]: frame2 Out[62]: 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方法可以用來刪除這列: ```python In [63]: del frame2['eastern'] In [64]: frame2.columns Out[64]: Index(['year', 'state', 'pop', 'debt'], dtype='object') ``` >注意:通過索引方式返回的列只是相應數據的視圖而已,并不是副本。因此,對返回的Series所做的任何就地修改全都會反映到源DataFrame上。通過Series的copy方法即可指定復制列。 另一種常見的數據形式是嵌套字典: ```python In [65]: pop = {'Nevada': {2001: 2.4, 2002: 2.9}, ....: 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}} ``` 如果嵌套字典傳給DataFrame,pandas就會被解釋為:外層字典的鍵作為列,內層鍵則作為行索引: ```python In [66]: frame3 = pd.DataFrame(pop) In [67]: frame3 Out[67]: Nevada Ohio 2000 NaN 1.5 2001 2.4 1.7 2002 2.9 3.6 ``` 你也可以使用類似NumPy數組的方法,對DataFrame進行轉置(交換行和列): ```python In [68]: frame3.T Out[68]: 2000 2001 2002 Nevada NaN 2.4 2.9 Ohio 1.5 1.7 3.6 ``` 內層字典的鍵會被合并、排序以形成最終的索引。如果明確指定了索引,則不會這樣: ```python In [69]: pd.DataFrame(pop, index=[2001, 2002, 2003]) Out[69]: Nevada Ohio 2001 2.4 1.7 2002 2.9 3.6 2003 NaN NaN ``` 由Series組成的字典差不多也是一樣的用法: ```python In [70]: pdata = {'Ohio': frame3['Ohio'][:-1], ....: 'Nevada': frame3['Nevada'][:2]} In [71]: pd.DataFrame(pdata) Out[71]: Nevada Ohio 2000 NaN 1.5 2001 2.4 1.7 ``` 表5-1列出了DataFrame構造函數所能接受的各種數據。 ![](https://img.kancloud.cn/17/48/1748203442a2301b76bb40f33895cbb6_1075x766.png) 如果設置了DataFrame的index和columns的name屬性,則這些信息也會被顯示出來: ```python In [72]: frame3.index.name = 'year'; frame3.columns.name = 'state' In [73]: frame3 Out[73]: state Nevada Ohio year 2000 NaN 1.5 2001 2.4 1.7 2002 2.9 3.6 ``` 跟Series一樣,values屬性也會以二維ndarray的形式返回DataFrame中的數據: ```python In [74]: frame3.values Out[74]: array([[ nan, 1.5], [ 2.4, 1.7], [ 2.9, 3.6]]) ``` 如果DataFrame各列的數據類型不同,則值數組的dtype就會選用能兼容所有列的數據類型: ```python In [75]: frame2.values Out[75]: 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) ``` ## 索引對象 pandas的索引對象負責管理軸標簽和其他元數據(比如軸名稱等)。構建Series或DataFrame時,所用到的任何數組或其他序列的標簽都會被轉換成一個Index: ```python In [76]: obj = pd.Series(range(3), index=['a', 'b', 'c']) In [77]: index = obj.index In [78]: index Out[78]: Index(['a', 'b', 'c'], dtype='object') In [79]: index[1:] Out[79]: Index(['b', 'c'], dtype='object') ``` Index對象是不可變的,因此用戶不能對其進行修改: ```python index[1] = 'd' # TypeError ``` 不可變可以使Index對象在多個數據結構之間安全共享: ```python In [80]: labels = pd.Index(np.arange(3)) In [81]: labels Out[81]: Int64Index([0, 1, 2], dtype='int64') In [82]: obj2 = pd.Series([1.5, -2.5, 0], index=labels) In [83]: obj2 Out[83]: 0 1.5 1 -2.5 2 0.0 dtype: float64 In [84]: obj2.index is labels Out[84]: True ``` >注意:雖然用戶不需要經常使用Index的功能,但是因為一些操作會生成包含被索引化的數據,理解它們的工作原理是很重要的。 除了類似于數組,Index的功能也類似一個固定大小的集合: ```python In [85]: frame3 Out[85]: state Nevada Ohio year 2000 NaN 1.5 2001 2.4 1.7 2002 2.9 3.6 In [86]: frame3.columns Out[86]: Index(['Nevada', 'Ohio'], dtype='object', name='state') In [87]: 'Ohio' in frame3.columns Out[87]: True In [88]: 2003 in frame3.index Out[88]: False ``` 與python的集合不同,pandas的Index可以包含重復的標簽: ```python In [89]: dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar']) In [90]: dup_labels Out[90]: Index(['foo', 'foo', 'bar', 'bar'], dtype='object') ``` 選擇重復的標簽,會顯示所有的結果。 每個索引都有一些方法和屬性,它們可用于設置邏輯并回答有關該索引所包含的數據的常見問題。表5-2列出了這些函數。 ![](https://img.kancloud.cn/ca/ca/caca4b3f7063067c5812a016e812e9ac_1240x731.jpg) # 5.2 基本功能 本節中,我將介紹操作Series和DataFrame中的數據的基本手段。后續章節將更加深入地挖掘pandas在數據分析和處理方面的功能。本書不是pandas庫的詳盡文檔,主要關注的是最重要的功能,那些不大常用的內容(也就是那些更深奧的內容)就交給你自己去摸索吧。 ## 重新索引 pandas對象的一個重要方法是reindex,其作用是創建一個新對象,它的數據符合新的索引。看下面的例子: ```python 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將會根據新索引進行重排。如果某個索引值當前不存在,就引入缺失值: ```python 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 ``` 對于時間序列這樣的有序數據,重新索引時可能需要做一些插值處理。method選項即可達到此目的,例如,使用ffill可以實現前向值填充: ```python 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可以修改(行)索引和列。只傳遞一個序列時,會重新索引結果的行: ```python 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關鍵字重新索引: ```python 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函數的各參數及說明。 ![](https://img.kancloud.cn/b9/69/b969b4490b6bffbb48c0503d05cb3ac2_1240x569.jpg) ## 丟棄指定軸上的項 丟棄某條軸上的一個或多個項很簡單,只要有一個索引數組或列表即可。由于需要執行一些數據整理和集合邏輯,所以drop方法返回的是一個在指定軸上刪除了指定值的新對象: ```python 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例子: ```python 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 ``` 用標簽序列調用drop會從行標簽(axis 0)刪除值: ```python 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'可以刪除列的值: ```python 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 ``` 許多函數,如drop,會修改Series或DataFrame的大小或形狀,可以就地修改對象,不會返回新的對象: ```python 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,它會銷毀所有被刪除的數據。 ## 索引、選取和過濾 Series索引(obj[...])的工作方式類似于NumPy數組的索引,只不過Series的索引值不只是整數。下面是幾個例子: ```python 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 ``` 利用標簽的切片運算與普通的Python切片運算不同,其末端是包含的: ```python In [125]: obj['b':'c'] Out[125]: b 1.0 c 2.0 dtype: float64 ``` 用切片可以對Series的相應部分進行設置: ```python 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進行索引其實就是獲取一個或多個列: ```python 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 ``` 這種索引方式有幾個特殊的情況。首先通過切片或布爾型數組選取數據: ```python 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(比如下面這個由標量比較運算得出的)進行索引: ```python 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二維數組的語法很像。 ## 用loc和iloc進行選取 對于DataFrame的行的標簽索引,我引入了特殊的標簽運算符loc和iloc。它們可以讓你用類似NumPy的標記,使用軸標簽(loc)或整數索引(iloc),從DataFrame選擇行和列的子集。 作為一個初步示例,讓我們通過標簽選擇一行和多列: ```python In [137]: data.loc['Colorado', ['two', 'three']] Out[137]: two 5 three 6 Name: Colorado, dtype: int64 ``` 然后用iloc和整數進行選取: ```python 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 ``` 這兩個索引函數也適用于一個標簽或多個標簽的切片: ```python 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中,有多個方法可以選取和重新組合數據。對于DataFrame,表5-4進行了總結。后面會看到,還有更多的方法進行層級化索引。 >筆記:在一開始設計pandas時,我覺得用frame[:, col]選取列過于繁瑣(也容易出錯),因為列的選擇是非常常見的操作。我做了些取舍,將花式索引的功能(標簽和整數)放到了ix運算符中。在實踐中,這會導致許多邊緣情況,數據的軸標簽是整數,所以pandas團隊決定創造loc和iloc運算符分別處理嚴格基于標簽和整數的索引。 ix運算符仍然可用,但并不推薦。 ![表5-4 DataFrame的索引選項](https://img.kancloud.cn/5d/d6/5dd6bd1a9dc1c613a4e3921bbb551992_929x566.png) ## 整數索引 處理整數索引的pandas對象常常難住新手,因為它與Python內置的列表和元組的索引語法不同。例如,你可能不認為下面的代碼會出錯: ```python ser = pd.Series(np.arange(3.)) ser ser[-1] ``` 這里,pandas可以勉強進行整數索引,但是會導致小bug。我們有包含0,1,2的索引,但是引入用戶想要的東西(基于標簽或位置的索引)很難: ```python In [144]: ser Out[144]: 0 0.0 1 1.0 2 2.0 dtype: float64 ``` 另外,對于非整數索引,不會產生歧義: ```python In [145]: ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c']) In [146]: ser2[-1] Out[146]: 2.0 ``` 為了進行統一,如果軸索引含有整數,數據選取總會使用標簽。為了更準確,請使用loc(標簽)或iloc(整數): ```python 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 ``` ## 算術運算和數據對齊 pandas最重要的一個功能是,它可以對不同索引的對象進行算術運算。在將對象相加時,如果存在不同的索引對,則結果的索引就是該索引對的并集。對于有數據庫經驗的用戶,這就像在索引標簽上進行自動外連接。看一個簡單的例子: ```python 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 ``` 將它們相加就會產生: ```python In [154]: s1 + s2 Out[154]: a 5.2 c 1.1 d NaN e 0.0 f NaN g NaN dtype: float64 ``` 自動的數據對齊操作在不重疊的索引處引入了NA值。缺失值會在算術運算過程中傳播。 對于DataFrame,對齊操作會同時發生在行和列上: ```python 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的并集: ```python 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 ``` 因為'c'和'e'列均不在兩個DataFrame對象中,在結果中以缺省值呈現。行也是同樣。 如果DataFrame對象相加,沒有共用的列或行標簽,結果都會是空: ```python 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 ``` ## 在算術方法中填充值 在對不同索引的對象進行算術運算時,你可能希望當一個對象中某個軸標簽在另一個對象中找不到時填充一個特殊值(比如0): ```python 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 ``` 將它們相加時,沒有重疊的位置就會產生NA值: ```python 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參數: ```python 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的算術方法。它們每個都有一個副本,以字母r開頭,它會翻轉參數。因此這兩個語句是等價的: ```python 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 靈活的算術方法](https://img.kancloud.cn/33/7e/337ec8928ab105e2eb30d3123befcd54_388x254.png) 與此類似,在對Series或DataFrame重新索引時,也可以指定一個填充值: ```python 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之間的運算 跟不同維度的NumPy數組一樣,DataFrame和Series之間算術運算也是有明確規定的。先來看一個具有啟發性的例子,計算一個二維數組與其某行之間的差: ```python 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.]]) ``` 當我們從arr減去arr[0],每一行都會執行這個操作。這就叫做廣播(broadcasting),附錄A將對此進行詳細講解。DataFrame和Series之間的運算差不多也是如此: ```python 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 ``` 默認情況下,DataFrame和Series之間的算術運算會將Series的索引匹配到DataFrame的列,然后沿著行一直向下廣播: ```python 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的索引中找不到,則參與運算的兩個對象就會被重新索引以形成并集: ```python 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 ``` 如果你希望匹配行且在列上廣播,則必須使用算術運算方法。例如: ```python 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)并進行廣播。 ## 函數應用和映射 NumPy的ufuncs(元素級數組方法)也可用于操作pandas對象: ```python 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 ``` 另一個常見的操作是,將函數應用到由各列或行所形成的一維數組上。DataFrame的apply方法即可實現此功能: ```python 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 ``` 這里的函數f,計算了一個Series的最大值和最小值的差,在frame的每列都執行了一次。結果是一個Series,使用frame的列作為索引。 如果傳遞axis='columns'到apply,這個函數會在每行執行: ```python In [195]: frame.apply(f, axis='columns') Out[195]: Utah 0.998382 Ohio 2.521511 Texas 0.676115 Oregon 2.542656 dtype: float64 ``` 許多最為常見的數組統計功能都被實現成DataFrame的方法(如sum和mean),因此無需使用apply方法。 傳遞到apply的函數不是必須返回一個標量,還可以返回由多個值組成的Series: ```python 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函數也是可以用的。假如你想得到frame中各個浮點值的格式化字符串,使用applymap即可: ```python 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,是因為Series有一個用于應用元素級函數的map方法: ```python In [200]: frame['e'].map(format) Out[200]: Utah -0.52 Ohio 1.39 Texas 0.77 Oregon -1.30 Name: e, dtype: object ``` ## 排序和排名 根據條件對數據集排序(sorting)也是一種重要的內置運算。要對行或列索引進行排序(按字典順序),可使用sort_index方法,它將返回一個已排序的新對象: ```python 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,則可以根據任意一個軸上的索引進行排序: ```python 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 ``` 數據默認是按升序排序的,但也可以降序排序: ```python 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進行排序,可使用其sort_values方法: ```python 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 ``` 在排序時,任何缺失值默認都會被放到Series的末尾: ```python 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 ``` 當排序一個DataFrame時,你可能希望根據一個或多個列中的值進行排序。將一個或多個列的名字傳遞給sort_values的by選項即可達到該目的: ```python 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 ``` 要根據多個列進行排序,傳入名稱的列表即可: ```python 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開始一直到數組中有效數據的數量。接下來介紹Series和DataFrame的rank方法。默認情況下,rank是通過“為各組分配一個平均排名”的方式破壞平級關系的: ```python 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 ``` 也可以根據值在原數據中出現的順序給出排名: ```python 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,它們被設成了6和7,因為數據中標簽0位于標簽2的前面。 你也可以按降序進行排名: ```python # 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列出了所有用于破壞平級關系的method選項。DataFrame可以在行或列上計算排名: ```python 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 排名時用于破壞平級關系的方法](https://img.kancloud.cn/fb/69/fb6935c62d869767acfdab4007b60af9_653x224.png) ## 帶有重復標簽的軸索引 直到目前為止,我所介紹的所有范例都有著唯一的軸標簽(索引值)。雖然許多pandas函數(如reindex)都要求標簽唯一,但這并不是強制性的。我們來看看下面這個簡單的帶有重復索引值的Series: ```python 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屬性可以告訴你它的值是否是唯一的: ```python In [224]: obj.index.is_unique Out[224]: False ``` 對于帶有重復值的索引,數據選取的行為將會有些不同。如果某個索引對應多個值,則返回一個Series;而對應單個值的,則返回一個標量值: ```python In [225]: obj['a'] Out[225]: a 0 a 1 dtype: int64 In [226]: obj['c'] Out[226]: 4 ``` 這樣會使代碼變復雜,因為索引的輸出類型會根據標簽是否有重復發生變化。 對DataFrame的行進行索引時也是如此: ```python 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 ``` # 5.3 匯總和計算描述統計 pandas對象擁有一組常用的數學和統計方法。它們大部分都屬于約簡和匯總統計,用于從Series中提取單個值(如sum或mean)或從DataFrame的行或列中提取一個Series。跟對應的NumPy數組方法相比,它們都是基于沒有缺失數據的假設而構建的。看一個簡單的DataFrame: ```python In [230]: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], .....: [np.nan, np.nan], [0.75, -1.3]], .....: index=['a', 'b', 'c', 'd'], .....: columns=['one', 'two']) In [231]: df Out[231]: one two a 1.40 NaN b 7.10 -4.5 c NaN NaN d 0.75 -1.3 ``` 調用DataFrame的sum方法將會返回一個含有列的和的Series: ```python In [232]: df.sum() Out[232]: one 9.25 two -5.80 dtype: float64 ``` 傳入axis='columns'或axis=1將會按行進行求和運算: ```python In?[233]:?df.sum(axis=1) Out[233]: a????1.40 b????2.60 c?????NaN d???-0.55 ``` NA值會自動被排除,除非整個切片(這里指的是行或列)都是NA。通過skipna選項可以禁用該功能: ```python In [234]: df.mean(axis='columns', skipna=False) Out[234]: a NaN b 1.300 c NaN d -0.275 dtype: float64 ``` 表5-7列出了這些約簡方法的常用選項。 ![](https://img.kancloud.cn/a9/62/a962e59998dcad326a2157127806a016_1240x289.jpg) 有些方法(如idxmin和idxmax)返回的是間接統計(比如達到最小值或最大值的索引): ```python In [235]: df.idxmax() Out[235]: one b two d dtype: object ``` 另一些方法則是累計型的: ```python In [236]: df.cumsum() Out[236]: one two a 1.40 NaN b 8.50 -4.5 c NaN NaN d 9.25 -5.8 ``` 還有一種方法,它既不是約簡型也不是累計型。describe就是一個例子,它用于一次性產生多個匯總統計: ```python In [237]: df.describe() Out[237]: one two count 3.000000 2.000000 mean 3.083333 -2.900000 std 3.493685 2.262742 min 0.750000 -4.500000 25% 1.075000 -3.700000 50% 1.400000 -2.900000 75% 4.250000 -2.100000 max 7.100000 -1.300000 ``` 對于非數值型數據,describe會產生另外一種匯總統計: ```python In [238]: obj = pd.Series(['a', 'a', 'b', 'c'] * 4) In [239]: obj.describe() Out[239]: count 16 unique 3 top a freq 8 dtype: object ``` 表5-8列出了所有與描述統計相關的方法。 ![](https://img.kancloud.cn/33/9d/339d07f1429e786d67536d408e2d7135_1205x1143.jpg) ## 相關系數與協方差 有些匯總統計(如相關系數和協方差)是通過參數對計算出來的。我們來看幾個DataFrame,它們的數據來自Yahoo!Finance的股票價格和成交量,使用的是pandas-datareader包(可以用conda或pip安裝): ```python conda install pandas-datareader ``` 我使用pandas_datareader模塊下載了一些股票數據: ```python import pandas_datareader.data as web all_data = {ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG']} price = pd.DataFrame({ticker: data['Adj Close'] for ticker, data in all_data.items()}) volume = pd.DataFrame({ticker: data['Volume'] for ticker, data in all_data.items()}) ``` >注意:此時Yahoo! Finance已經不存在了,因為2017年Yahoo!被Verizon收購了。參閱pandas-datareader文檔,可以學習最新的功能。 現在計算價格的百分數變化,時間序列的操作會在第11章介紹: ```python In [242]: returns = price.pct_change() In [243]: returns.tail() Out[243]: AAPL GOOG IBM MSFT Date 2016-10-17 -0.000680 0.001837 0.002072 -0.003483 2016-10-18 -0.000681 0.019616 -0.026168 0.007690 2016-10-19 -0.002979 0.007846 0.003583 -0.002255 2016-10-20 -0.000512 -0.005652 0.001719 -0.004867 2016-10-21 -0.003930 0.003011 -0.012474 0.042096 ``` Series的corr方法用于計算兩個Series中重疊的、非NA的、按索引對齊的值的相關系數。與此類似,cov用于計算協方差: ```python In [244]: returns['MSFT'].corr(returns['IBM']) Out[244]: 0.49976361144151144 In [245]: returns['MSFT'].cov(returns['IBM']) Out[245]: 8.8706554797035462e-05 ``` 因為MSTF是一個合理的Python屬性,我們還可以用更簡潔的語法選擇列: ```python In [246]: returns.MSFT.corr(returns.IBM) Out[246]: 0.49976361144151144 ``` 另一方面,DataFrame的corr和cov方法將以DataFrame的形式分別返回完整的相關系數或協方差矩陣: ```python In [247]: returns.corr() Out[247]: AAPL GOOG IBM MSFT AAPL 1.000000 0.407919 0.386817 0.389695 GOOG 0.407919 1.000000 0.405099 0.465919 IBM 0.386817 0.405099 1.000000 0.499764 MSFT 0.389695 0.465919 0.499764 1.000000 In [248]: returns.cov() Out[248]: AAPL GOOG IBM MSFT AAPL 0.000277 0.000107 0.000078 0.000095 GOOG 0.000107 0.000251 0.000078 0.000108 IBM 0.000078 0.000078 0.000146 0.000089 MSFT 0.000095 0.000108 0.000089 0.000215 ``` 利用DataFrame的corrwith方法,你可以計算其列或行跟另一個Series或DataFrame之間的相關系數。傳入一個Series將會返回一個相關系數值Series(針對各列進行計算): ```python In [249]: returns.corrwith(returns.IBM) Out[249]: AAPL 0.386817 GOOG 0.405099 IBM 1.000000 MSFT 0.499764 dtype: float64 ``` 傳入一個DataFrame則會計算按列名配對的相關系數。這里,我計算百分比變化與成交量的相關系數: ```python In [250]: returns.corrwith(volume) Out[250]: AAPL -0.075565 GOOG -0.007067 IBM -0.204849 MSFT -0.092950 dtype: float64 ``` 傳入axis='columns'即可按行進行計算。無論如何,在計算相關系數之前,所有的數據項都會按標簽對齊。 ## 唯一值、值計數以及成員資格 還有一類方法可以從一維Series的值中抽取信息。看下面的例子: ```python In [251]: obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c']) ``` 第一個函數是unique,它可以得到Series中的唯一值數組: ```python In [252]: uniques = obj.unique() In [253]: uniques Out[253]: array(['c', 'a', 'd', 'b'], dtype=object) ``` 返回的唯一值是未排序的,如果需要的話,可以對結果再次進行排序(uniques.sort())。相似的,value_counts用于計算一個Series中各值出現的頻率: ```python In [254]: obj.value_counts() Out[254]: c 3 a 3 b 2 d 1 dtype: int64 ``` 為了便于查看,結果Series是按值頻率降序排列的。value_counts還是一個頂級pandas方法,可用于任何數組或序列: ```python In [255]: pd.value_counts(obj.values, sort=False) Out[255]: a 3 b 2 c 3 d 1 dtype: int64 ``` isin用于判斷矢量化集合的成員資格,可用于過濾Series中或DataFrame列中數據的子集: ```python In [256]: obj Out[256]: 0 c 1 a 2 d 3 a 4 a 5 b 6 b 7 c 8 c dtype: object In [257]: mask = obj.isin(['b', 'c']) In [258]: mask Out[258]: 0 True 1 False 2 False 3 False 4 False 5 True 6 True 7 True 8 True dtype: bool In [259]: obj[mask] Out[259]: 0 c 5 b 6 b 7 c 8 c dtype: object ``` 與isin類似的是Index.get_indexer方法,它可以給你一個索引數組,從可能包含重復值的數組到另一個不同值的數組: ```python In [260]: to_match = pd.Series(['c', 'a', 'b', 'b', 'c', 'a']) In [261]: unique_vals = pd.Series(['c', 'b', 'a']) In [262]: pd.Index(unique_vals).get_indexer(to_match) Out[262]: array([0, 2, 1, 1, 0, 2]) ``` 表5-9給出了這幾個方法的一些參考信息。 ![表5-9 唯一值、值計數、成員資格方法](https://img.kancloud.cn/b3/ce/b3ced7a17c508f4b992fe1dd569cee6e_848x188.png) 有時,你可能希望得到DataFrame中多個相關列的一張柱狀圖。例如: ```python In [263]: data = pd.DataFrame({'Qu1': [1, 3, 4, 3, 4], .....: 'Qu2': [2, 3, 1, 2, 3], .....: 'Qu3': [1, 5, 2, 4, 4]}) In [264]: data Out[264]: 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函數,就會出現: ```python In [265]: result = data.apply(pd.value_counts).fillna(0) In [266]: result Out[266]: 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 ``` 這里,結果中的行標簽是所有列的唯一值。后面的頻率值是每個列中這些值的相應計數。 # 5.4 總結 在下一章,我們將討論用pandas讀取(或加載)和寫入數據集的工具。 之后,我們將更深入地研究使用pandas進行數據清洗、規整、分析和可視化工具。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看