Pandas的五项高级功能及使用方法

【51CTO.com快译】 你用Python准备数据时,Pandas库提供了核心功能。但许多人只了解基础的方法,本文介绍的这些鲜为人知的高级方法让你更轻松整洁地处理数据。

Pandas是数据界的典型库。由于能够加载、过滤、处理和浏览数据,难怪它备受数据科学家的喜爱。

大多数人自然会坚守Pandas很基础的方法。从CSV文件加载数据,过滤几列,然后直接进入到数据可视化。不过Pandas实际上有许多鲜为人知但实用的功能,可以使数据处理起来轻松得多,整洁得多。

本教程将介绍5项更高级的功能、它们的功用及使用方法。

(1)配置选项和设置

Pandas带有一组用户可配置的选项和设置。它们能大大提高生产力,因为你可以根据自己的喜好来定制Pandas环境。

比如说,我们可以更改Pandas的一些显示设置,改变显示的行数和列数以及显示的精度浮点数。

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个小数位。这样,我们尝试打印大的DataFrame时,终端或Jupyter Notebook不会看起来一团糟!

这只是个基本的例子。除了简单的显示设置外,还有很多设置可以探索。可以查看官方文档中的所有选项(https://pandas.pydata.org/pandas-docs/stable/user_guide/options.html)。

(2)合并DataFrame

Pandas DataFrame一个相对不为人知的地方是,实际上有两种不同的方法来合并。每种方法得到的结果不一样,因此,根据你要实现的目标选择合适的方法很重要。此外,它们含有许多进一步定制合并的参数。不妨看一下。

连接

连接是合并DataFrame的最著名方法,它好比“堆叠”。这种堆叠可以横向或纵向进行。

假设你有一个庞大的CSV格式的数据集。将它分成多个文件以便处理合情合理(这是大型数据集的常见做法,名为分片)。

将其加载到Pandas后,你可以纵向堆叠每个CSV的DataFrame,为所有数据创建一个大的DataFrame。假设我们有3个分片,每个分片有500万行,那么在纵向堆叠所有分片后,最终的DataFrame会有1500万行。

下面的代码显示了如何在Pandas中纵向连接DataFrame。

# Vertical concat 
pd.concat([october_df, november_df, december_df], axis=0) 

你可以按照列而不是按照行来拆分数据集,执行类似的操作——每个CSV文件有几列(包含数据集的所有行)。就像我们将数据集的特征划分为不同的分片那样。然后,你可以横向堆叠它们以合并那些列/特征。

# Horizontal concat 
pd.concat([features_1to5_df, features_6to10_df, features_11to15_df], axis=1) 

合并

合并更复杂但功能更强大,以类似SQL的方式合并Pandas DataFrame,即DataFrame将通过某个常见属性加以连接。

假设你有描述YouTube频道的两个DataFrame。其中一个含有用户ID列表和每个用户在频道上总共花费的时间。另一个含有类似的用户ID列表和每个用户看过多少视频。合并使我们可以通过匹配用户ID,然后将ID、花费的时间和视频数量归入到每个用户的单行,即可将两个DataFrame合并为一个。

合并Pandas中的两个DataFrame通过合并函数来完成。你可以在下面的代码中看到其工作方式。left和right参数是指你希望合并的两个DataFrame,而on指定了用于匹配的列。

pd.merge(left=ids_and_time_df, 
right=ids_and_videos_df, 
on="id") 

为了进一步模拟SQL连接,how参数让你可以选择想要执行的类似SQL的连接的类型:内、外、左或右。想了解SQL连接的更多信息,请参阅W3Schools教程(https://www.w3schools.com/sql/sql_join.asp)。

(3)重塑DataFrame

有几种方法可以重塑和重组Pandas DataFrame。既有简单易用的方法,也有强大复杂的方法。不妨看看最常见的三种方法。针对以下所有示例,我们将使用超级英雄的这个数据集!

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

转置

转置是其中最简单的。转置将DataFrame的行与列进行互换。如果你有5000行和10列,然后转置你的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的主要用途是根据一些键将DataFrame分成多个部分。一旦DataFrame拆分成多个部分,你可以执行遍历、对每个部分独立执行一些操作。

比如说,我们可以从下面的代码中看到如何创建了有相应年份和积分的玩家DataFrame。然后我们执行groupby,根据玩家将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转换成有多级索引,即每行有多个子部分。这些子部分是使用DataFrame的列创建的,并将其压缩成多索引。总体而言,可以将堆叠视为将列压缩成多索引行。

可以通过示例来说明,如下所示。

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)处理时间数据

Datetime库是Python的基本库。只要你处理与实际日期和时间信息有关的任何东西,它都是值得你使用的库。幸好,Pandas还有使用Datetime对象的功能。

不妨举例说明。在下面的代码中,我们先创建一个有4列的DataFrame:Day、Month、Year和data,然后按年和月进行排序。如你所见,这非常混乱。仅仅为了存储日期,我们就用了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()的函数,它可以压缩多个DataFrame列并将其转换成单个Datetime对象。一旦采用这种格式,你可以享用Datetime库的所有灵活性。

想使用to_datetime()函数,需要将相关列中的所有“data”数据传递给它。那就是“Day”、“Month”和“Year”这三列。一旦有了Datetime格式的内容,我们不再需要其他列,删除即可。看看下面的代码,看看它们如何工作!

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)将项映射到组

映射是个巧妙的技巧,有助于对分类数据进行组织。比如设想我们有一个庞大的DataFrame,有成千上万行,其中一列含有我们想要分类的项。这么做可以大大简化机器学习模型的训练和有效地可视化数据。

请查看下面的代码,这个小示例表明了我们想要分类的食品列表。

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系列。我们还创建了一个字典,显示了想要的映射,将每个食品项分类成“Protein”或“Carbs”。这是尝试性质的示例,但如果该系列规模很大,假设有1000000项 ,那么遍历它根本不可行。

我们可以使用Pandas内置的.map()函数编写函数,以优化的方式执行映射,而不是使用基本的for-loop。请查看下面的代码,看看该函数及使用方式。

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

在该函数中,我们先遍历字典以创建一个新的字典,其中的键代表Pandas系列中每个可能的项,值代表新的映射项:“Protein”或“Carbs”。 然后,我们只需使用Pandas的内置map函数来映射该系列中的所有值。

不妨看看下面的输出以查看结果!

[‘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’]

原文标题:5 Advanced Features of Pandas and How to Use Them,作者:George Seif

【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】