【问题标题】:Selecting from pandas dataframe (or numpy ndarray?) by criterion按标准从熊猫数据框(或numpy ndarray?)中选择
【发布时间】:2013-02-05 20:49:33
【问题描述】:

我发现自己编写了这种模式很多

tmp = <some operation>
result = tmp[<boolean expression>]
del tmp

...其中&lt;boolean expression&gt; 应理解为布尔表达式涉及 tmp。 (目前,tmp 始终是 pandas 数据框,但我想如果我使用 numpy ndarrays 会出现相同的模式——不确定。)

例如:

tmp = df.xs('A')['II'] - df.xs('B')['II']
result = tmp[tmp < 0]
del tmp

从结尾处的del tmp 中可以猜到,创建tmp唯一 原因是我可以在应用到的索引表达式中使用涉及它的布尔表达式它。

我很想消除对这种(否则无用的)中间体的需求,但我不知道有任何有效的1 方法来做到这一点。 (如果我错了,请纠正我!)

作为第二好的,我想把这个模式推到一些辅助函数上。问题是找到一种体面的方式将&lt;boolean expression&gt; 传递给它。我只能想到不雅的。例如:

def filterobj(obj, criterion):
    return obj[eval(criterion % 'obj')]

这确实有效2

filterobj(df.xs('A')['II'] - df.xs('B')['II'], '%s < 0')

# Int
# 0     -1.650107
# 2     -0.718555
# 3     -1.725498
# 4     -0.306617
# Name: II

...但是使用eval 总是让我觉得所有的东西都令人讨厌...如果有其他方法请告诉我。


1例如,我能想到的任何涉及 filter 内置函数的方法都可能效率低下,因为它会通过“在 Python 中”迭代来应用标准(一些 lambda 函数),在熊猫(或 numpy)对象上...

2上面最后一个表达式中使用的df的定义是这样的:

import itertools
import pandas as pd
import numpy as np
a = ('A', 'B')
i = range(5)
ix = pd.MultiIndex.from_tuples(list(itertools.product(a, i)),
                               names=('Alpha', 'Int'))
c = ('I', 'II', 'III')
df = pd.DataFrame(np.random.randn(len(idx), len(c)), index=ix, columns=c)

【问题讨论】:

  • 只需使用result 的名称为tmp ;)

标签: numpy pandas


【解决方案1】:

由于 Python 的工作方式,我认为这会很困难。我只能想到只能让你部分获得成功的技巧。类似的东西

def filterobj(obj, fn):
    return obj[fn(obj)]

filterobj(df.xs('A')['II'] - df.xs('B')['II'], lambda x: x < 0)

应该有效,除非我错过了什么。以这种方式使用 lambda 是延迟评估的常用技巧之一。

大声思考:可以创建一个 this 对象,该对象不被评估,但只是作为表达式保留,类似于

>>> this
this
>>> this < 3
this < 3
>>> df[this < 3]
Traceback (most recent call last):
  File "<ipython-input-34-d5f1e0baecf9>", line 1, in <module>
    df[this < 3]
[...]
KeyError: u'no item named this < 3'

然后要么将this 的特殊情况处理成熊猫,要么仍然具有类似的功能

def filterobj(obj, criterion):
    return obj[eval(str(criterion.subs({"this": "obj"})))]

(我们可能会失去eval,这只是概念证明)之后类似

>>> tmp = df["I"] + df["II"]
>>> tmp[tmp < 0]
Alpha  Int
A      4     -0.464487
B      3     -1.352535
       4     -1.678836
Dtype: float64
>>> filterobj(df["I"] + df["II"], this < 0)
Alpha  Int
A      4     -0.464487
B      3     -1.352535
       4     -1.678836
Dtype: float64

会工作的。我不确定这是否值得头疼,不过,Python 根本不适合这种风格。

【讨论】:

  • 让我想起了他们试图用 Bokeh 复制 ggplot 所做的事情......不像在 R 中那样简单,似乎
【解决方案2】:

这是尽可能简洁的:

(df.xs('A')['II'] - df.xs('B')['II']).apply(lambda x: x if (x<0) else np.nan).dropna()

Int
0     -4.488312
1     -0.666710
2     -1.995535
Name: II

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 2020-01-12
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 1970-01-01
    相关资源
    最近更新 更多