Pandas 查询筛选数据

Pandas 查询筛选数据

《Pandas 教程》 修订中,可作为 Pandas 入门进阶课程、Pandas 中文手册、用法大全,配有案例讲解和速查手册。提供建议、纠错、催更等加作者微信: sinbam 和关注公众号「盖若」ID: gairuo。查看更新日志

数据有选择是 Pandas 最基础的使用,我们通过各种条件的组合可以模拟 Excel 的筛选操作。Pandas 也能实现类似列表的切片的操作。

注:本文所使用的 dfs数据信息一文中的数据。

数据检查

我们一拿到数据需要对数据有一个抽查,一方面是了解数据结构,另一方面随机检查一下数据的质量问题。常用的:

语法操作返回结果
df.head(n)查看 DataFrame 对象的前n行DataFrame
df.tail(n)查看 DataFrame 对象的最后n行DataFrame
df.sample(n)查看 n 个样本,随机DataFrame

以上都是选择整行。

查看头部 df.head()

每次加载数据后一般需要看一下头部数据

df.head()
'''
    name team  Q1  Q2  Q3  Q4
0  Liver    E  89  21  24  64
1   Arry    C  36  37  37  57
2    Ack    A  57  60  18  84
3  Eorge    C  93  96  71  78
4    Oah    D  65  49  61  86
'''

# 可指定数量
df.head(15)

查看尾部 df.tail()

查看最后的尾部数据。

df.head()
'''
        name team  Q1  Q2  Q3  Q4
95   Gabriel    C  48  59  87  74
96   Austin7    C  21  31  30  43
97  Lincoln4    C  98  93   1  20
98       Eli    E  11  74  58  91
99       Ben    E  21  43  41  74
'''

# 可指定数量
df.tail(15)

查看样本 df.sample()

df.sample() 会随机返回一条样本数据。

df.sample()
'''
     name team  Q1  Q2  Q3  Q4
79  Tyler    A  75  16  44  63
'''

# 可指定数量
df.sample(15)

数据截取:

# 去掉索引之前和之后的数据
df.truncate(before=2, after=4) # 只要索引 2-4
s.truncate(before="60", after="66")
df.truncate(before="A", after="B", axis="columns") # 选取列

操作列

以下两种方法都可以代表一列:

df['name'] # 会返回本列的 Series
df.name
df.Q1
# df.1Q 即使列名叫 1Q 也无法使用
# df.my name 有空格也无法调用,可以处理加上下划线

注意,当列名为一个合法的 python 变量时可以直接作为属性去使用。

选择部分行列

有时我们需要按条件选择部分列、部分行,一般常用的有:

操作语法返回结果
选择列df[col]Series
按索引选择行df.loc[label]Series
按数字索引选择行df.iloc[loc]Series
使用切片选择行df[5:10]DataFrame
用表达式筛选行df[bool_vec]DataFrame

以上操作称为 Fancy Indexing(花式索引),它来自 Numpy,是指传递一个索引序列,然后一次性得到多个索引元素。Fancy Indexing 和 slicing 不同,它通常将元素拷贝到新的数据对象中。索引中可以有切片 slice,或者省略 ellipsis、新轴 newaxis、布尔数组或者整数数组索引等,可以看做是一个多维切片。

接下来我们将重点介绍一下这些查询的方法。

切片 []

我们可以像列表那样利用切片功能选择部分行的数据,但是不支持索引一条:

df[:2] # 前两行数据
df[4:10]
df[:] # 所有数据,一般没这么用的
df[:10:2] # 按步长取
s[::-1] # 反转顺序

也可以选择列:

df['name'] # 只要一列,Series
df[['Q1', 'Q2']] # 选择两列
df[['name']] # 选择一列,返回 DataFrame,注意和上例区别

按标签 .loc

df.loc() 的格式为 df.loc[<索引表达式>, <列表达式>],表达式支持以下形式:

单个标签:

# 代表索引,如果是字符需要加引号
df.loc[0] # 选择索引为 0 的行
df.loc[8]

单个列表标签:

df.loc[[0,5,10]] # 指定索引 0,5,10 的行
df.loc[['Eli', 'Ben']] # 如果索引是 name
# 真假选择,长度要和索引一样
df.loc[[False, True]*50] # 为真的列显示,隔一个显示一个

带标签的切片,包括起始和停止start:stop, 可以其中只有一个,返回包括它们的数据:

df.loc[0:5] # 索引切片, 代表0-5行,包括5
df.loc['2010':'2014'] # 如果索引是时间可以用字符查询
df.loc[:] # 所有
# 本方法支持 Series

进行切片操作,索引必须经过排序,意味着索引单调递增或者单调递减,以下代码中其中一个为 True,否则会引发 KeyError 错误。

