熊猫:为什么是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])

可以考虑的其他一些好处

innot 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)]


以上是熊猫:为什么是query()而不是括号运算符?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>