熊猫:为什么是query()而不是括号运算符?
.query在 apandas.DataFrame和括号运算符中使用方法有什么区别?对我来说,它们似乎做同样的事情,只是语法不同。我错过了什么吗?为什么我会选择一种方式而不是另一种方式?
回答
我想说两者几乎相同,但 query() 的出现与括号运算符相比几乎没有什么好处。
根据数据的大小、所需的性能和维护代码的难易程度,总会有一些权衡。
根据熊猫文档:
易于编码和代码可维护性
您可以获得框架的值,其中 b 列的值介于 a 列和 c 列的值之间。例如:
df = DataFrame({
'a': np.random.choice(10, 5),
'b': np.random.choice(10, 5),
'c': np.random.choice(10, 5),
})
pure python
df[(df['a'] < df['b']) & (df['b'] < df['c'])]
query
df.query('(a<b) & (b<c)')
query() 的性能
对于大帧,使用 numexpr 的 DataFrame.query() 比 Python 稍快。
注意:只有当您的框架超过大约 200,000 行时,您才会看到将 numexpr 引擎与 DataFrame.query() 一起使用的性能优势。
语法比较
query()和bracket语法比较
Full numpy-like syntax:
df = pd.DataFrame(np.random.randint(n, size=(n, 3)), columns=list('abc'))
df.query('(a < b) & (b < c)')
df[(df['a'] < df['b']) & (df['b'] < df['c'])]
Slightly nicer by removing the parentheses (by binding making comparison operators bind tighter than & and |).
df.query('a < b & b < c')
Use English instead of symbols:
df.query('a < b and b < c')
Pretty close to how you might write it on paper:
df.query('a < b < c')
query() 用例
query() 的一个用例是当您有一组 DataFrame 对象时,这些对象具有共同的列名(或索引级别/名称)的子集。您可以将相同的查询传递给两个框架,而无需指定您对查询感兴趣的框架
df1 = DataFrame({
'a':np.random.choice(10, 5),
'b':np.random.choice(10, 5),
'c':np.random.choice(10, 5),
})
df2 = DataFrame({
'a':np.random.choice(np.arange(5,15,3), 8),
'b':np.random.choice(np.arange(5,13,2), 8),
'c':np.random.choice(np.arange(3,11,3), 8),
})
expr = '4<a<c<9'
map(lambda frame:frame.query(expr), [df1, df2])
可以考虑的其他一些好处
在in与not in运营商
query() 还支持 Python 的 in 和 not in 比较运算符的特殊使用,为调用 Series 或 DataFrame 的 isin 方法提供简洁的语法。
get all rows where columns "a" and "b" have overlapping values
df = pd.DataFrame({'y': list('aabbccddeeff'), 'z': list('aaaabbbbcccc'),
'c': np.random.randint(5, size=12),
'd': np.random.randint(9, size=12)})
df.query('y in z')
How you'd do it in pure Python
df[df['y'].isin(df['z'])]
df.query('y not in z')
pure Python
df[~df['y'].isin(df['z'])]
您可以将其与其他表达式结合起来进行非常简洁的查询:
rows where cols a and b have overlapping values and col c's values are less than col d's
df.query('y in z and c > d')
pure python
df[(df.y.isin(df.z)) & (df.c > df.d)]
注意:请注意 in 和 not in 在 Python 中进行计算,因为 numexpr 没有与此操作等效的操作。然而,只有 in/not in 表达式本身在 vanilla Python 中被评估。
For example, in the expression
df.query('a in b + c + d')
(b + c + d) is evaluated by numexpr and then the in operation is evaluated in plain Python. In general, any
operations that can be evaluated using numexpr will be.
==运算符与列表对象的特殊使用
Comparing a list of values to a column using ==/!= works similarly to in/not in.
df.query('z == ["y", "z", "c"]')
it is equivalent to - df.query('z in ["y", "z", "c"]')
which one is faster in or ==?
both are almost same
df.query('z == ["y", "z", "c"]')
pure python
df[df['z'].isin(['y','z','c'])]
df.query('c == [1, 2]')
df.query('c != [1, 2]')
df.query('[1, 2] in c')
df.query('[1, 2] not in c')
pure Python
df[df['c'].isin([1, 2])]
布尔运算符
You can negate boolean expressions with the word not or the ~ operator.
df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
df['bools'] = np.random.rand(len(df)) > 0.5
df.query('~bools')
df.query('not bools')
df.query('not bools') == df[~df['bools']]
Of course, expressions can be arbitrarily complex too:
short query syntax
shorter = df.query('a < b < c and (not bools) or bools > 2')
equivalent in pure Python
longer = df[(df['a'] < df['b']) & (df['b'] < df['c']) & (~df['bools']) | (df['bools'] > 2)]