使用query()方法根据pandas.DataFrame的列值的条件提取行。它很方便,因为您可以使用比较运算符和字符串方法以及多个条件的组合来简洁地描述条件规范。
目录
有关布尔索引的条件指定,请参阅以下文章。
本文示例代码的pandas版本为2.0.3版本。请注意,行为可能因版本而异。
import pandas as pd
print(pd.__version__)
# 2.0.3
df = pd.read_csv('data/sample_pandas_normal.csv')
print(df)
# name age state point
# 0 Alice 24 NY 64
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
# 4 Ellen 24 CA 88
# 5 Frank 30 NY 57
在 pandas 中,您可以使用比较运算符来提取行,如下所示:
print(df[df['age'] < 25])
# name age state point
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
可以使用 query() 方法通过字符串指定类似的条件。
print(df.query('age < 25'))
# name age state point
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
在变量名前面加上 @ 前缀以在条件字符串中使用该变量。
val = 25
print(df.query('age < @val'))
# name age state point
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
可以使用两个比较运算符来指定范围,就像 Python 的条件规范一样。
print(df.query('30 <= age < 50'))
# name age state point
# 1 Bob 42 CA 92
# 5 Frank 30 NY 57
还可以比较列并通过使用算术运算符进行计算来比较它们。
print(df.query('age < point / 3'))
# name age state point
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
==、!= 表示匹配和不匹配。请注意,条件字符串中的字符串必须加引号。
双引号 " 可以用在单引号 ’ 括起来的字符串中,单引号 ’ 可以用在双引号 " 括起来的字符串中。可以通过使用反斜杠 \ 转义来使用相同的符号。
print(df.query('state == "CA"'))
# name age state point
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
使用变量时不必担心引号。
s = 'CA'
print(df.query('state != @s'))
# name age state point
# 0 Alice 24 NY 64
# 3 Dave 68 TX 70
# 5 Frank 30 NY 57
isin() 是一个返回 bool (True, False) 的方法,判断列 (pandas.Series) 元素是否包含在参数列表中。可以使用它来提取列中元素与特定值匹配的行。
print(df[df['state'].isin(['NY', 'TX'])])
# name age state point
# 0 Alice 24 NY 64
# 3 Dave 68 TX 70
# 5 Frank 30 NY 57
在 query() 方法中使用 in 可以进行等效处理。
print(df.query('state in ["NY", "TX"]'))
# name age state point
# 0 Alice 24 NY 64
# 3 Dave 68 TX 70
# 5 Frank 30 NY 57
作为一种特殊用法,列表的 == 也以同样的方式处理。
print(df.query('state == ["NY", "TX"]'))
# name age state point
# 0 Alice 24 NY 64
# 3 Dave 68 TX 70
# 5 Frank 30 NY 57
还可以使用列表变量。
l = ['NY', 'TX']
print(df.query('state in @l'))
# name age state point
# 0 Alice 24 NY 64
# 3 Dave 68 TX 70
# 5 Frank 30 NY 57
可以使用上面的 == 或 in 指定完整字符串匹配的条件,但使用字符串方法 str.xxx() 来指定部分匹配条件。
参考一下的方法:
print(df.query('name.str.endswith("e")'))
# name age state point
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
print(df.query('name.str.contains("li")'))
# name age state point
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
可以通过使用 astype() 将除 string 之外的 dtype 类型列转换为字符串类型 str 来使用字符串方法。这也可以用 query() 指定。
print(df.query('age.astype("str").str.endswith("8")'))
# name age state point
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
请注意,如果使用字符串方法作为缺失值 NaN 或 None 的列的条件,则会出现错误。
df.at[0, 'name'] = None
print(df)
# name age state point
# 0 None 24 NY 64
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
# 4 Ellen 24 CA 88
# 5 Frank 30 NY 57
# print(df.query('name.str.endswith("e")'))
# ValueError: unknown type object
许多字符串方法允许参数 na 指定一个值来替换 None 或缺失值 NaN 的结果。指定 True 则提取包含缺失值的行,指定 False 则不提取包含缺失值的行。
print(df[df['name'].str.endswith('e', na=False)])
# name age state point
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
可以以与 query() 相同的方式指定参数。
print(df.query('name.str.endswith("e", na=False)'))
# name age state point
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
可以使用index.index指定条件(行名)。
df = pd.read_csv('data/sample_pandas_normal.csv')
print(df.query('index % 2 == 0'))
# name age state point
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
如果索引有名称,则可以是该名称或索引。
df_name = df.set_index('name')
print(df_name)
# age state point
# name
# Alice 24 NY 64
# Bob 42 CA 92
# Charlie 18 CA 70
# Dave 68 TX 70
# Ellen 24 CA 88
# Frank 30 NY 57
print(df_name.query('name.str.endswith("e")'))
# age state point
# name
# Alice 24 NY 64
# Charlie 18 CA 70
# Dave 68 TX 70
print(df_name.query('index.str.endswith("e")'))
# age state point
# name
# Alice 24 NY 64
# Charlie 18 CA 70
# Dave 68 TX 70
当用布尔索引指定多个条件时,描述如下。
print(df[(df['age'] < 25) & (df['point'] > 65)])
# name age state point
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
query()方法可以写成如下。每个条件不需要括号,AND(和)可以是 & 或 and。
print(df.query('age < 25 & point > 65'))
# name age state point
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
print(df.query('age < 25 and point > 65'))
# name age state point
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
OR(或)、| 或或都是可接受的。
print(df.query('age < 20 | point > 80'))
# name age state point
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
print(df.query('age < 20 or point > 80'))
# name age state point
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
NOT(否定)not。
print(df.query('not age < 25 and not point > 65'))
# name age state point
# 5 Frank 30 NY 57
对于三个或三个以上的条件也是如此,但结果根据顺序不同而不同,例如 & 的优先级高于 |,因此将要首先处理的部分显式括在括号中会更安全。
print(df.query('age == 24 | point > 80 & state == "CA"'))
# name age state point
# 0 Alice 24 NY 64
# 1 Bob 42 CA 92
# 4 Ellen 24 CA 88
print(df.query('(age == 24 | point > 80) & state == "CA"'))
# name age state point
# 1 Bob 42 CA 92
# 4 Ellen 24 CA 88
使用 query() 方法时要小心列名。例如,按如下方式更改列名称。
df.columns = ['0name', 'age.year', 'state name', 3]
print(df)
# 0name age.year state name 3
# 0 Alice 24 NY 64
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
# 4 Ellen 24 CA 88
# 5 Frank 30 NY 57
使用作为 Python 变量名无效的列名将导致错误。例如,以数字开头的列名、包含 . 或空格的列名都是错误的。
# print(df.query('0name.str.endswith("e")'))
# SyntaxError: invalid syntax
# print(df.query('age.year < 25'))
# UndefinedVariableError: name 'age' is not defined
# print(df.query('state name == "CA"'))
# SyntaxError: invalid syntax
必须用“`”括起来。
print(df.query('`0name`.str.endswith("e")'))
# 0name age.year state name 3
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
print(df.query('`age.year` < 25'))
# 0name age.year state name 3
# 0 Alice 24 NY 64
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
print(df.query('`state name` == "CA"'))
# 0name age.year state name 3
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88
即使数字列名包含在“`”中也会发生错误。如果使用布尔索引指定条件,则没有问题。
# print(df.query('3 > 75'))
# KeyError: False
# print(df.query('`3` > 75'))
# UndefinedVariableError: name 'BACKTICK_QUOTED_STRING_3' is not defined
print(df[df[3] > 75])
# 0name age.year state name 3
# 1 Bob 42 CA 92
# 4 Ellen 24 CA 88
在到目前为止的示例中,返回一个新的 pandas.DataFrame,其中包含通过 query() 提取的行,并且原始对象保持原样。参数 inplace=True 将更改原始对象本身。
df = pd.read_csv('data/sample_pandas_normal.csv')
df.query('age > 25', inplace=True)
print(df)
# name age state point
# 1 Bob 42 CA 92
# 3 Dave 68 TX 70
# 5 Frank 30 NY 57