三过滤数据
Posted 5250
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三过滤数据相关的知识,希望对你有一定的参考价值。
数据表中的数据一般都是非常大,我们一般只需要查询特定的数据
3.1 where单一子句
>>> select * from trade WHERE trade_date=\'20230313\'; #匹配查询
>>> select user_id,product_id,order_id form trade WHERE user_id=\'tom\'; #匹配查询特定列
>>> select * from trade WHERE qty <> 50000; #不匹配查询
>>> select * from trade WHERE price between 10.00 and 105.00; #范围查询,还有范围:in
>>> select * from trade WHERE ext_fields IS NULL; #空值检查
where子句操作符:=,<>,!=,>,>=,<,<=, between...and...
3.2 where多子句组合
多个子句组合需要使用逻辑操作符and, or连接(and的优先级高于or);当多个子句组合时,先执行and,再执行or.
>>> select * from trade where user_id=\'tom\' AND trade_date>=20230121;
>>> select * from trade where trade_date=20230101 OR trade_date=20230202;
>>> select * from trade where user_id not in (\'tom\',\'bill\');
>>> select * from trade where trade_date=20230101 OR trade_date=20230202 AND user_id=\'tom\';
返回结果:满足trade_date=20230101的所有数据 + 满足trade_date=20230202 AND user_id=\'tom\'的所有数据
3.3 通配符过滤
like操作符,模糊搜索。 与%连用。 %表示任意字符出现任意次数; _表示任意字符出现一次。
>>> select * from trade where product_id like \'jet%\'; #查找以jet开头的所有产品
>>> select * from trade where product_id like \'%com\'; #查找以jet结尾的所有产品
>>> select * from trade where product_id like \'j%com\'; #查找以j开头,以jet结尾的所有产品
>>> select * from trade where product_id like \'jet_\'; #查找以jet开头的所有产品(产品名称长度4个字符)
3.4 过滤后排序
先过滤,再排序
>>> select * from trade where product_id like \'jet%\' order by trade_date DESC;
动态过滤熊猫数据框
【中文标题】动态过滤熊猫数据框【英文标题】:Dynamically filtering a pandas dataframe 【发布时间】:2018-02-06 02:19:36 【问题描述】:我正在尝试使用三列的阈值过滤熊猫数据框
import pandas as pd
df = pd.DataFrame("A" : [6, 2, 10, -5, 3],
"B" : [2, 5, 3, 2, 6],
"C" : [-5, 2, 1, 8, 2])
df = df.loc[(df.A > 0) & (df.B > 2) & (df.C > -1)].reset_index(drop = True)
df
A B C
0 2 5 2
1 10 3 1
2 3 6 2
但是,我想在一个函数中执行此操作,其中列的名称及其阈值在字典中提供给我。这是我的第一次尝试,效果很好。本质上,我将过滤器放在 cond
变量中并运行它:
df = pd.DataFrame("A" : [6, 2, 10, -5, 3],
"B" : [2, 5, 3, 2, 6],
"C" : [-5, 2, 1, 8, 2])
limits_dic = "A" : 0, "B" : 2, "C" : -1
cond = "df = df.loc["
for key in limits_dic.keys():
cond += "(df." + key + " > " + str(limits_dic[key])+ ") & "
cond = cond[:-2] + "].reset_index(drop = True)"
exec(cond)
df
A B C
0 2 5 2
1 10 3 1
2 3 6 2
现在,最后我把所有东西都放在一个函数中,它停止工作(也许exec
函数不喜欢在函数中使用!):
df = pd.DataFrame("A" : [6, 2, 10, -5, 3],
"B" : [2, 5, 3, 2, 6],
"C" : [-5, 2, 1, 8, 2])
limits_dic = "A" : 0, "B" : 2, "C" : -1
def filtering(df, limits_dic):
cond = "df = df.loc["
for key in limits_dic.keys():
cond += "(df." + key + " > " + str(limits_dic[key])+ ") & "
cond = cond[:-2] + "].reset_index(drop = True)"
exec(cond)
return(df)
df = filtering(df, limits_dic)
df
A B C
0 6 2 -5
1 2 5 2
2 10 3 1
3 -5 2 8
4 3 6 2
我知道exec
函数在函数内部使用时的行为有所不同,但不知道如何解决该问题。另外,我想知道在给定两个输入的情况下,必须有一种更优雅的方法来定义一个函数来进行过滤:1)df
和 2)limits_dic = "A" : 0, "B" : 2, "C" : -1
。我将不胜感激。
【问题讨论】:
如果您更改结果的名称(cond = "df2 = df.loc["
和 return(locals()['df2'])
),它会起作用。我试图将字典添加到exec
无济于事
如需更多关于pd.eval()
系列函数、它们的特性和用例的信息,请访问Dynamic Expression Evaluation in pandas using pd.eval()。
【参考方案1】:
两者都张贴的替代品,可能更pythonic,也可能不是:
import pandas as pd
import operator
from functools import reduce
df = pd.DataFrame("A": [6, 2, 10, -5, 3],
"B": [2, 5, 3, 2, 6],
"C": [-5, 2, 1, 8, 2])
limits_dic = "A": 0, "B": 2, "C": -1
# equiv to [df['A'] > 0, df['B'] > 2 ...]
loc_elements = [df[key] > val for key, val in limits_dic.items()]
df = df.loc[reduce(operator.and_, loc_elements)]
【讨论】:
【参考方案2】:如何在不创建字符串和 df.query
的情况下做到这一点:
limits_dic = "A" : 0, "B" : 2, "C" : -1
cond = None
# Build the conjunction one clause at a time
for key, val in limits_dic.items():
if cond is None:
cond = df[key] > val
else:
cond = cond & (df[key] > val)
df.loc[cond]
A B C
0 2 5 2
1 10 3 1
2 3 6 2
请注意硬编码的 (>, &)
运算符(因为我想完全按照您的示例进行操作)。
【讨论】:
【参考方案3】:如果您尝试构建动态查询,有更简单的方法。这是一个使用列表理解和str.join
:
query = ' & '.join(['>'.format(k, v) for k, v in limits_dic.items()])
或者,将f
-strings 与 python-3.6+ 一起使用,
query = ' & '.join([f'k>v' for k, v in limits_dic.items()])
print(query)
'A>0 & C>-1 & B>2'
将查询字符串传递给df.query
,就是为了这个目的:
out = df.query(query)
print(out)
A B C
1 2 5 2
2 10 3 1
4 3 6 2
如果我的列名有空格或其他奇怪的字符怎么办?
从 pandas 0.25 开始,您可以将列名包含在反引号中,这样可以正常工作:
query = ' & '.join([f'`k`>v' for k, v in limits_dic.items()])
请参阅this Stack Overflow post 了解更多信息。
如果您想为查询获取布尔掩码,也可以使用df.eval
,然后索引变得简单:
mask = df.eval(query)
print(mask)
0 False
1 True
2 True
3 False
4 True
dtype: bool
out = df[mask]
print(out)
A B C
1 2 5 2
2 10 3 1
4 3 6 2
字符串数据
如果需要查询使用字符串数据的列,上面的代码需要稍作修改。
考虑(来自this answer的数据):
df = pd.DataFrame('gender':list('MMMFFF'),
'height':[4,5,4,5,5,4],
'age':[70,80,90,40,2,3])
print (df)
gender height age
0 M 4 70
1 M 5 80
2 M 4 90
3 F 5 40
4 F 5 2
5 F 4 3
还有列、运算符和值的列表:
column = ['height', 'age', 'gender']
equal = ['>', '>', '==']
condition = [1.68, 20, 'F']
这里适当的修改是:
query = ' & '.join(f'i j repr(k)' for i, j, k in zip(column, equal, condition))
df.query(query)
age gender height
3 40 F 5
有关pd.eval()
系列函数、它们的特性和用例的信息,请访问Dynamic Expression Evaluation in pandas using pd.eval()。
【讨论】:
在 f-strings 中,您可以使用上面的简写 k!r,而不是 repr(k)...有助于像上面这样的长表达式。 同一列有多个值如何处理 @Abhis 那应该是什么样子? @cs95 如果我的列名本身有一些运算符,例如C > D
,我想比较两个这样的列。我应该在每个列名周围添加双引号,并在单引号中添加整个查询吗?
关于使用“掩码”的那部分回答了我在使用“loc”以避免链式索引时如何将“查询”与选择列子集结合起来的问题。谢谢!【参考方案4】:
@coldspeed 版本的替代方案:
conditions = None
for key, val in limit_dic.items():
cond = df[key] > val
if conditions is None:
conditions = cond
else:
conditions = conditions & cond
print(df[conditions])
【讨论】:
谢谢。我找不到一种方法来使接受的答案将引用我的代码中定义的 python 列表的isin
条件结合在一起。以上是关于三过滤数据的主要内容,如果未能解决你的问题,请参考以下文章