<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 第 8 章 數據規整:聚合、合并和重塑 在許多應用中,數據可能分散在許多文件或數據庫中,存儲的形式也不利于分析。本章關注可以聚合、合并、重塑數據的方法。 首先,我會介紹pandas的層次化索引,它廣泛用于以上操作。然后,我深入介紹了一些特殊的數據操作。在第14章,你可以看到這些工具的多種應用。 # 8.1 層次化索引 層次化索引(hierarchical indexing)是pandas的一項重要功能,它使你能在一個軸上擁有多個(兩個以上)索引級別。抽象點說,它使你能以低維度形式處理高維度數據。我們先來看一個簡單的例子:創建一個Series,并用一個由列表或數組組成的列表作為索引: ```python In [9]: data = pd.Series(np.random.randn(9), ...: index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], ...: [1, 2, 3, 1, 3, 1, 2, 2, 3]]) In [10]: data Out[10]: a 1 -0.204708 2 0.478943 3 -0.519439 b 1 -0.555730 3 1.965781 c 1 1.393406 2 0.092908 d 2 0.281746 3 0.769023 dtype: float64 ``` 看到的結果是經過美化的帶有MultiIndex索引的Series的格式。索引之間的“間隔”表示“直接使用上面的標簽”: ```python In [11]: data.index Out[11]: MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]], labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]]) ``` 對于一個層次化索引的對象,可以使用所謂的部分索引,使用它選取數據子集的操作更簡單: ```python In [12]: data['b'] Out[12]: 1 -0.555730 3 1.965781 dtype: float64 In [13]: data['b':'c'] Out[13]: b 1 -0.555730 3 1.965781 c 1 1.393406 2 0.092908 dtype: float64 In [14]: data.loc[['b', 'd']] Out[14]: b 1 -0.555730 3 1.965781 d 2 0.281746 3 0.769023 dtype: float64 ``` 有時甚至還可以在“內層”中進行選取: ```python In [15]: data.loc[:, 2] Out[15]: a 0.478943 c 0.092908 d 0.281746 dtype: float64 ``` 層次化索引在數據重塑和基于分組的操作(如透視表生成)中扮演著重要的角色。例如,可以通過unstack方法將這段數據重新安排到一個DataFrame中: ```python In [16]: data.unstack() Out[16]: 1 2 3 a -0.204708 0.478943 -0.519439 b -0.555730 NaN 1.965781 c 1.393406 0.092908 NaN d NaN 0.281746 0.769023 ``` unstack的逆運算是stack: ```python In [17]: data.unstack().stack() Out[17]: a 1 -0.204708 2 0.478943 3 -0.519439 b 1 -0.555730 3 1.965781 c 1 1.393406 2 0.092908 d 2 0.281746 3 0.769023 dtype: float64 ``` stack和unstack將在本章后面詳細講解。 對于一個DataFrame,每條軸都可以有分層索引: ```python In [18]: frame = pd.DataFrame(np.arange(12).reshape((4, 3)), ....: index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]], ....: columns=[['Ohio', 'Ohio', 'Colorado'], ....: ['Green', 'Red', 'Green']]) In [19]: frame Out[19]: Ohio Colorado Green Red Green a 1 0 1 2 2 3 4 5 b 1 6 7 8 2 9 10 11 ``` 各層都可以有名字(可以是字符串,也可以是別的Python對象)。如果指定了名稱,它們就會顯示在控制臺輸出中: ```python In [20]: frame.index.names = ['key1', 'key2'] In [21]: frame.columns.names = ['state', 'color'] In [22]: frame Out[22]: state Ohio Colorado color Green Red Green key1 key2 a 1 0 1 2 2 3 4 5 b 1 6 7 8 2 9 10 11 ``` >注意:小心區分索引名state、color與行標簽。 有了部分列索引,因此可以輕松選取列分組: ```python In [23]: frame['Ohio'] Out[23]: color Green Red key1 key2 a 1 0 1 2 3 4 b 1 6 7 2 9 10 ``` 可以單獨創建MultiIndex然后復用。上面那個DataFrame中的(帶有分級名稱)列可以這樣創建: ```python MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']], names=['state', 'color']) ``` ## 重排與分級排序 有時,你需要重新調整某條軸上各級別的順序,或根據指定級別上的值對數據進行排序。swaplevel接受兩個級別編號或名稱,并返回一個互換了級別的新對象(但數據不會發生變化): ```python In [24]: frame.swaplevel('key1', 'key2') Out[24]: state Ohio Colorado color Green Red Green key2 key1 1 a 0 1 2 2 a 3 4 5 1 b 6 7 8 2 b 9 10 11 ``` 而sort_index則根據單個級別中的值對數據進行排序。交換級別時,常常也會用到sort_index,這樣最終結果就是按照指定順序進行字母排序了: ```python In [25]: frame.sort_index(level=1) Out[25]: state Ohio Colorado color Green Red Green key1 key2 a 1 0 1 2 b 1 6 7 8 a 2 3 4 5 b 2 9 10 11 In [26]: frame.swaplevel(0, 1).sort_index(level=0) Out[26]: state Ohio Colorado color Green Red Green key2 key1 1 a 0 1 2 b 6 7 8 2 a 3 4 5 b 9 10 11 ``` ## 根據級別匯總統計 許多對DataFrame和Series的描述和匯總統計都有一個level選項,它用于指定在某條軸上求和的級別。再以上面那個DataFrame為例,我們可以根據行或列上的級別來進行求和: ```python In [27]: frame.sum(level='key2') Out[27]: state Ohio Colorado color Green Red Green key2 1 6 8 10 2 12 14 16 In [28]: frame.sum(level='color', axis=1) Out[28]: color Green Red key1 key2 a 1 2 1 2 8 4 b 1 14 7 2 20 10 ``` 這其實是利用了pandas的groupby功能,本書稍后將對其進行詳細講解。 ## 使用DataFrame的列進行索引 人們經常想要將DataFrame的一個或多個列當做行索引來用,或者可能希望將行索引變成DataFrame的列。以下面這個DataFrame為例: ```python In [29]: frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1), ....: 'c': ['one', 'one', 'one', 'two', 'two', ....: 'two', 'two'], ....: 'd': [0, 1, 2, 0, 1, 2, 3]}) In [30]: frame Out[30]: a b c d 0 0 7 one 0 1 1 6 one 1 2 2 5 one 2 3 3 4 two 0 4 4 3 two 1 5 5 2 two 2 6 6 1 two 3 ``` DataFrame的set_index函數會將其一個或多個列轉換為行索引,并創建一個新的DataFrame: ```python In [31]: frame2 = frame.set_index(['c', 'd']) In [32]: frame2 Out[32]: a b c d one 0 0 7 1 1 6 2 2 5 two 0 3 4 1 4 3 2 5 2 3 6 1 ``` 默認情況下,那些列會從DataFrame中移除,但也可以將其保留下來: ```python In [33]: frame.set_index(['c', 'd'], drop=False) Out[33]: a b c d c d one 0 0 7 one 0 1 1 6 one 1 2 2 5 one 2 two 0 3 4 two 0 1 4 3 two 1 2 5 2 two 2 3 6 1 two 3 ``` reset_index的功能跟set_index剛好相反,層次化索引的級別會被轉移到列里面: ```python In [34]: frame2.reset_index() Out[34]: c d a b 0 one 0 0 7 1 one 1 1 6 2 one 2 2 5 3 two 0 3 4 4 two 1 4 3 5 two 2 5 2 6 two 3 6 1 ``` # 8.2 合并數據集 pandas對象中的數據可以通過一些方式進行合并: - pandas.merge可根據一個或多個鍵將不同DataFrame中的行連接起來。SQL或其他關系型數據庫的用戶對此應該會比較熟悉,因為它實現的就是數據庫的join操作。 - pandas.concat可以沿著一條軸將多個對象堆疊到一起。 - 實例方法combine_first可以將重復數據拼接在一起,用一個對象中的值填充另一個對象中的缺失值。 我將分別對它們進行講解,并給出一些例子。本書剩余部分的示例中將經常用到它們。 ##數據庫風格的DataFrame合并 數據集的合并(merge)或連接(join)運算是通過一個或多個鍵將行連接起來的。這些運算是關系型數據庫(基于SQL)的核心。pandas的merge函數是對數據應用這些算法的主要切入點。 以一個簡單的例子開始: ```python In [35]: df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], ....: 'data1': range(7)}) In [36]: df2 = pd.DataFrame({'key': ['a', 'b', 'd'], ....: 'data2': range(3)}) In [37]: df1 Out[37]: data1 key 0 0 b 1 1 b 2 2 a 3 3 c 4 4 a 5 5 a 6 6 b In [38]: df2 Out[38]: data2 key 0 0 a 1 1 b 2 2 d ``` 這是一種多對一的合并。df1中的數據有多個被標記為a和b的行,而df2中key列的每個值則僅對應一行。對這些對象調用merge即可得到: ```python In [39]: pd.merge(df1, df2) Out[39]: data1 key data2 0 0 b 1 1 1 b 1 2 6 b 1 3 2 a 0 4 4 a 0 5 5 a 0 ``` 注意,我并沒有指明要用哪個列進行連接。如果沒有指定,merge就會將重疊列的列名當做鍵。不過,最好明確指定一下: ```python In [40]: pd.merge(df1, df2, on='key') Out[40]: data1 key data2 0 0 b 1 1 1 b 1 2 6 b 1 3 2 a 0 4 4 a 0 5 5 a 0 ``` 如果兩個對象的列名不同,也可以分別進行指定: ```python In [41]: df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], ....: 'data1': range(7)}) In [42]: df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'], ....: 'data2': range(3)}) In [43]: pd.merge(df3, df4, left_on='lkey', right_on='rkey') Out[43]: data1 lkey data2 rkey 0 0 b 1 b 1 1 b 1 b 2 6 b 1 b 3 2 a 0 a 4 4 a 0 a 5 5 a 0 a ``` 可能你已經注意到了,結果里面c和d以及與之相關的數據消失了。默認情況下,merge做的是“內連接”;結果中的鍵是交集。其他方式還有"left"、"right"以及"outer"。外連接求取的是鍵的并集,組合了左連接和右連接的效果: ```python In [44]: pd.merge(df1, df2, how='outer') Out[44]: data1 key data2 0 0.0 b 1.0 1 1.0 b 1.0 2 6.0 b 1.0 3 2.0 a 0.0 4 4.0 a 0.0 5 5.0 a 0.0 6 3.0 c NaN 7 NaN d 2.0 ``` 表8-1對這些選項進行了總結。 ![表8-1 不同的連接類型](https://img.kancloud.cn/8f/6a/8f6abd8242365c7b6973e328003abe56_739x333.png) 多對多的合并有些不直觀。看下面的例子: ```python In [45]: df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'], ....: 'data1': range(6)}) In [46]: df2 = pd.DataFrame({'key': ['a', 'b', 'a', 'b', 'd'], ....: 'data2': range(5)}) In [47]: df1 Out[47]: data1 key 0 0 b 1 1 b 2 2 a 3 3 c 4 4 a 5 5 b In [48]: df2 Out[48]: data2 key 0 0 a 1 1 b 2 2 a 3 3 b 4 4 d In [49]: pd.merge(df1, df2, on='key', how='left') Out[49]: data1 key data2 0 0 b 1.0 1 0 b 3.0 2 1 b 1.0 3 1 b 3.0 4 2 a 0.0 5 2 a 2.0 6 3 c NaN 7 4 a 0.0 8 4 a 2.0 9 5 b 1.0 10 5 b 3.0 ``` 多對多連接產生的是行的笛卡爾積。由于左邊的DataFrame有3個"b"行,右邊的有2個,所以最終結果中就有6個"b"行。連接方式只影響出現在結果中的不同的鍵的值: ```python In [50]: pd.merge(df1, df2, how='inner') Out[50]: data1 key data2 0 0 b 1 1 0 b 3 2 1 b 1 3 1 b 3 4 5 b 1 5 5 b 3 6 2 a 0 7 2 a 2 8 4 a 0 9 4 a 2 ``` 要根據多個鍵進行合并,傳入一個由列名組成的列表即可: ```python In [51]: left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], ....: 'key2': ['one', 'two', 'one'], ....: 'lval': [1, 2, 3]}) In [52]: right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], ....: 'key2': ['one', 'one', 'one', 'two'], ....: 'rval': [4, 5, 6, 7]}) In [53]: pd.merge(left, right, on=['key1', 'key2'], how='outer') Out[53]: key1 key2 lval rval 0 foo one 1.0 4.0 1 foo one 1.0 5.0 2 foo two 2.0 NaN 3 bar one 3.0 6.0 4 bar two NaN 7.0 ``` 結果中會出現哪些鍵組合取決于所選的合并方式,你可以這樣來理解:多個鍵形成一系列元組,并將其當做單個連接鍵(當然,實際上并不是這么回事)。 >注意:在進行列-列連接時,DataFrame對象中的索引會被丟棄。 對于合并運算需要考慮的最后一個問題是對重復列名的處理。雖然你可以手工處理列名重疊的問題(查看前面介紹的重命名軸標簽),但merge有一個更實用的suffixes選項,用于指定附加到左右兩個DataFrame對象的重疊列名上的字符串: ```python In [54]: pd.merge(left, right, on='key1') Out[54]: key1 key2_x lval key2_y rval 0 foo one 1 one 4 1 foo one 1 one 5 2 foo two 2 one 4 3 foo two 2 one 5 4 bar one 3 one 6 5 bar one 3 two 7 In [55]: pd.merge(left, right, on='key1', suffixes=('_left', '_right')) Out[55]: key1 key2_left lval key2_right rval 0 foo one 1 one 4 1 foo one 1 one 5 2 foo two 2 one 4 3 foo two 2 one 5 4 bar one 3 one 6 5 bar one 3 two 7 ``` merge的參數請參見表8-2。使用DataFrame的行索引合并是下一節的主題。 表8-2 merge函數的參數 ![](https://img.kancloud.cn/46/e3/46e3d0b7fc4a241584f93252f6bba2c0_1180x269.png) ![](https://img.kancloud.cn/4e/d8/4ed8180bb8ecd4aa78f5e4703312e744_1180x706.png) indicator 添加特殊的列_merge,它可以指明每個行的來源,它的值有left_only、right_only或both,根據每行的合并數據的來源。 ## 索引上的合并 有時候,DataFrame中的連接鍵位于其索引中。在這種情況下,你可以傳入left_index=True或right_index=True(或兩個都傳)以說明索引應該被用作連接鍵: ```python In [56]: left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], ....: 'value': range(6)}) In [57]: right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b']) In [58]: left1 Out[58]: key value 0 a 0 1 b 1 2 a 2 3 a 3 4 b 4 5 c 5 In [59]: right1 Out[59]: group_val a 3.5 b 7.0 In [60]: pd.merge(left1, right1, left_on='key', right_index=True) Out[60]: key value group_val 0 a 0 3.5 2 a 2 3.5 3 a 3 3.5 1 b 1 7.0 4 b 4 7.0 ``` 由于默認的merge方法是求取連接鍵的交集,因此你可以通過外連接的方式得到它們的并集: ```python In [61]: pd.merge(left1, right1, left_on='key', right_index=True, how='outer') Out[61]: key value group_val 0 a 0 3.5 2 a 2 3.5 3 a 3 3.5 1 b 1 7.0 4 b 4 7.0 5 c 5 NaN ``` 對于層次化索引的數據,事情就有點復雜了,因為索引的合并默認是多鍵合并: ```python In [62]: lefth = pd.DataFrame({'key1': ['Ohio', 'Ohio', 'Ohio', ....: 'Nevada', 'Nevada'], ....: 'key2': [2000, 2001, 2002, 2001, 2002], ....: 'data': np.arange(5.)}) In [63]: righth = pd.DataFrame(np.arange(12).reshape((6, 2)), ....: index=[['Nevada', 'Nevada', 'Ohio', 'Ohio', ....: 'Ohio', 'Ohio'], ....: [2001, 2000, 2000, 2000, 2001, 2002]], ....: columns=['event1', 'event2']) In [64]: lefth Out[64]: data key1 key2 0 0.0 Ohio 2000 1 1.0 Ohio 2001 2 2.0 Ohio 2002 3 3.0 Nevada 2001 4 4.0 Nevada 2002 In [65]: righth Out[65]: event1 event2 Nevada 2001 0 1 2000 2 3 Ohio 2000 4 5 2000 6 7 2001 8 9 2002 10 11 ``` 這種情況下,你必須以列表的形式指明用作合并鍵的多個列(注意用how='outer'對重復索引值的處理): ```python In [66]: pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True) Out[66]: data key1 key2 event1 event2 0 0.0 Ohio 2000 4 5 0 0.0 Ohio 2000 6 7 1 1.0 Ohio 2001 8 9 2 2.0 Ohio 2002 10 11 3 3.0 Nevada 2001 0 1 In [67]: pd.merge(lefth, righth, left_on=['key1', 'key2'], ....: right_index=True, how='outer') Out[67]: data key1 key2 event1 event2 0 0.0 Ohio 2000 4.0 5.0 0 0.0 Ohio 2000 6.0 7.0 1 1.0 Ohio 2001 8.0 9.0 2 2.0 Ohio 2002 10.0 11.0 3 3.0 Nevada 2001 0.0 1.0 4 4.0 Nevada 2002 NaN NaN 4 NaN Nevada 2000 2.0 3.0 ``` 同時使用合并雙方的索引也沒問題: ```python In [68]: left2 = pd.DataFrame([[1., 2.], [3., 4.], [5., 6.]], ....: index=['a', 'c', 'e'], ....: columns=['Ohio', 'Nevada']) In [69]: right2 = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]], ....: index=['b', 'c', 'd', 'e'], ....: columns=['Missouri', 'Alabama']) In [70]: left2 Out[70]: Ohio Nevada a 1.0 2.0 c 3.0 4.0 e 5.0 6.0 In [71]: right2 Out[71]: Missouri Alabama b 7.0 8.0 c 9.0 10.0 d 11.0 12.0 e 13.0 14.0 In [72]: pd.merge(left2, right2, how='outer', left_index=True, right_index=True) Out[72]: Ohio Nevada Missouri Alabama a 1.0 2.0 NaN NaN b NaN NaN 7.0 8.0 c 3.0 4.0 9.0 10.0 d NaN NaN 11.0 12.0 e 5.0 6.0 13.0 14.0 ``` DataFrame還有一個便捷的join實例方法,它能更為方便地實現按索引合并。它還可用于合并多個帶有相同或相似索引的DataFrame對象,但要求沒有重疊的列。在上面那個例子中,我們可以編寫: ```python In [73]: left2.join(right2, how='outer') Out[73]: Ohio Nevada Missouri Alabama a 1.0 2.0 NaN NaN b NaN NaN 7.0 8.0 c 3.0 4.0 9.0 10.0 d NaN NaN 11.0 12.0 e 5.0 6.0 13.0 14.0 ``` 因為一些歷史版本的遺留原因,DataFrame的join方法默認使用的是左連接,保留左邊表的行索引。它還支持在調用的DataFrame的列上,連接傳遞的DataFrame索引: ```python In [74]: left1.join(right1, on='key') Out[74]: key value group_val 0 a 0 3.5 1 b 1 7.0 2 a 2 3.5 3 a 3 3.5 4 b 4 7.0 5 c 5 NaN ``` 最后,對于簡單的索引合并,你還可以向join傳入一組DataFrame,下一節會介紹更為通用的concat函數,也能實現此功能: ```python In [75]: another = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]], ....: index=['a', 'c', 'e', 'f'], ....: columns=['New York', 'Oregon']) In [76]: another Out[76]: New York Oregon a 7.0 8.0 c 9.0 10.0 e 11.0 12.0 f 16.0 17.0 In [77]: left2.join([right2, another]) Out[77]: Ohio Nevada Missouri Alabama New York Oregon a 1.0 2.0 NaN NaN 7.0 8.0 c 3.0 4.0 9.0 10.0 9.0 10.0 e 5.0 6.0 13.0 14.0 11.0 12.0 In [78]: left2.join([right2, another], how='outer') Out[78]: Ohio Nevada Missouri Alabama New York Oregon a 1.0 2.0 NaN NaN 7.0 8.0 b NaN NaN 7.0 8.0 NaN NaN c 3.0 4.0 9.0 10.0 9.0 10.0 d NaN NaN 11.0 12.0 NaN NaN e 5.0 6.0 13.0 14.0 11.0 12.0 f NaN NaN NaN NaN 16.0 17.0 ``` ## 軸向連接 另一種數據合并運算也被稱作連接(concatenation)、綁定(binding)或堆疊(stacking)。NumPy的concatenation函數可以用NumPy數組來做: ```python In [79]: arr = np.arange(12).reshape((3, 4)) In [80]: arr Out[80]: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) In [81]: np.concatenate([arr, arr], axis=1) Out[81]: array([[ 0, 1, 2, 3, 0, 1, 2, 3], [ 4, 5, 6, 7, 4, 5, 6, 7], [ 8, 9, 10, 11, 8, 9, 10, 11]]) ``` 對于pandas對象(如Series和DataFrame),帶有標簽的軸使你能夠進一步推廣數組的連接運算。具體點說,你還需要考慮以下這些東西: - 如果對象在其它軸上的索引不同,我們應該合并這些軸的不同元素還是只使用交集? - 連接的數據集是否需要在結果對象中可識別? - 連接軸中保存的數據是否需要保留?許多情況下,DataFrame默認的整數標簽最好在連接時刪掉。 pandas的concat函數提供了一種能夠解決這些問題的可靠方式。我將給出一些例子來講解其使用方式。假設有三個沒有重疊索引的Series: ```python In [82]: s1 = pd.Series([0, 1], index=['a', 'b']) In [83]: s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e']) In [84]: s3 = pd.Series([5, 6], index=['f', 'g']) ``` 對這些對象調用concat可以將值和索引粘合在一起: ```python In [85]: pd.concat([s1, s2, s3]) Out[85]: a 0 b 1 c 2 d 3 e 4 f 5 g 6 dtype: int64 ``` 默認情況下,concat是在axis=0上工作的,最終產生一個新的Series。如果傳入axis=1,則結果就會變成一個DataFrame(axis=1是列): ```python In [86]: pd.concat([s1, s2, s3], axis=1) Out[86]: 0 1 2 a 0.0 NaN NaN b 1.0 NaN NaN c NaN 2.0 NaN d NaN 3.0 NaN e NaN 4.0 NaN f NaN NaN 5.0 g NaN NaN 6.0 ``` 這種情況下,另外的軸上沒有重疊,從索引的有序并集(外連接)上就可以看出來。傳入join='inner'即可得到它們的交集: ```python In [87]: s4 = pd.concat([s1, s3]) In [88]: s4 Out[88]: a 0 b 1 f 5 g 6 dtype: int64 In [89]: pd.concat([s1, s4], axis=1) Out[89]: 0 1 a 0.0 0 b 1.0 1 f NaN 5 g NaN 6 In [90]: pd.concat([s1, s4], axis=1, join='inner') Out[90]: 0 1 a 0 0 b 1 1 ``` 在這個例子中,f和g標簽消失了,是因為使用的是join='inner'選項。 你可以通過join_axes指定要在其它軸上使用的索引: ```python In [91]: pd.concat([s1, s4], axis=1, join_axes=[['a', 'c', 'b', 'e']]) Out[91]: 0 1 a 0.0 0.0 c NaN NaN b 1.0 1.0 e NaN NaN ``` 不過有個問題,參與連接的片段在結果中區分不開。假設你想要在連接軸上創建一個層次化索引。使用keys參數即可達到這個目的: ```python In [92]: result = pd.concat([s1, s1, s3], keys=['one','two', 'three']) In [93]: result Out[93]: one a 0 b 1 two a 0 b 1 three f 5 g 6 dtype: int64 In [94]: result.unstack() Out[94]: a b f g one 0.0 1.0 NaN NaN two 0.0 1.0 NaN NaN three NaN NaN 5.0 6.0 ``` 如果沿著axis=1對Series進行合并,則keys就會成為DataFrame的列頭: ```python In [95]: pd.concat([s1, s2, s3], axis=1, keys=['one','two', 'three']) Out[95]: one two three a 0.0 NaN NaN b 1.0 NaN NaN c NaN 2.0 NaN d NaN 3.0 NaN e NaN 4.0 NaN f NaN NaN 5.0 g NaN NaN 6.0 ``` 同樣的邏輯也適用于DataFrame對象: ```python In [96]: df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'], ....: columns=['one', 'two']) In [97]: df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'], ....: columns=['three', 'four']) In [98]: df1 Out[98]: one two a 0 1 b 2 3 c 4 5 In [99]: df2 Out[99]: three four a 5 6 c 7 8 In [100]: pd.concat([df1, df2], axis=1, keys=['level1', 'level2']) Out[100]: level1 level2 one two three four a 0 1 5.0 6.0 b 2 3 NaN NaN c 4 5 7.0 8.0 ``` 如果傳入的不是列表而是一個字典,則字典的鍵就會被當做keys選項的值: ```python In [101]: pd.concat({'level1': df1, 'level2': df2}, axis=1) Out[101]: level1 level2 one two three four a 0 1 5.0 6.0 b 2 3 NaN NaN c 4 5 7.0 8.0 ``` 此外還有兩個用于管理層次化索引創建方式的參數(參見表8-3)。舉個例子,我們可以用names參數命名創建的軸級別: ```python In [102]: pd.concat([df1, df2], axis=1, keys=['level1', 'level2'], .....: names=['upper', 'lower']) Out[102]: upper level1 level2 lower one two three four a 0 1 5.0 6.0 b 2 3 NaN NaN c 4 5 7.0 8.0 ``` 最后一個關于DataFrame的問題是,DataFrame的行索引不包含任何相關數據: ```python In [103]: df1 = pd.DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd']) In [104]: df2 = pd.DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a']) In [105]: df1 Out[105]: a b c d 0 1.246435 1.007189 -1.296221 0.274992 1 0.228913 1.352917 0.886429 -2.001637 2 -0.371843 1.669025 -0.438570 -0.539741 In [106]: df2 Out[106]: b d a 0 0.476985 3.248944 -1.021228 1 -0.577087 0.124121 0.302614 ``` 在這種情況下,傳入ignore_index=True即可: ```python In [107]: pd.concat([df1, df2], ignore_index=True) Out[107]: a b c d 0 1.246435 1.007189 -1.296221 0.274992 1 0.228913 1.352917 0.886429 -2.001637 2 -0.371843 1.669025 -0.438570 -0.539741 3 -1.021228 0.476985 NaN 3.248944 4 0.302614 -0.577087 NaN 0.124121 ``` ![表8-3 concat函數的參數](https://img.kancloud.cn/64/e2/64e2260367eb2494a348a22267c16645_1167x706.png) ## 合并重疊數據 還有一種數據組合問題不能用簡單的合并(merge)或連接(concatenation)運算來處理。比如說,你可能有索引全部或部分重疊的兩個數據集。舉個有啟發性的例子,我們使用NumPy的where函數,它表示一種等價于面向數組的if-else: ```python In [108]: a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan], .....: index=['f', 'e', 'd', 'c', 'b', 'a']) In [109]: b = pd.Series(np.arange(len(a), dtype=np.float64), .....: index=['f', 'e', 'd', 'c', 'b', 'a']) In [110]: b[-1] = np.nan In [111]: a Out[111]: f NaN e 2.5 d NaN c 3.5 b 4.5 a NaN dtype: float64 In [112]: b Out[112]: f 0.0 e 1.0 d 2.0 c 3.0 b 4.0 a NaN dtype: float64 In [113]: np.where(pd.isnull(a), b, a) Out[113]: array([ 0. , 2.5, 2. , 3.5, 4.5, nan]) ``` Series有一個combine_first方法,實現的也是一樣的功能,還帶有pandas的數據對齊: ```python In [114]: b[:-2].combine_first(a[2:]) Out[114]: a NaN b 4.5 c 3.0 d 2.0 e 1.0 f 0.0 dtype: float64 ``` 對于DataFrame,combine_first自然也會在列上做同樣的事情,因此你可以將其看做:用傳遞對象中的數據為調用對象的缺失數據“打補丁”: ```python In [115]: df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan], .....: 'b': [np.nan, 2., np.nan, 6.], .....: 'c': range(2, 18, 4)}) In [116]: df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.], .....: 'b': [np.nan, 3., 4., 6., 8.]}) In [117]: df1 Out[117]: a b c 0 1.0 NaN 2 1 NaN 2.0 6 2 5.0 NaN 10 3 NaN 6.0 14 In [118]: df2 Out[118]: a b 0 5.0 NaN 1 4.0 3.0 2 NaN 4.0 3 3.0 6.0 4 7.0 8.0 In [119]: df1.combine_first(df2) Out[119]: a b c 0 1.0 NaN 2.0 1 4.0 2.0 6.0 2 5.0 4.0 10.0 3 3.0 6.0 14.0 4 7.0 8.0 NaN ``` # 8.3 重塑和軸向旋轉 有許多用于重新排列表格型數據的基礎運算。這些函數也稱作重塑(reshape)或軸向旋轉(pivot)運算。 ## 重塑層次化索引 層次化索引為DataFrame數據的重排任務提供了一種具有良好一致性的方式。主要功能有二: - stack:將數據的列“旋轉”為行。 - unstack:將數據的行“旋轉”為列。 我將通過一系列的范例來講解這些操作。接下來看一個簡單的DataFrame,其中的行列索引均為字符串數組: ```python In [120]: data = pd.DataFrame(np.arange(6).reshape((2, 3)), .....: index=pd.Index(['Ohio','Colorado'], name='state'), .....: columns=pd.Index(['one', 'two', 'three'], .....: name='number')) In [121]: data Out[121]: number one two three state Ohio 0 1 2 Colorado 3 4 5 ``` 對該數據使用stack方法即可將列轉換為行,得到一個Series: ```python In [122]: result = data.stack() In [123]: result Out[123]: state number Ohio one 0 two 1 three 2 Colorado one 3 two 4 three 5 dtype: int64 ``` 對于一個層次化索引的Series,你可以用unstack將其重排為一個DataFrame: ```python In [124]: result.unstack() Out[124]: number one two three state Ohio 0 1 2 Colorado 3 4 5 ``` 默認情況下,unstack操作的是最內層(stack也是如此)。傳入分層級別的編號或名稱即可對其它級別進行unstack操作: ```python In [125]: result.unstack(0) Out[125]: state Ohio Colorado number one 0 3 two 1 4 three 2 5 In [126]: result.unstack('state') Out[126]: state Ohio Colorado number one 0 3 two 1 4 three 2 5 ``` 如果不是所有的級別值都能在各分組中找到的話,則unstack操作可能會引入缺失數據: ```python In [127]: s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) In [128]: s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) In [129]: data2 = pd.concat([s1, s2], keys=['one', 'two']) In [130]: data2 Out[130]: one a 0 b 1 c 2 d 3 two c 4 d 5 e 6 dtype: int64 In [131]: data2.unstack() Out[131]: a b c d e one 0.0 1.0 2.0 3.0 NaN two NaN NaN 4.0 5.0 6.0 ``` stack默認會濾除缺失數據,因此該運算是可逆的: ```python In [132]: data2.unstack() Out[132]: a b c d e one 0.0 1.0 2.0 3.0 NaN two NaN NaN 4.0 5.0 6.0 In [133]: data2.unstack().stack() Out[133]: one a 0.0 b 1.0 c 2.0 d 3.0 two c 4.0 d 5.0 e 6.0 dtype: float64 In [134]: data2.unstack().stack(dropna=False) Out[134]: one a 0.0 b 1.0 c 2.0 d 3.0 e NaN two a NaN b NaN c 4.0 d 5.0 e 6.0 dtype: float64 ``` 在對DataFrame進行unstack操作時,作為旋轉軸的級別將會成為結果中的最低級別: ```python In [135]: df = pd.DataFrame({'left': result, 'right': result + 5}, .....: columns=pd.Index(['left', 'right'], name='side')) In [136]: df Out[136]: side left right state number Ohio one 0 5 two 1 6 three 2 7 Colorado one 3 8 two 4 9 three 5 10 In [137]: df.unstack('state') Out[137]: side left right state Ohio Colorado Ohio Colorado number one 0 3 5 8 two 1 4 6 9 three 2 5 7 10 ``` 當調用stack,我們可以指明軸的名字: ```python In [138]: df.unstack('state').stack('side') Out[138]: state Colorado Ohio number side one left 3 0 right 8 5 two left 4 1 right 9 6 three left 5 2 right 10 7 ``` ## 將“長格式”旋轉為“寬格式” 多個時間序列數據通常是以所謂的“長格式”(long)或“堆疊格式”(stacked)存儲在數據庫和CSV中的。我們先加載一些示例數據,做一些時間序列規整和數據清洗: ```python In [139]: data = pd.read_csv('examples/macrodata.csv') In [140]: data.head() Out[140]: year quarter realgdp realcons realinv realgovt realdpi cpi \ 0 1959.0 1.0 2710.349 1707.4 286.898 470.045 1886.9 28.98 1 1959.0 2.0 2778.801 1733.7 310.859 481.301 1919.7 29.15 2 1959.0 3.0 2775.488 1751.8 289.226 491.260 1916.4 29.35 3 1959.0 4.0 2785.204 1753.7 299.356 484.052 1931.3 29.37 4 1960.0 1.0 2847.699 1770.5 331.722 462.199 1955.5 29.54 m1 tbilrate unemp pop infl realint 0 139.7 2.82 5.8 177.146 0.00 0.00 1 141.7 3.08 5.1 177.830 2.34 0.74 2 140.5 3.82 5.3 178.657 2.74 1.09 3 140.0 4.33 5.6 179.386 0.27 4.06 4 139.6 3.50 5.2 180.007 2.31 1.19 In [141]: periods = pd.PeriodIndex(year=data.year, quarter=data.quarter, .....: name='date') In [142]: columns = pd.Index(['realgdp', 'infl', 'unemp'], name='item') In [143]: data = data.reindex(columns=columns) In [144]: data.index = periods.to_timestamp('D', 'end') In [145]: ldata = data.stack().reset_index().rename(columns={0: 'value'}) ``` 這就是多個時間序列(或者其它帶有兩個或多個鍵的可觀察數據,這里,我們的鍵是date和item)的長格式。表中的每行代表一次觀察。 關系型數據庫(如MySQL)中的數據經常都是這樣存儲的,因為固定架構(即列名和數據類型)有一個好處:隨著表中數據的添加,item列中的值的種類能夠增加。在前面的例子中,date和item通常就是主鍵(用關系型數據庫的說法),不僅提供了關系完整性,而且提供了更為簡單的查詢支持。有的情況下,使用這樣的數據會很麻煩,你可能會更喜歡DataFrame,不同的item值分別形成一列,date列中的時間戳則用作索引。DataFrame的pivot方法完全可以實現這個轉換: ```python In [147]: pivoted = ldata.pivot('date', 'item', 'value') In [148]: pivoted Out[148]: item infl realgdp unemp date 1959-03-31 0.00 2710.349 5.8 1959-06-30 2.34 2778.801 5.1 1959-09-30 2.74 2775.488 5.3 1959-12-31 0.27 2785.204 5.6 1960-03-31 2.31 2847.699 5.2 1960-06-30 0.14 2834.390 5.2 1960-09-30 2.70 2839.022 5.6 1960-12-31 1.21 2802.616 6.3 1961-03-31 -0.40 2819.264 6.8 1961-06-30 1.47 2872.005 7.0 ... ... ... ... 2007-06-30 2.75 13203.977 4.5 2007-09-30 3.45 13321.109 4.7 2007-12-31 6.38 13391.249 4.8 2008-03-31 2.82 13366.865 4.9 2008-06-30 8.53 13415.266 5.4 2008-09-30 -3.16 13324.600 6.0 2008-12-31 -8.79 13141.920 6.9 2009-03-31 0.94 12925.410 8.1 2009-06-30 3.37 12901.504 9.2 2009-09-30 3.56 12990.341 9.6 [203 rows x 3 columns] ``` 前兩個傳遞的值分別用作行和列索引,最后一個可選值則是用于填充DataFrame的數據列。假設有兩個需要同時重塑的數據列: ```python In [149]: ldata['value2'] = np.random.randn(len(ldata)) In [150]: ldata[:10] Out[150]: date item value value2 0 1959-03-31 realgdp 2710.349 0.523772 1 1959-03-31 infl 0.000 0.000940 2 1959-03-31 unemp 5.800 1.343810 3 1959-06-30 realgdp 2778.801 -0.713544 4 1959-06-30 infl 2.340 -0.831154 5 1959-06-30 unemp 5.100 -2.370232 6 1959-09-30 realgdp 2775.488 -1.860761 7 1959-09-30 infl 2.740 -0.860757 8 1959-09-30 unemp 5.300 0.560145 9 1959-12-31 realgdp 2785.204 -1.265934 ``` 如果忽略最后一個參數,得到的DataFrame就會帶有層次化的列: ```python In [151]: pivoted = ldata.pivot('date', 'item') In [152]: pivoted[:5] Out[152]: value value2 item infl realgdp unemp infl realgdp unemp date 1959-03-31 0.00 2710.349 5.8 0.000940 0.523772 1.343810 1959-06-30 2.34 2778.801 5.1 -0.831154 -0.713544 -2.370232 1959-09-30 2.74 2775.488 5.3 -0.860757 -1.860761 0.560145 1959-12-31 0.27 2785.204 5.6 0.119827 -1.265934 -1.063512 1960-03-31 2.31 2847.699 5.2 -2.359419 0.332883 -0.199543 In [153]: pivoted['value'][:5] Out[153]: item infl realgdp unemp date 1959-03-31 0.00 2710.349 5.8 1959-06-30 2.34 2778.801 5.1 1959-09-30 2.74 2775.488 5.3 1959-12-31 0.27 2785.204 5.6 1960-03-31 2.31 2847.699 5.2 ``` 注意,pivot其實就是用set_index創建層次化索引,再用unstack重塑: ```python In [154]: unstacked = ldata.set_index(['date', 'item']).unstack('item') In [155]: unstacked[:7] Out[155]: value value2 item infl realgdp unemp infl realgdp unemp date 1959-03-31 0.00 2710.349 5.8 0.000940 0.523772 1.343810 1959-06-30 2.34 2778.801 5.1 -0.831154 -0.713544 -2.370232 1959-09-30 2.74 2775.488 5.3 -0.860757 -1.860761 0.560145 1959-12-31 0.27 2785.204 5.6 0.119827 -1.265934 -1.063512 1960-03-31 2.31 2847.699 5.2 -2.359419 0.332883 -0.199543 1960-06-30 0.14 2834.390 5.2 -0.970736 -1.541996 -1.307030 1960-09-30 2.70 2839.022 5.6 0.377984 0.286350 -0.753887 ``` ## 將“寬格式”旋轉為“長格式” 旋轉DataFrame的逆運算是pandas.melt。它不是將一列轉換到多個新的DataFrame,而是合并多個列成為一個,產生一個比輸入長的DataFrame。看一個例子: ```python In [157]: df = pd.DataFrame({'key': ['foo', 'bar', 'baz'], .....: 'A': [1, 2, 3], .....: 'B': [4, 5, 6], .....: 'C': [7, 8, 9]}) In [158]: df Out[158]: A B C key 0 1 4 7 foo 1 2 5 8 bar 2 3 6 9 baz ``` key列可能是分組指標,其它的列是數據值。當使用pandas.melt,我們必須指明哪些列是分組指標。下面使用key作為唯一的分組指標: ```python In [159]: melted = pd.melt(df, ['key']) In [160]: melted Out[160]: key variable value 0 foo A 1 1 bar A 2 2 baz A 3 3 foo B 4 4 bar B 5 5 baz B 6 6 foo C 7 7 bar C 8 8 baz C 9 ``` 使用pivot,可以重塑回原來的樣子: ```python In [161]: reshaped = melted.pivot('key', 'variable', 'value') In [162]: reshaped Out[162]: variable A B C key bar 2 5 8 baz 3 6 9 foo 1 4 7 ``` 因為pivot的結果從列創建了一個索引,用作行標簽,我們可以使用reset_index將數據移回列: ```python In [163]: reshaped.reset_index() Out[163]: variable key A B C 0 bar 2 5 8 1 baz 3 6 9 2 foo 1 4 7 ``` 你還可以指定列的子集,作為值的列: ```python In [164]: pd.melt(df, id_vars=['key'], value_vars=['A', 'B']) Out[164]: key variable value 0 foo A 1 1 bar A 2 2 baz A 3 3 foo B 4 4 bar B 5 5 baz B 6 ``` pandas.melt也可以不用分組指標: ```python In [165]: pd.melt(df, value_vars=['A', 'B', 'C']) Out[165]: variable value 0 A 1 1 A 2 2 A 3 3 B 4 4 B 5 5 B 6 6 C 7 7 C 8 8 C 9 In [166]: pd.melt(df, value_vars=['key', 'A', 'B']) Out[166]: variable value 0 key foo 1 key bar 2 key baz 3 A 1 4 A 2 5 A 3 6 B 4 7 B 5 8 B 6 ``` #8.4 總結 現在你已經掌握了pandas數據導入、清洗、重塑,我們可以進一步學習matplotlib數據可視化。我們在稍后會回到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>

                              哎呀哎呀视频在线观看