# 索引单调性
(
    df.index.is_monotonic_increasing,
    df.index.is_monotonic_decreasing
)
# (True, False)

通过上边的规则可以先对索引排序再执行词义上的查询,如:

# 姓名开头从 Ad 到 Bo 的
df.set_index('name').sort_index().loc['Ad':'Bo']
# 姓名开头从开始到 Bo 的
df.set_index('name').sort_index().loc[:'Bo']
# 团队名称从 C 到 D 的
df.set_index('team').sort_index().loc['C': 'D']
# 姓名开头从 Te 到 X 的
df.sort_values('name').set_index('name').loc['Te': 'X']

列筛选,必须有行元素:

dft.loc[:, ['Q1', 'Q2']] # 所有行,Q1 和 Q2两列
dft.loc[:, ['Q1', 'Q2']] # 所有行,Q1 和 Q2两列
dft.loc[:10, 'Q1':] # 0-10 行,Q1后边的所有列

按位置 .iloc

df.ilocdf.loc 相似,但只能用自然索引(行和列的 0 - n 索引),不能用标签。

df.iloc[:3]
df.iloc[:]
df.iloc[:, [1, 2]]
df.iloc[2:20:3]
s.iloc[:3]

如果想筛选多个不连续的行列数据(使用 np.r_),可以使用以下方法:

# 筛选索引0-4&10&5-29每两行取一个&70-74
df.iloc[np.r_[:5, 10, 15:30:2, 70:75]] # 行
df.iloc[:, np.r_[0, 2:6]] # 列,0列和第2-5列
# 也可以使用追加的方式拼接
df.loc[:5].append(df.loc[10]).append(df.loc[15:30:2])

取具体值 .at

类似于 loc, 但仅取一个具体的值,结构为 at[<索引>,<列名>]:

# 注:索引是字符需要加引号
df.at[4, 'Q1'] # 65
df.at['lily', 'Q1'] # 65 假定索引是 name
df.at[0, 'name'] # 'Liver'
df.loc[0].at['name'] # 'Liver'
# 指定列的值对应其他列的值
df.set_index('name').at['Eorge', 'team'] # 'C'
df.set_index('name').team.at['Eorge'] # 'C'
# 指定列的对应索引的值
df.team.at[3] # 'C'

同样 iat 和 iloc 一样,仅支持数字索引:

df.iat[4, 2] # 65
df.loc[0].iat[1] # 'E'

.get 可以做类似字典的操作,如果无值给返回默认值(例中是0):

df.get('name', 0) # 是 name 列
df.get('nameXXX', 0) # 0, 返回默认值
s.get(3, 0) # 93, Series 传索引返回具体值
df.name.get(99, 0) # 'Ben'

表达式筛选

[] 切片里可以使用表达式进行筛选:

df[df['Q1'] == 8] # Q1 等于8
df[~(df['Q1'] == 8)] # 不等于8
df[df.name == 'Ben'] # 姓名为Ben
df.loc[df['Q1'] > 90, 'Q1':]  # Q1 大于90,显示Q1后边的所有列
df.loc[(df.Q1 > 80) & (df.Q2 < 15)] # and 关系
df.loc[(df.Q1 > 90) | (df.Q2 < 90)] # or 关系
df[df.Q1 > df.Q2]

df.loc 里的索引部分可以使用表达式进行数据筛选。

df.loc[df['Q1'] == 8] # 等于8
df.loc[df.Q1 == 8] # 等于8
df.loc[df['Q1'] > 90, 'Q1':] # Q1 大于90,只显示 Q1
# 其他表达式与切片一致

# 通过列位置筛选列
df.loc[:, lambda df: df.columns.str.len()==4] # 真假组成的序列
df.loc[:, lambda df: [i for i in df.columns if 'Q' in i]] # 列名列表
df.iloc[:3, lambda df: df.columns.str.len()==2] # 真假组成的序列

逻辑判断和函数:

df.eq() # 等于相等 ==
df.ne() # 不等于 !=
df.le() # 小于等于 >=
df.lt() # 小于 <
df.ge() # 大于等于 >=
df.gt() # 大于 >
# 都支持  axis{0 or ‘index’, 1 or ‘columns’}, default ‘columns’
df[df.Q1.ne(89)] # Q1 不等于8
df.loc[df.Q1.gt(90) & df.Q2.lt(90)] # and 关系 Q1>90 Q2<90

其他函数:

# isin
df[df.team.isin(['A','B'])] # 包含 AB 两组的
df[df.isin({'team': ['C', 'D'], 'Q1':[36,93]})] # 复杂查询,其他值为 NaN

函数筛选

函数生成具体的标签值或者同长度对应布尔索引,作用于筛选:

