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

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

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

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

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

 (1)配置选项和设置

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

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

  1. import pandas as pd 
  2. display_settings = { 
  3. 'max_columns'10
  4. 'expand_frame_repr'True# Wrap to multiple pages 
  5. 'max_rows'10
  6. 'precision'2
  7. 'show_dimensions'True 
  8. for op, value in display_settings.items(): 
  9. 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。

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

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

  1. # Horizontal concat 
  2. 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指定了用于匹配的列。

  1. pd.merge(left=ids_and_time_df, 
  2. right=ids_and_videos_df, 
  3. on="id"

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

(3)重塑DataFrame

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

  1. import pandas as pd 
  2. players_data = {'Player': ['Superman''Batman''Thanos''Batman''Thanos'
  3. 'Superman''Batman''Thanos''Black Widow''Batman''Thanos''Superman'], 
  4. 'Year': [2000,2000,2000,2001,2001,2002,2002,2002,2003,2004,2004,2005], 
  5. 'Points':[23,43,45,65,76,34,23,78,89,76,92,87]} 
  6. df = pd.DataFrame(players_data) 
  7. print(df) 
  8. """ 
  9. Player Year Points 
  10. 0 Superman 2000 23 
  11. 1 Batman 2000 43 
  12. 2 Thanos 2000 45 
  13. 3 Batman 2001 65 
  14. 4 Thanos 2001 76 
  15. 5 Superman 2002 34 
  16. 6 Batman 2002 23 
  17. 7 Thanos 2002 78 
  18. 8 Black Widow 2003 89 
  19. 9 Batman 2004 76 
  20. 10 Thanos 2004 92 
  21. 11 Superman 2005 87 
  22. """ 

转置

转置是其中最简单的。转置将DataFrame的行与列进行互换。如果你有5000行和10列,然后转置你的DataFrame后,最终会得到10行和5000列。

  1. import pandas as pd 
  2. players_data = {'Player': ['Superman''Batman''Thanos''Batman''Thanos'
  3. 'Superman''Batman''Thanos''Black Widow''Batman''Thanos''Superman'], 
  4. 'Year': [2000,2000,2000,2001,2001,2002,2002,2002,2003,2004,2004,2005], 
  5. 'Points':[23,43,45,65,76,34,23,78,89,76,92,87]} 
  6. df = pd.DataFrame(players_data) 
  7. print(df) 
  8. """ 
  9. Player Year Points 
  10. 0 Superman 2000 23 
  11. 1 Batman 2000 43 
  12. 2 Thanos 2000 45 
  13. 3 Batman 2001 65 
  14. 4 Thanos 2001 76 
  15. 5 Superman 2002 34 
  16. 6 Batman 2002 23 
  17. 7 Thanos 2002 78 
  18. 8 Black Widow 2003 89 
  19. 9 Batman 2004 76 
  20. 10 Thanos 2004 92 
  21. 11 Superman 2005 87 
  22. """ 

Groupby

Groupby的主要用途是根据一些键将DataFrame分成多个部分。一旦DataFrame拆分成多个部分,你可以执行遍历、对每个部分独立执行一些操作。

比如说,我们可以从下面的代码中看到如何创建了有相应年份和积分的玩家DataFrame。然后我们执行groupby,根据玩家将DataFrame分为多个部分。因此,每个玩家都有自己的组,显示该玩家每年玩游戏时获得了多少积分。

  1. groups_df = df.groupby('Player'
  2. for player, group in groups_df: 
  3. print("----- {} -----".format(player)) 
  4. print(group) 
  5. print("") 
  6.  
  7. ### This prints out the following 
  8. """ 
  9. ----- Batman ----- 
  10. Player Year Points 
  11. 1 Batman 2000 43 
  12. 3 Batman 2001 65 
  13. 6 Batman 2002 23 
  14. 9 Batman 2004 76 
  15. ----- Black Widow ----- 
  16. Player Year Points 
  17. 8 Black Widow 2003 89 
  18. ----- Superman ----- 
  19. Player Year Points 
  20. 0 Superman 2000 23 
  21. 5 Superman 2002 34 
  22. 11 Superman 2005 87 
  23. ----- Thanos ----- 
  24. Player Year Points 
  25. 2 Thanos 2000 45 
  26. 4 Thanos 2001 76 
  27. 7 Thanos 2002 78 
  28. 10 Thanos 2004 92 
  29. """ 

堆叠

堆叠将DataFrame转换成有多级索引,即每行有多个子部分。这些子部分是使用DataFrame的列创建的,并将其压缩成多索引。总体而言,可以将堆叠视为将列压缩成多索引行。

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

  1. df = df.stack() 
  2. print(df) 
  3. """ 
  4. 0 Player Superman 
  5. Year 2000 
  6. Points 23 
  7. 1 Player Batman 
  8. Year 2000 
  9. Points 43 
  10. 2 Player Thanos 
  11. Year 2000 
  12. Points 45 
  13. 3 Player Batman 
  14. Year 2001 
  15. Points 65 
  16. 4 Player Thanos 
  17. Year 2001 
  18. Points 76 
  19. 5 Player Superman 
  20. Year 2002 
  21. Points 34 
  22. 6 Player Batman 
  23. Year 2002 
  24. Points 23 
  25. 7 Player Thanos 
  26. Year 2002 
  27. Points 78 
  28. 8 Player Black Widow 
  29. Year 2003 
  30. Points 89 
  31. 9 Player Batman 
  32. Year 2004 
  33. Points 76 
  34. 10 Player Thanos 
  35. Year 2004 
  36. Points 92 
  37. 11 Player Superman 
  38. Year 2005 
  39. Points 87 
  40. """ 

(4)处理时间数据

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

不妨举例说明。在下面的代码中,我们先创建一个有4列的DataFrame:Day、Month、Year和data,然后按年和月进行排序。如你所见,这非常混乱。仅仅为了存储日期,我们就用了3列,实际上我们知道日历日期只是一个值。

  1. from itertools import product 
  2. import pandas as pd 
  3. import numpy as np 
  4. col_names = ["Day""Month""Year"
  5. df = pd.DataFrame(list(product([101112], [89], [20182019])), 
  6. columns=col_names) 
  7. df['data'] = np.random.randn(len(df)) 
  8. df = df.sort_values(['Year''Month'], ascending=[TrueTrue]) 
  9. print(df) 
  10. """ 
  11. Day Month Year data 
  12. 0 10 8 2018 1.685356 
  13. 4 11 8 2018 0.441383 
  14. 8 12 8 2018 1.276089 
  15. 2 10 9 2018 -0.260338 
  16. 6 11 9 2018 0.404769 
  17. 10 12 9 2018 -0.359598 
  18. 1 10 8 2019 0.145498 
  19. 5 11 8 2019 -0.731463 
  20. 9 12 8 2019 -1.451633 
  21. 3 10 9 2019 -0.988294 
  22. 7 11 9 2019 -0.687049 
  23. 11 12 9 2019 -0.067432 
  24. """ 

我们可以用datetime来清理。

Pandas贴心地随带名为to_datetime()的函数,它可以压缩多个DataFrame列并将其转换成单个Datetime对象。一旦采用这种格式,你可以享用Datetime库的所有灵活性。

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

  1. from itertools import product 
  2. import pandas as pd 
  3. import numpy as np 
  4. col_names = ["Day""Month""Year"
  5. df = pd.DataFrame(list(product([101112], [89], [20182019])), 
  6. columns=col_names) 
  7. df['data'] = np.random.randn(len(df)) 
  8. df = df.sort_values(['Year''Month'], ascending=[TrueTrue]) 
  9. df.insert(loc=0, column="date", value=pd.to_datetime(df[col_names])) 
  10. df = df.drop(col_names, axis=1).squeeze() 
  11. print(df) 
  12. """ 
  13. date data 
  14. 0 2018-08-10 -0.328973 
  15. 4 2018-08-11 -0.670790 
  16. 8 2018-08-12 -1.360565 
  17. 2 2018-09-10 -0.401973 
  18. 6 2018-09-11 -1.238754 
  19. 10 2018-09-12 0.957695 
  20. 1 2019-08-10 0.571126 
  21. 5 2019-08-11 -1.320735 
  22. 9 2019-08-12 0.196036 
  23. 3 2019-09-10 -1.717800 
  24. 7 2019-09-11 0.074606 
  25. 11 2019-09-12 -0.643198 
  26. """ 

(5)将项映射到组

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

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

  1. import pandas as pd 
  2. foods = pd.Series(["Bread""Rice""Steak""Ham""Chicken"
  3. "Apples""Potatoes""Mangoes""Fish"
  4. "Bread""Rice""Steak""Ham""Chicken"
  5. "Apples""Potatoes""Mangoes""Fish"
  6. "Apples""Potatoes""Mangoes""Fish"
  7. "Apples""Potatoes""Mangoes""Fish"
  8. "Bread""Rice""Steak""Ham""Chicken"
  9. "Bread""Rice""Steak""Ham""Chicken"
  10. "Bread""Rice""Steak""Ham""Chicken"
  11. "Apples""Potatoes""Mangoes""Fish"
  12. "Apples""Potatoes""Mangoes""Fish"
  13. "Apples""Potatoes""Mangoes""Fish"
  14. "Bread""Rice""Steak""Ham""Chicken"
  15. "Bread""Rice""Steak""Ham""Chicken",]) 
  16. groups_dict = { 
  17. "Protein": ["Steak""Ham""Chicken""Fish"], 
  18. "Carbs": ["Bread""Rice""Apples""Potatoes""Mangoes"

在上面的代码中,我们将列表放入到Pandas系列。我们还创建了一个字典,显示了想要的映射,将每个食品项分类成“Protein”或“Carbs”。这是尝试性质的示例,但如果该系列规模很大,假设有1000000项 ,那么遍历它根本不可行。

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

  1. def membership_map(pandas_series, groups_dict): 
  2. groups = {x: k for k, v in groups_dict.items() for x in v} 
  3. mapped_series = pandas_series.map(groups) 
  4. return mapped_series 
  5.  
  6. mapped_data = membership_map(foods, groups_dict) 
  7. print(list(mapped_data)) 

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

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

相关推荐