Pandas的五項高級功能及使用方法
譯文【51CTO.com快譯】 你用Python準(zhǔn)備數(shù)據(jù)時,Pandas庫提供了核心功能。但許多人只了解基礎(chǔ)的方法,本文介紹的這些鮮為人知的高級方法讓你更輕松整潔地處理數(shù)據(jù)。
Pandas是數(shù)據(jù)界的典型庫。由于能夠加載、過濾、處理和瀏覽數(shù)據(jù),難怪它備受數(shù)據(jù)科學(xué)家的喜愛。
大多數(shù)人自然會堅守Pandas很基礎(chǔ)的方法。從CSV文件加載數(shù)據(jù),過濾幾列,然后直接進(jìn)入到數(shù)據(jù)可視化。不過Pandas實際上有許多鮮為人知但實用的功能,可以使數(shù)據(jù)處理起來輕松得多,整潔得多。
本教程將介紹5項更高級的功能、它們的功用及使用方法。
(1)配置選項和設(shè)置
Pandas帶有一組用戶可配置的選項和設(shè)置。它們能大大提高生產(chǎn)力,因為你可以根據(jù)自己的喜好來定制Pandas環(huán)境。
比如說,我們可以更改Pandas的一些顯示設(shè)置,改變顯示的行數(shù)和列數(shù)以及顯示的精度浮點數(shù)。
- import pandas as pd
- display_settings = {
- 'max_columns': 10,
- 'expand_frame_repr': True, # Wrap to multiple pages
- 'max_rows': 10,
- 'precision': 2,
- 'show_dimensions': True
- }
- for op, value in display_settings.items():
- pd.set_option("display.{}".format(op), value)
上面的代碼確保Pandas始終最多顯示10行和10列,浮點值最多顯示2個小數(shù)位。這樣,我們嘗試打印大的DataFrame時,終端或Jupyter Notebook不會看起來一團(tuán)糟!
這只是個基本的例子。除了簡單的顯示設(shè)置外,還有很多設(shè)置可以探索。可以查看官方文檔中的所有選項(https://pandas.pydata.org/pandas-docs/stable/user_guide/options.html)。
(2)合并DataFrame
Pandas DataFrame一個相對不為人知的地方是,實際上有兩種不同的方法來合并。每種方法得到的結(jié)果不一樣,因此,根據(jù)你要實現(xiàn)的目標(biāo)選擇合適的方法很重要。此外,它們含有許多進(jìn)一步定制合并的參數(shù)。不妨看一下。
連接
連接是合并DataFrame的最著名方法,它好比“堆疊”。這種堆疊可以橫向或縱向進(jìn)行。
假設(shè)你有一個龐大的CSV格式的數(shù)據(jù)集。將它分成多個文件以便處理合情合理(這是大型數(shù)據(jù)集的常見做法,名為分片)。
將其加載到Pandas后,你可以縱向堆疊每個CSV的DataFrame,為所有數(shù)據(jù)創(chuàng)建一個大的DataFrame。假設(shè)我們有3個分片,每個分片有500萬行,那么在縱向堆疊所有分片后,最終的DataFrame會有1500萬行。
下面的代碼顯示了如何在Pandas中縱向連接DataFrame。
- # Vertical concat
- pd.concat([october_df, november_df, december_df], axis=0)
你可以按照列而不是按照行來拆分?jǐn)?shù)據(jù)集,執(zhí)行類似的操作——每個CSV文件有幾列(包含數(shù)據(jù)集的所有行)。就像我們將數(shù)據(jù)集的特征劃分為不同的分片那樣。然后,你可以橫向堆疊它們以合并那些列/特征。
- # Horizontal concat
- pd.concat([features_1to5_df, features_6to10_df, features_11to15_df], axis=1)
合并
合并更復(fù)雜但功能更強大,以類似SQL的方式合并Pandas DataFrame,即DataFrame將通過某個常見屬性加以連接。
假設(shè)你有描述YouTube頻道的兩個DataFrame。其中一個含有用戶ID列表和每個用戶在頻道上總共花費的時間。另一個含有類似的用戶ID列表和每個用戶看過多少視頻。合并使我們可以通過匹配用戶ID,然后將ID、花費的時間和視頻數(shù)量歸入到每個用戶的單行,即可將兩個DataFrame合并為一個。
合并Pandas中的兩個DataFrame通過合并函數(shù)來完成。你可以在下面的代碼中看到其工作方式。left和right參數(shù)是指你希望合并的兩個DataFrame,而on指定了用于匹配的列。
- pd.merge(left=ids_and_time_df,
- right=ids_and_videos_df,
- on="id")
為了進(jìn)一步模擬SQL連接,how參數(shù)讓你可以選擇想要執(zhí)行的類似SQL的連接的類型:內(nèi)、外、左或右。想了解SQL連接的更多信息,請參閱W3Schools教程(https://www.w3schools.com/sql/sql_join.asp)。
(3)重塑DataFrame
有幾種方法可以重塑和重組Pandas DataFrame。既有簡單易用的方法,也有強大復(fù)雜的方法。不妨看看最常見的三種方法。針對以下所有示例,我們將使用超級英雄的這個數(shù)據(jù)集!
- import pandas as pd
- players_data = {'Player': ['Superman', 'Batman', 'Thanos', 'Batman', 'Thanos',
- 'Superman', 'Batman', 'Thanos', 'Black Widow', 'Batman', 'Thanos', 'Superman'],
- 'Year': [2000,2000,2000,2001,2001,2002,2002,2002,2003,2004,2004,2005],
- 'Points':[23,43,45,65,76,34,23,78,89,76,92,87]}
- df = pd.DataFrame(players_data)
- print(df)
- """
- Player Year Points
- 0 Superman 2000 23
- 1 Batman 2000 43
- 2 Thanos 2000 45
- 3 Batman 2001 65
- 4 Thanos 2001 76
- 5 Superman 2002 34
- 6 Batman 2002 23
- 7 Thanos 2002 78
- 8 Black Widow 2003 89
- 9 Batman 2004 76
- 10 Thanos 2004 92
- 11 Superman 2005 87
- """
轉(zhuǎn)置
轉(zhuǎn)置是其中最簡單的。轉(zhuǎn)置將DataFrame的行與列進(jìn)行互換。如果你有5000行和10列,然后轉(zhuǎn)置你的DataFrame后,最終會得到10行和5000列。
- import pandas as pd
- players_data = {'Player': ['Superman', 'Batman', 'Thanos', 'Batman', 'Thanos',
- 'Superman', 'Batman', 'Thanos', 'Black Widow', 'Batman', 'Thanos', 'Superman'],
- 'Year': [2000,2000,2000,2001,2001,2002,2002,2002,2003,2004,2004,2005],
- 'Points':[23,43,45,65,76,34,23,78,89,76,92,87]}
- df = pd.DataFrame(players_data)
- print(df)
- """
- Player Year Points
- 0 Superman 2000 23
- 1 Batman 2000 43
- 2 Thanos 2000 45
- 3 Batman 2001 65
- 4 Thanos 2001 76
- 5 Superman 2002 34
- 6 Batman 2002 23
- 7 Thanos 2002 78
- 8 Black Widow 2003 89
- 9 Batman 2004 76
- 10 Thanos 2004 92
- 11 Superman 2005 87
- """
Groupby
Groupby的主要用途是根據(jù)一些鍵將DataFrame分成多個部分。一旦DataFrame拆分成多個部分,你可以執(zhí)行遍歷、對每個部分獨立執(zhí)行一些操作。
比如說,我們可以從下面的代碼中看到如何創(chuàng)建了有相應(yīng)年份和積分的玩家DataFrame。然后我們執(zhí)行g(shù)roupby,根據(jù)玩家將DataFrame分為多個部分。因此,每個玩家都有自己的組,顯示該玩家每年玩游戲時獲得了多少積分。
- groups_df = df.groupby('Player')
- for player, group in groups_df:
- print("----- {} -----".format(player))
- print(group)
- print("")
- ### This prints out the following
- """
- ----- Batman -----
- Player Year Points
- 1 Batman 2000 43
- 3 Batman 2001 65
- 6 Batman 2002 23
- 9 Batman 2004 76
- ----- Black Widow -----
- Player Year Points
- 8 Black Widow 2003 89
- ----- Superman -----
- Player Year Points
- 0 Superman 2000 23
- 5 Superman 2002 34
- 11 Superman 2005 87
- ----- Thanos -----
- Player Year Points
- 2 Thanos 2000 45
- 4 Thanos 2001 76
- 7 Thanos 2002 78
- 10 Thanos 2004 92
- """
堆疊
堆疊將DataFrame轉(zhuǎn)換成有多級索引,即每行有多個子部分。這些子部分是使用DataFrame的列創(chuàng)建的,并將其壓縮成多索引??傮w而言,可以將堆疊視為將列壓縮成多索引行。
可以通過示例來說明,如下所示。
- df = df.stack()
- print(df)
- """
- 0 Player Superman
- Year 2000
- Points 23
- 1 Player Batman
- Year 2000
- Points 43
- 2 Player Thanos
- Year 2000
- Points 45
- 3 Player Batman
- Year 2001
- Points 65
- 4 Player Thanos
- Year 2001
- Points 76
- 5 Player Superman
- Year 2002
- Points 34
- 6 Player Batman
- Year 2002
- Points 23
- 7 Player Thanos
- Year 2002
- Points 78
- 8 Player Black Widow
- Year 2003
- Points 89
- 9 Player Batman
- Year 2004
- Points 76
- 10 Player Thanos
- Year 2004
- Points 92
- 11 Player Superman
- Year 2005
- Points 87
- """
(4)處理時間數(shù)據(jù)
Datetime庫是Python的基本庫。只要你處理與實際日期和時間信息有關(guān)的任何東西,它都是值得你使用的庫。幸好,Pandas還有使用Datetime對象的功能。
不妨舉例說明。在下面的代碼中,我們先創(chuàng)建一個有4列的DataFrame:Day、Month、Year和data,然后按年和月進(jìn)行排序。如你所見,這非常混亂。僅僅為了存儲日期,我們就用了3列,實際上我們知道日歷日期只是一個值。
- from itertools import product
- import pandas as pd
- import numpy as np
- col_names = ["Day", "Month", "Year"]
- df = pd.DataFrame(list(product([10, 11, 12], [8, 9], [2018, 2019])),
- columns=col_names)
- df['data'] = np.random.randn(len(df))
- df = df.sort_values(['Year', 'Month'], ascending=[True, True])
- print(df)
- """
- Day Month Year data
- 0 10 8 2018 1.685356
- 4 11 8 2018 0.441383
- 8 12 8 2018 1.276089
- 2 10 9 2018 -0.260338
- 6 11 9 2018 0.404769
- 10 12 9 2018 -0.359598
- 1 10 8 2019 0.145498
- 5 11 8 2019 -0.731463
- 9 12 8 2019 -1.451633
- 3 10 9 2019 -0.988294
- 7 11 9 2019 -0.687049
- 11 12 9 2019 -0.067432
- """
我們可以用datetime來清理。
Pandas貼心地隨帶名為to_datetime()的函數(shù),它可以壓縮多個DataFrame列并將其轉(zhuǎn)換成單個Datetime對象。一旦采用這種格式,你可以享用Datetime庫的所有靈活性。
想使用to_datetime()函數(shù),需要將相關(guān)列中的所有“data”數(shù)據(jù)傳遞給它。那就是“Day”、“Month”和“Year”這三列。一旦有了Datetime格式的內(nèi)容,我們不再需要其他列,刪除即可??纯聪旅娴拇a,看看它們?nèi)绾喂ぷ鳎?/p>
- from itertools import product
- import pandas as pd
- import numpy as np
- col_names = ["Day", "Month", "Year"]
- df = pd.DataFrame(list(product([10, 11, 12], [8, 9], [2018, 2019])),
- columns=col_names)
- df['data'] = np.random.randn(len(df))
- df = df.sort_values(['Year', 'Month'], ascending=[True, True])
- df.insert(loc=0, column="date", value=pd.to_datetime(df[col_names]))
- df = df.drop(col_names, axis=1).squeeze()
- print(df)
- """
- date data
- 0 2018-08-10 -0.328973
- 4 2018-08-11 -0.670790
- 8 2018-08-12 -1.360565
- 2 2018-09-10 -0.401973
- 6 2018-09-11 -1.238754
- 10 2018-09-12 0.957695
- 1 2019-08-10 0.571126
- 5 2019-08-11 -1.320735
- 9 2019-08-12 0.196036
- 3 2019-09-10 -1.717800
- 7 2019-09-11 0.074606
- 11 2019-09-12 -0.643198
- """
(5)將項映射到組
映射是個巧妙的技巧,有助于對分類數(shù)據(jù)進(jìn)行組織。比如設(shè)想我們有一個龐大的DataFrame,有成千上萬行,其中一列含有我們想要分類的項。這么做可以大大簡化機器學(xué)習(xí)模型的訓(xùn)練和有效地可視化數(shù)據(jù)。
請查看下面的代碼,這個小示例表明了我們想要分類的食品列表。
- import pandas as pd
- foods = pd.Series(["Bread", "Rice", "Steak", "Ham", "Chicken",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Bread", "Rice", "Steak", "Ham", "Chicken",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Bread", "Rice", "Steak", "Ham", "Chicken",
- "Bread", "Rice", "Steak", "Ham", "Chicken",
- "Bread", "Rice", "Steak", "Ham", "Chicken",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Apples", "Potatoes", "Mangoes", "Fish",
- "Bread", "Rice", "Steak", "Ham", "Chicken",
- "Bread", "Rice", "Steak", "Ham", "Chicken",])
- groups_dict = {
- "Protein": ["Steak", "Ham", "Chicken", "Fish"],
- "Carbs": ["Bread", "Rice", "Apples", "Potatoes", "Mangoes"]
- }
在上面的代碼中,我們將列表放入到Pandas系列。我們還創(chuàng)建了一個字典,顯示了想要的映射,將每個食品項分類成“Protein”或“Carbs”。這是嘗試性質(zhì)的示例,但如果該系列規(guī)模很大,假設(shè)有1000000項 ,那么遍歷它根本不可行。
我們可以使用Pandas內(nèi)置的.map()函數(shù)編寫函數(shù),以優(yōu)化的方式執(zhí)行映射,而不是使用基本的for-loop。請查看下面的代碼,看看該函數(shù)及使用方式。
- def membership_map(pandas_series, groups_dict):
- groups = {x: k for k, v in groups_dict.items() for x in v}
- mapped_series = pandas_series.map(groups)
- return mapped_series
- mapped_data = membership_map(foods, groups_dict)
- print(list(mapped_data))
在該函數(shù)中,我們先遍歷字典以創(chuàng)建一個新的字典,其中的鍵代表Pandas系列中每個可能的項,值代表新的映射項:“Protein”或“Carbs”。 然后,我們只需使用Pandas的內(nèi)置map函數(shù)來映射該系列中的所有值。
不妨看看下面的輸出以查看結(jié)果!
['Carbs', 'Carbs', 'Protein', 'Protein', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Protein', 'Protein', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Protein', 'Protein', 'Protein', 'Carbs', 'Carbs', 'Protein', 'Protein', 'Protein', 'Carbs', 'Carbs', 'Protein', 'Protein', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Carbs', 'Protein', 'Carbs', 'Carbs', 'Protein', 'Protein', 'Protein', 'Carbs', 'Carbs', 'Protein', 'Protein', 'Protein']
原文標(biāo)題:5 Advanced Features of Pandas and How to Use Them,作者:George Seif
【51CTO譯稿,合作站點轉(zhuǎn)載請注明原文譯者和出處為51CTO.com】