前言
今天是跟着@外星人玩Python学习#Pandas#数据分析的第3天,目前也来到了第4节内容:筛选 (Filter)。数据筛选Filter 类似SQL中的Where语句,作用是过滤掉不需要的数据,按规则或条件筛选出需要的数据。
注意,本节开始,逐渐地开始有点烧脑的感觉了,务必跟着代码走一遍,边敲边理解才能够事半功倍。再次提醒没有Python和Pandas环境的同学,直接安装Anaconda可以获得一个交互式的Python IDE环境,通过下面代码可以逐步理解Pandas Filter的概念和实现方法。
Pandas数据筛选主要包含下面几种方法:
- 通过Boolean或Condition
- 通过列索引(Labels)
- 通过Series.map方法以及匿名函数lambda
- 通过DataFrame的Query方法
代码实现
下面是具体的代码实现,务必跟着代码走一遍,理解其具体原理和含义。
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 27 18:30:55 2021
@Derek Zhu
@外星人学Python - Chapter 04 - Filter
"""
# Step1: Import the Libraries
import os
os.chdir("E:/2018-VGIC/21_SuccessFactor/Python Training/pandas专栏数据与源码/文章源码/文章源码/src/04/src")
#%%
import pandas as pd
def get_df(g_path, g_encoding):
df = pd.read_csv(
g_path,
encoding = g_encoding,
index_col = [0, 1],
header = [0, 1]
)
df = df.sort_index()
return df
# Step 2: Read the dataset.
df = get_df('data/weather_new.csv', 'gb2312')
df
# =============================================================================
# Out[10]:
# 白夜 白天 夜间
# 指标 天气状况 风力方向 最高温度 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 27
# 2019-07-02 阵雨 无持续风向 1-2级 34 大雨 无持续风向 1-2级 26
# 2019-07-03 中雨 无持续风向 1-2级 29 大雨 无持续风向 1-2级 25
# 2019-07-04 多云 无持续风向 1-2级 33 多云 无持续风向 1-2级 26
# 2019-07-05 多云 无持续风向 1-2级 34 多云 无持续风向 1-2级 27
# 博罗 2019-07-01 雷阵雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 27
# 2019-07-02 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 25
# 2019-07-03 中雨 无持续风向 1-2级 28 中雨 无持续风向 1-2级 25
# 2019-07-04 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 25
# 2019-07-05 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 25
# 珠海 2019-07-01 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 28
# 2019-07-02 中雨 东风 3-4级 31 中雨 东风 3-4级 25
# 2019-07-03 中雨 东南风 3-4级 29 中雨 东南风 3-4级 25
# 2019-07-04 阵雨 南风 3-4级 30 多云 南风 3-4级 26
# 2019-07-05 阵雨 西南风 3-4级 31 多云 西南风 3-4级 26
# 番禺 2019-07-01 雷阵雨 无持续风向 1-2级 34 中雨 无持续风向 1-2级 28
# 2019-07-02 中雨 无持续风向 1-2级 34 大雨 无持续风向 1-2级 26
# 2019-07-03 大雨 东南风 3-4级 30 大雨 东南风 3-4级 26
# 2019-07-04 中雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 26
# 2019-07-05 雷阵雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 27
# =============================================================================
#%%
# Step 3: Filter the Dataset
# 检查行列索引名称
df.index.names
# Out[12]: FrozenList(['城市', '日期'])
df.columns.names
# Out[13]: FrozenList(['白夜', '指标'])
# 过滤方法1:通过布尔过滤
# 创建列变量cols,牢记:外层索引用元组,内层索引用列表
cols = ('白天','天气状况')
# 标签索引
df.loc[:, cols]
# df.loc[:, ('白天', '天气状况')] == '多云'
# =============================================================================
# Out[19]:
# 城市 日期
# 中山 2019-07-01 阵雨
# 2019-07-02 阵雨
# 2019-07-03 中雨
# 2019-07-04 多云
# 2019-07-05 多云
# 博罗 2019-07-01 雷阵雨
# 2019-07-02 阵雨
# 2019-07-03 中雨
# 2019-07-04 阵雨
# 2019-07-05 阵雨
# 珠海 2019-07-01 阵雨
# 2019-07-02 中雨
# 2019-07-03 中雨
# 2019-07-04 阵雨
# 2019-07-05 阵雨
# 番禺 2019-07-01 雷阵雨
# 2019-07-02 中雨
# 2019-07-03 大雨
# 2019-07-04 中雨
# 2019-07-05 雷阵雨
# Name: (白天, 天气状况), dtype: object
# =============================================================================
# 创建条件参数,
cond = (df.loc[:, cols] == '多云')
# Pandas的Series类型,结果值是布尔类型,如下面的False和True
type(cond)
# Out[22]: pandas.core.series.Series
cond
# =============================================================================
# Out[21]:
# 城市 日期
# 中山 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 博罗 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 珠海 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 番禺 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# Name: (白天, 天气状况), dtype: bool
# =============================================================================
# DataFrame数据集通过条件参数cond,提取出所有cond值为True的数据
df[cond]
# =============================================================================
# Out[23]:
# 白夜 白天 夜间
# 指标 天气状况 风力方向 最高温度 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-04 多云 无持续风向 1-2级 33 多云 无持续风向 1-2级 26
# 2019-07-05 多云 无持续风向 1-2级 34 多云 无持续风向 1-2级 27
# =============================================================================
# DataFrame[列名]是另外一种便捷的提取列数据的方式
df[cols] == '多云'
# =============================================================================
# Out[32]:
# 城市 日期
# 中山 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 博罗 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 珠海 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 番禺 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# Name: (白天, 天气状况), dtype: bool
# =============================================================================
#%%
# 使用Series.map方法过滤布尔列中的数据,可以理解为模糊匹配
# 1. 先定义布尔列
cols = ('白天','天气状况')
# 2. 通过DataFrame得到对应的列数据,类型为Series
type(df[cols])
# Out[38]: pandas.core.series.Series
df[cols]
# =============================================================================
# Out[42]:
# 城市 日期
# 中山 2019-07-01 阵雨
# 2019-07-02 阵雨
# 2019-07-03 中雨
# 2019-07-04 多云
# 2019-07-05 多云
# 博罗 2019-07-01 雷阵雨
# 2019-07-02 阵雨
# 2019-07-03 中雨
# 2019-07-04 阵雨
# 2019-07-05 阵雨
# 珠海 2019-07-01 阵雨
# 2019-07-02 中雨
# 2019-07-03 中雨
# 2019-07-04 阵雨
# 2019-07-05 阵雨
# 番禺 2019-07-01 雷阵雨
# 2019-07-02 中雨
# 2019-07-03 大雨
# 2019-07-04 中雨
# 2019-07-05 雷阵雨
# Name: (白天, 天气状况), dtype: object
# =============================================================================
# 3. 通过Series的Map方法 -> 匿名函数(lambda)find方法进行数据值的模糊匹配,'> -1'表示数据是否包含对应值
cond = df[cols].map(lambda x: x.find('雨') > -1)
cond
# =============================================================================
# Out[43]:
# 城市 日期
# 中山 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 True
# 2019-07-04 False
# 2019-07-05 False
# 博罗 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 True
# 2019-07-04 True
# 2019-07-05 True
# 珠海 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 True
# 2019-07-04 True
# 2019-07-05 True
# 番禺 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 True
# 2019-07-04 True
# 2019-07-05 True
# Name: (白天, 天气状况), dtype: bool
# =============================================================================
# 4. 再次传入DataFrame按条件提取数据
df[cond]
# =============================================================================
# Out[41]:
# 白夜 白天 夜间
# 指标 天气状况 风力方向 最高温度 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 27
# 2019-07-02 阵雨 无持续风向 1-2级 34 大雨 无持续风向 1-2级 26
# 2019-07-03 中雨 无持续风向 1-2级 29 大雨 无持续风向 1-2级 25
# 博罗 2019-07-01 雷阵雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 27
# 2019-07-02 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 25
# 2019-07-03 中雨 无持续风向 1-2级 28 中雨 无持续风向 1-2级 25
# 2019-07-04 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 25
# 2019-07-05 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 25
# 珠海 2019-07-01 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 28
# 2019-07-02 中雨 东风 3-4级 31 中雨 东风 3-4级 25
# 2019-07-03 中雨 东南风 3-4级 29 中雨 东南风 3-4级 25
# 2019-07-04 阵雨 南风 3-4级 30 多云 南风 3-4级 26
# 2019-07-05 阵雨 西南风 3-4级 31 多云 西南风 3-4级 26
# 番禺 2019-07-01 雷阵雨 无持续风向 1-2级 34 中雨 无持续风向 1-2级 28
# 2019-07-02 中雨 无持续风向 1-2级 34 大雨 无持续风向 1-2级 26
# 2019-07-03 大雨 东南风 3-4级 30 大雨 东南风 3-4级 26
# 2019-07-04 中雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 26
# 2019-07-05 雷阵雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 27
# =============================================================================
#%%
# 多条件合并进行数据过滤
# Case Study 1: 筛选出'白天'或'夜间',天气状况为:'阵雨'的数据
# 1. 定义布尔列, 通过Python的Unpacking 语法,即解包概念赋值
cols1, cols2 = ('白天' ,'天气状况'), ('夜间', '天气状况')
# 2. 通过DataFrame[布尔列]对布尔列的Series数据进行判断
cond1 = (df[cols1] == '阵雨') # 对'白天'所有数据是否等于'阵雨'进行判断
# =============================================================================
# Out[52]:
# 城市 日期
# 中山 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 博罗 2019-07-01 False
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 珠海 2019-07-01 True
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 番禺 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# Name: (白天, 天气状况), dtype: bool
# =============================================================================
cond2 = (df[cols2] == '阵雨') # 对'夜间'所有数据是否等于'阵雨'进行判断
# =============================================================================
# Out[53]:
# 城市 日期
# 中山 2019-07-01 True
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 博罗 2019-07-01 False
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 珠海 2019-07-01 True
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 番禺 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# Name: (夜间, 天气状况), dtype: bool
# =============================================================================
# 3. 条件合并,定义合并条件参数,'|'表示或者(Or)的概念
cond = cond1 | cond2
cond
# =============================================================================
# Out[55]:
# 城市 日期
# 中山 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 博罗 2019-07-01 False
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 珠海 2019-07-01 True
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 番禺 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# dtype: bool
# =============================================================================
# 4. 传入DataFrame[cond]筛选出布尔值为True的数据
df[cond]
# =============================================================================
# Out[56]:
# 白夜 白天 夜间
# 指标 天气状况 风力方向 最高温度 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 27
# 2019-07-02 阵雨 无持续风向 1-2级 34 大雨 无持续风向 1-2级 26
# 博罗 2019-07-02 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 25
# 2019-07-04 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 25
# 2019-07-05 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 25
# 珠海 2019-07-01 阵雨 无持续风向 1-2级 32 阵雨 无持续风向 1-2级 28
# 2019-07-04 阵雨 南风 3-4级 30 多云 南风 3-4级 26
# 2019-07-05 阵雨 西南风 3-4级 31 多云 西南风 3-4级 26
# =============================================================================
# Case Study 2: 筛选出'白天'且'夜间',天气状况为:'中雨'的数据
# 1. 构建符合条件的列索引
cols1, cols2 = ('白天', '天气状况'), ('夜间', '天气状况')
# 2. 通过DataFrame构建布尔过滤并传给条件参数
cond1 = (df[cols1] == '中雨')
cond2 = (df[cols2] == '中雨')
# 通过Python解包语法赋值
# cond1, cond2 = (df[cols1] == '多云'), (df[cols2] == '多云')
# 3. 通过'&'符号,实现条件的交集,即:既符合cond1,也符合cond2的数据
cond = cond1 & cond2
cond
# =============================================================================
# Out[82]:
# 城市 日期
# 中山 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 博罗 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 珠海 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 番禺 2019-07-01 False
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# dtype: bool
# =============================================================================
# 4. 最终条件参数(布尔过滤)赋值给DataFrame,筛选出布尔值为True的数据
df[cond]
# =============================================================================
# Out[94]:
# 白夜 白天 夜间
# 指标 天气状况 风力方向 最高温度 天气状况 风力方向 最高温度
# 城市 日期
# 博罗 2019-07-03 中雨 无持续风向 1-2级 28 中雨 无持续风向 1-2级 25
# 珠海 2019-07-02 中雨 东风 3-4级 31 中雨 东风 3-4级 25
# 2019-07-03 中雨 东南风 3-4级 29 中雨 东南风 3-4级 25
# =============================================================================
#%%
# 通过Query方法进行过滤
# @外星人学Python,提示过Query方法对多级索引支持的不太好,因此通过一级索引数据进行演示)
# 通过标签索引提取'白天'的数据,并赋值给df_day
df_day = df.loc[:, '白天']
# 等同于df_day = df['白天']
df_day
# =============================================================================
# Out[103]:
# 指标 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33
# 2019-07-02 阵雨 无持续风向 1-2级 34
# 2019-07-03 中雨 无持续风向 1-2级 29
# 2019-07-04 多云 无持续风向 1-2级 33
# 2019-07-05 多云 无持续风向 1-2级 34
# 博罗 2019-07-01 雷阵雨 无持续风向 1-2级 33
# 2019-07-02 阵雨 无持续风向 1-2级 33
# 2019-07-03 中雨 无持续风向 1-2级 28
# 2019-07-04 阵雨 无持续风向 1-2级 32
# 2019-07-05 阵雨 无持续风向 1-2级 32
# 珠海 2019-07-01 阵雨 无持续风向 1-2级 32
# 2019-07-02 中雨 东风 3-4级 31
# 2019-07-03 中雨 东南风 3-4级 29
# 2019-07-04 阵雨 南风 3-4级 30
# 2019-07-05 阵雨 西南风 3-4级 31
# 番禺 2019-07-01 雷阵雨 无持续风向 1-2级 34
# 2019-07-02 中雨 无持续风向 1-2级 34
# 2019-07-03 大雨 东南风 3-4级 30
# 2019-07-04 中雨 无持续风向 1-2级 33
# 2019-07-05 雷阵雨 无持续风向 1-2级 33
# =============================================================================
df_day.query(' 最高温度 == 33 | 最高温度 == 34')
# =============================================================================
# Out[105]:
# 指标 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33
# 2019-07-02 阵雨 无持续风向 1-2级 34
# 2019-07-04 多云 无持续风向 1-2级 33
# 2019-07-05 多云 无持续风向 1-2级 34
# 博罗 2019-07-01 雷阵雨 无持续风向 1-2级 33
# 2019-07-02 阵雨 无持续风向 1-2级 33
# 番禺 2019-07-01 雷阵雨 无持续风向 1-2级 34
# 2019-07-02 中雨 无持续风向 1-2级 34
# 2019-07-04 中雨 无持续风向 1-2级 33
# 2019-07-05 雷阵雨 无持续风向 1-2级 33
# =============================================================================
df_day.query(' 32 < 最高温度 < 34')
# =============================================================================
# Out[107]:
# 指标 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33
# 2019-07-04 多云 无持续风向 1-2级 33
# 博罗 2019-07-01 雷阵雨 无持续风向 1-2级 33
# 2019-07-02 阵雨 无持续风向 1-2级 33
# 番禺 2019-07-04 中雨 无持续风向 1-2级 33
# 2019-07-05 雷阵雨 无持续风向 1-2级 33
# =============================================================================
df_day.query('天气状况 == "阵雨" and 最高温度 < 33')
# 先定义条件参数,再通过Query方法筛选数据
cond = ('天气状况 == "阵雨" & 最高温度 < 33')
# =============================================================================
# 等同于下面语句
# cond = (
# '天气状况 == "阵雨"'
# '& 最高温度 < 33'
# )
# =============================================================================
df_day.query(cond)
# =============================================================================
# Out[136]:
# 指标 天气状况 风力方向 最高温度
# 城市 日期
# 博罗 2019-07-04 阵雨 无持续风向 1-2级 32
# 2019-07-05 阵雨 无持续风向 1-2级 32
# 珠海 2019-07-01 阵雨 无持续风向 1-2级 32
# 2019-07-04 阵雨 南风 3-4级 30
# 2019-07-05 阵雨 西南风 3-4级 31
# =============================================================================
# 通过外部变量@,构建条件参数
values = ("多云","中雨")
temp = 33
cond = ('天气状况 in @values and 最高温度 >= @temp')
df_day.query(cond)
# =============================================================================
# Out[146]:
# 指标 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-04 多云 无持续风向 1-2级 33
# 2019-07-05 多云 无持续风向 1-2级 34
# 番禺 2019-07-02 中雨 无持续风向 1-2级 34
# 2019-07-04 中雨 无持续风向 1-2级 33
# =============================================================================
#%%
# 多层索引的Query方法,当列索引为多层时,需要通过外部变量引入列
cond = ('@df.白天.最高温度 >= 32 and @df.夜间.最高温度 == 27')
df.query(cond)
# =============================================================================
# Out[157]:
# 白夜 白天 夜间
# 指标 天气状况 风力方向 最高温度 天气状况 风力方向 最高温度
# 城市 日期
# 中山 2019-07-01 阵雨 无持续风向 1-2级 33 阵雨 无持续风向 1-2级 27
# 2019-07-05 多云 无持续风向 1-2级 34 多云 无持续风向 1-2级 27
# 博罗 2019-07-01 雷阵雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 27
# 番禺 2019-07-05 雷阵雨 无持续风向 1-2级 33 雷阵雨 无持续风向 1-2级 27
# =============================================================================
# 下面两种写法结果一致
df.loc[:, ('白天', '最高温度')] >=32
df.白天.最高温度 >= 32
# =============================================================================
# Out[165]:
# 城市 日期
# 中山 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 博罗 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# 珠海 2019-07-01 True
# 2019-07-02 False
# 2019-07-03 False
# 2019-07-04 False
# 2019-07-05 False
# 番禺 2019-07-01 True
# 2019-07-02 True
# 2019-07-03 False
# 2019-07-04 True
# 2019-07-05 True
# Name: 最高温度, dtype: bool
# =============================================================================
# Bonus: 筛选出全天温度在25 ~ 32度的数据
cond = (
'25 <= @df.白天.最高温度 <= 32'
'and 25 <= @df.夜间.最高温度 <= 32'
)
df.query(cond)
总结
Pandas过滤数据有布尔列过滤,Series.map方法,Query方法等;
布尔列过滤的两个步骤如下:
- 构建布尔列
- 通过DataFrame传入布尔列:df[布尔列],得到条件为True的数据
Series.map方法,需要通过匿名函数lambda,find方法进行数据的模糊匹配。
Query方法理解起来比较相对容易,原作者也提到相对于标签索引构造的布尔列性能较高,且能够通过字符串构造筛选条件,应当在实战中优先考虑。
下面是今天的Mindmap
文末彩蛋:Pandas Cheatsheet
近期在读WesMckinney大神的《Python for Data Analysis》2nd Edition英文原版,无意间在网上发现了下面的Pandas Cheatsheet,分享给大家~ 希望大家一起努力,理解Pandas,掌握数据分析的原理和方法,早日得到大厂青睐,P8,P9指日可待