Pandas实战-筛选DataFrame

本文将主要介绍以下内容:

1. 针对内存使用优化数据集

2. 按单一条件筛选

3. 按多个条件筛选

4. 其它筛选方法

5. 处理重复项

 

在前面的文章中,我们练习了从DataFrame中选择单独的行,列和值。现在让我们探索如何基于一个或多个条件来筛选数据。

1. 针对内存使用优化数据集

和往常一样,让我们从导入pandas开始:

In  [1]: import pandas as pd

接下来让我们看看要使用的employee.csv测试数据集,它是公司虚构的员工集合。每条记录都包括员工的名字、性别、在公司的开始日期、薪水、管理状态和所在的团队:

In  [2]: pd.read_csv("employees.csv")
Out [2]:      First Name   Gender Start Date     Salary    Mgmt           Team
            0    Douglas     Male     8/6/93        NaN    True      Marketing
            1     Thomas     Male    3/31/96    61933.0    True            NaN
            2      Maria   Female        NaN   130590.0   False        Finance
            3      Jerry      NaN     3/4/05   138705.0    True        Finance
            4      Larry     Male    1/24/98   101004.0    True             IT
            …          …        …          …          …       …              …
          996    Phillip     Male    1/31/84    42392.0   False        Finance
          997    Russell     Male    5/20/13    96914.0   False        Product
          998      Larry     Male    4/20/13    60500.0   False   Business Dev
          999     Albert     Male    5/15/12   129949.0    True          Sales
         1000       NaN       NaN        NaN        NaN     NaN            NaN
         1001 rows × 6 columns

不难看出数据集在每列中都有缺失的值,实际上最后一行仅包含NaN值。在现实世界中的数据会根据导出系统的不同而变化很大,空行是常见的情况。

第一个优化可以使用parse_dates参数将Start Date列中的文本值转换为datetime对象:

In  [3]: pd.read_csv("employees.csv", parse_dates = ["Start Date"]).head()
Out [3]:   First Name   Gender   Start Date     Salary    Mgmt        Team
         0    Douglas     Male   1993-08-06        NaN    True   Marketing
         1     Thomas     Male   1996-03-31    61933.0    True         NaN
         2      Maria   Female          NaT   130590.0   False     Finance
         3      Jerry      NaN   2005-03-04   138705.0    True     Finance
         4      Larry     Male   1998-01-24   101004.0    True          IT

下面让我们将DataFrame对象分配给变量employees:

In  [4]: employees = pd.read_csv("employees.csv",
                                 parse_dates = ["Start Date"])

1.1 使用as_type方法转换数据类型

info方法返回数据集的摘要,包括列名、非空值数量、数据类型和内存消耗:

In [5]: employees.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1001 entries, 0 to 1000
Data columns (total 6 columns):
  #    Column        Non-Null Count  Dtype
  0    First Name    933 non-null    object
  1    Gender        854 non-null    object
  2    Start Date    999 non-null    datetime64[ns]
  3    Salary        999 non-null    float64
  4    Mgmt          933 non-null    object
  5    Team          957 non-null    object
dtypes: datetime64[ns](1), float64(1), object(4)
memory usage: 47.0+ KB

RangeIndex显示数据集有1001行,然后我们可以从Non-Null Count列确定每列非空值的数量,所有六列都缺少数据。当前的内存使用量约为47kb,让我们看看是否可以减少它。

astype方法用于把Pandas对象的值转换为其它数据类型。下例是把Mgmt列转换为bool数据类型,返回值是一个新的Series对象。请注意,NaN值会被转换为True值。在本文的后面,我会介绍如何删除和替换缺失值。

In  [6]: employees["Mgmt"].astype(bool)
Out [6]: 0      True
         1      True
         2     False
         3      True
         4      True
                 ...
         996   False
         997   False
         998   False
         999    True
         1000   True
         Name: Mgmt, Length: 1001, dtype: bool

在DataFrame中覆盖存在列或创建新列的原理和向字典添加键值对是相似的,如果存在具有指定名称的列,Pandas会使用新的Series覆盖它;如果该列不存在,Pandas会把新的Series添加到DataFrame的右侧,并通过两个数据结构中的公共索引标签进行匹配。

In  [7]: employees["Mgmt"] = employees["Mgmt"].astype(bool)

让我们用info方法再查看一下内存消耗:

In [8]: employees.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1001 entries, 0 to 1000
Data columns (total 6 columns):
  #    Column        Non-Null Count   Dtype
  0    First Name    933 non-null     object
  1    Gender        854 non-null     object
  2    Start Date    999 non-null     datetime64[ns]
  3    Salary        999 non-null     float64
  4    Mgmt          1001 non-null    bool
  5    Team          957 non-null     object
dtypes: bool(1), datetime64[ns](1), float64(1), object(3)
memory usage: 40.2+ KB

啊哈!我们把内存使用量减少了近15%,这是一个很好的开始!接下来,让我们看一下Salary列。如果打开原始CSV文件会看到该列的值实际上存储为整数,出于技术原因,Pandas需要将其从整数转换为浮点值,以支持分散在各处的NaN值。如果我们尝试把列的值强制转为整数,则会抛出ValueError异常:

In  [9]: employees["Salary"].astype(int)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-99-b148c8b8be90> in <module>
----> 1 employees["Salary"].astype(int)
ValueError: Cannot convert non-finite values (NA or inf) to integer

在本文的后面,我将会介绍如何完全删除最后一行。现在,我们可以使用fillna方法把NaN替换为指定的值,返回一个新的Series。例如替换为0:

In  [10]: employees["Salary"].fillna(0).tail()
Out [10]: 99      42392.0
          99      96914.0
          998     60500.0
          999    129949.0
          1000        0.0
          Name: Salary, dtype: float64

现在Salary列中已经没有缺少的值,可以将其值转换为整数:

In  [11]: employees["Salary"].fillna(0).astype(int).head()
Out [11]: 0         0
          1     61933
          2    130590
          3    138705
          4    101004
          Name: Salary, dtype: int64

转换为整数后覆盖原来的列:

In  [12]: employees["Salary"] = employees["Salary"].fillna(0).astype(int)

我们已经转换了Start Date和Mgmt列,以存储比字符串更合适的数据类型。还有什么可以优化的吗?绝对有!

Pandas包含一种称为category的特殊数据类型,当列包含相对于其总数量的少量唯一值时,它是理想的选择。数量有限的常见数据包括性别、工作日、血型等。category的值存储为普通的Python对象而不是NumPy的ndarrays,并针对性能进行了优化。

之前介绍过nunique方法可以返回DataFrame每列中唯一值的数量。请注意,默认情况下将排除缺失值NaN,不过您也可以使用dropna = False参数把其计算在内。

In  [13]: employees.nunique()
Out [13]: First Name    200
          Gender          2
          Start Date    971
          Salary        994
          Mgmt            2
          Team           10
          dtype: int64

最适合作为category类型的两列是Gender和Team,在1001行数据中,它们分别仅有2和10个唯一值。让我们再次练习使用astype方法:

In  [14]: employees["Gender"].astype("category")
Out [14]: 0      Male
          1      Male
          2    Female
          3       NaN
          4      Male
                  ...
          996    Male
          997    Male
          998    Male
          999    Male
          1000    NaN
          Name: Gender, Length: 1001, dtype: category
          Categories (2, object): [Female, Male]

让我们覆盖原有的Gender列并检查内存使用情

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值