df[lambda df: df['Q1'] == 8] # Q1为8的
df.loc[lambda df: df.Q1 == 8, 'Q1':'Q2'] # Q1为8的, 显示 Q1 Q2
# 选择字段时尽量使用字典法,属性法在条件表达式时一些情况可能有 bug

函数不仅能应用在行位上,也能应用在列位上。

where 和 mask

s.where(s > 90) # 不符合条件的为 NaN
s.where(s > 90, 0) # 不符合条件的为 0
# np.where, 大于80是真否则是假
np.where(s>80, True, False)
np.where(df.num>=60, '合格', '不合格')

s.mask(s > 90) # 符合条件的为 NaN
s.mask(s > 90, 0) # 符合条件的为 0

# 例:能被整除的显示,不能的显示相反数
m = df.loc[:,'Q1':'Q4'] % 3 == 0
df.loc[:,'Q1':'Q4'].where(m, -df.loc[:,'Q1':'Q4'])

# 行列相同数量,返回一个 array
df.lookup([1,3,4], ['Q1','Q2','Q3']) # array([36, 96, 61])
df.lookup([1], ['Q1']) # array([36])

mask 和 where 还可以通过数据筛选返回布尔序列:

# 返回布尔序列,符合条件的行为 True
(df.where((df.team=='A') & (df.Q1>60)) == df).Q1

# 返回布尔序列,符合条件的行为 False
(df.mask((df.team=='A') & (df.Q1>60)) == df).Q1

query

df.query('Q1 > Q2 > 90') # 直接写类型 sql where 语句
df.query('Q1 + Q2 > 180')
df.query('Q1 == Q2')
df.query('(Q1<50) & (Q2>40) and (Q3>90)')
df.query('Q1 > Q2 > Q3 > Q4')
df.query('team != "C"')
df.query('team not in ("E","A","B")')
# 对于名称中带有空格的列,可以使用反引号引起来
df.query('B == `team name`')

# 支持传入变量,如:大于平均分40分的
a = df.Q1.mean()
df.query('Q1 > @a+40')
df.query('Q1 > `Q2`+@a')

# df.eval() 用法与 df.query 类似
df[df.eval("Q1 > 90 > Q3 > 10")]
df[df.eval("Q1 > `Q2`+@a")]

filter

使用 filter 可以对行名和列名进行筛选。

df.filter(items=['Q1', 'Q2']) # 选择两列
df.filter(regex='Q', axis=1) # 列名包含Q的
df.filter(regex='e$', axis=1) # 以 e 结尾的
df.filter(regex='1$', axis=0) # 正则, 索引名包含1的
df.filter(like='2', axis=0) # 索引中有2的
# 索引中2开头列名有Q的
df.filter(regex='^2', axis=0).filter(like='Q', axis=1)

索引选择器 pd.IndexSlice

pd.IndexSlice 的使用方法类似于df.loc[] 切片中的方法,常用在多层索引中,以及需要指定应用范围(subset 参数)的函数中,特别是在链式方法中。

df.loc[pd.IndexSlice[:, ['Q1', 'Q2']]]
# 变量化使用
idx = pd.IndexSlice
df.loc[idx[:, ['Q1', 'Q2']]]
df.loc[idx[:, 'Q1':'Q4'], :] # 多索引

复杂的选择:

# 创建复杂条件选择器
selected = df.loc[(df.team=='A') & (df.Q1>90)]
idxs = pd.IndexSlice[selected.index, 'name']
# 应用选择器
df.loc[idxs]
# 选择这部分区域加样式(样式功能见教程后文介绍)
df.style.applymap(style_fun, subset=idxs)

按数据类型

可以只选择或者排除指定类型数据:

df.select_dtypes(include=['float64']) # 选择 float64 型数据
df.select_dtypes(include='bool')
df.select_dtypes(include=['number']) # 只取数字型
df.select_dtypes(exclude=['int']) # 排除 int 类型
df.select_dtypes(exclude=['datetime64'])

any 和 all

any 方法如果至少有一个值为 True 是便为 True,all 需要所有值为 True 才为 True。它们可以传入 axis 为 1,会按行检测。

# Q1 Q2 成绩全为 80 分的
df[(df.loc[:,['Q1','Q2']] > 80).all(1)]
# Q1 Q2 成绩至少有一个 80 分的
df[(df.loc[:,['Q1','Q2']] > 80).any(1)]

理解筛选原理

df[<表达式>] 里边的表达式如果单独拿出来,可以看到:

df.Q1.gt(90)
'''
0     False
1     False
2     False
3      True
4     False
      ...
Name: Q1, Length: 100, dtype: bool
'''

会有一个由真假值组成的数据,筛选后的结果就是为 True 的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值