Pandas的query
函数为我们提供了一种编写查询过滤条件更简单的方法,特别是在的查询条件很多的时候。
在开始之前,先快速回顾一下Pandas中的查询函数query
。查询函数用于根据指定的表达式提取记录,并返回一个新的DataFrame。表达式是用字符串形式表示的条件或条件的组合。
PANDAS中的DATAFRAME(.loc
和.iloc
)属性用于根据行和列标签和索引提取数据集的子集。因此,它并不具备查询的灵活性。而括号符号[]
可以灵活地基于条件过滤数据帧,但是如果条件很多的话编写代码是繁琐且容易出错的。
Pandas的query()
函数可以灵活地根据一个或多个条件提取子集,这些条件被写成表达式并且不需要考虑括号的嵌套。
在后端Pandas使用eval()
函数对该表达式进行解析和求值,并返回表达式被求值为TRUE的数据子集或记录。所以要过滤Pandas中的DataFrame,需要做的就是在查询函数中指定条件即可。
df = pd.read_csv("Dummy_Sales_Data_v1.csv")
df.head()
在单个条件下进行过滤时,在Query()函数中表达式仅包含一个条件。返回的输出将包含该表达式评估为真的所有行。
#提取数量为95的所有行
df.query("Quantity == 95")
一个或多个条件下过滤,query()的语法都保持不变
但是需要指定两个或多个条件进行过滤的方式
两者都需要满足的并列条件使用符号 &
,或 单词 and
只需要满足其中之一的条件使用符号 |
,或 单词 or
# 查询数量为95&单位价格为182
df.query("Quantity == 95 and `UnitPrice(USD)` == 182")
# 等价于
# df.query("Quantity == 95 & `UnitPrice(USD)` == 182")
当 dataframe 的列名称中有空格或其他特殊符号的时候,需要使用
反引号
(backtick mark),即键盘ESC键下面的按键(就是键盘上第二排第一个按键,有~
这个符号的按键) 来将列名包裹起来
df.query("Quantity == 95 or UnitPrice == 182")
# 等价于
# df.query("Quantity == 95 | UnitPrice == 182")
# 获得数量不等于95的所有行
df.query("not (Quantity == 95)")
# 等价于
# df.query("~(Quantity == 95)")
其实这里的条件不一定必须是相等运算符,可以从==,!=,>,<,≥,≤
中选择
对于文本列过滤时,条件是列名与字符串进行比较。
# 获得即状态“未发货”所有记录
df.query("Status == 'Not Shipped'")
df.query("Shipping_Cost*2 < 50")
# 复杂一点的数学公式
df.query("Quantity**2 + Shipping_Cost**2 < 500")
# 与常规查询对比
# df[df["Quantity"]**2 + df["Shipping_Cost"]**2<500]
Python内置函数,例如sort(),abs(),factorial(),exp()
等,也可以在查询表达式中使用。
# 查找单位价格平方根的超过15的行
df.query("sqrt(UnitPrice) > 15")
query()函数还可以在同一查询表达式将函数和数学运算整合使用
df.query("sqrt(UnitPrice) < Shipping_Cost/2")
使用query()函数在日期时间值上进行查询的唯一要求是,包含这些值的列应为数据类型dateTime64 [ns]
# 将OrderDate列改为时间格式
df["OrderDate"] = pd.to_datetime(df["OrderDate"], format="%Y-%m-%d")
为了提取有关日期的有用信息并在query()需要使用dt
提取器,dt
是一种访问对象,用于提取日期时间。
# 获得八月份所有记录
df.query("OrderDate.dt.month == 8")
所有记录都是八月份的。OrderDate.dt.month
显示了如何使用dt访问者仅提取整个日期值的月份值。
如果提取2021年8月订购日为15或以上的所有订单,可以写成这样
df.query("OrderDate.dt.month == 8 and OrderDate.dt.year == 2021 and OrderDate.dt.day >=15")
# 等价于
df.query("OrderDate >= '2021-08-15' and OrderDate <= '2021-08-31'")
df.query("OrderDate >= '2021-08-15' and OrderDate <= '2021-08-31'")[['Quantity','Shipping_Cost']]
上面的查询中都会生成一个新的df。这是因为:query()的第二个参数(inplace
)默认false
。
与一般的Pandas提供的函数一样,inplace的默认值都是false,查询不会修改原始数据集。如果我们想覆盖原始df时,需要将inplace=true。但是一定要小心使用inplace=true,因为它会覆盖原始的数据。
参考链接:Python见习室