我发现自己编码了这种模式很多:
tmp = <some operation>
result = tmp[<boolean expression>]
del tmp
...其中<boolean expression>
被理解为布尔表达式涉及 tmp
。 (暂时,tmp
总是一个熊猫数据帧,但我想如果我使用numpy ndarrays会出现相同的模式 - 不确定。)
例如:
tmp = df.xs('A')['II'] - df.xs('B')['II']
result = tmp[tmp < 0]
del tmp
正如人们可以从最后的del tmp
猜测的那样,仅创建tmp
的原因是我可以使用一个布尔表达式来包含它应用索引表达式。
我很想消除对这种(无用的)中间体的需要,但我不知道有任何有效的 1 方法来做到这一点。 (如果我错了,请纠正我!)
作为第二好的,我想把这个模式推到一些辅助函数。问题是找到一种将<boolean expression>
传递给它的好方法。我只能想到不雅的。 E.g:
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
内置的方法都可能是无效的,因为它会通过迭代来应用标准(一些lambda函数),“在Python中“,在熊猫(或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)
答案 0 :(得分:1)
这是我能得到的简洁:
(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
答案 1 :(得分:1)
由于Python的工作方式,我认为这将是艰难的。我只能想到只能让你在那里的一部分的黑客。像
这样的东西def filterobj(obj, fn):
return obj[fn(obj)]
filterobj(df.xs('A')['II'] - df.xs('B')['II'], lambda x: x < 0)
应该有用,除非我错过了什么。以这种方式使用lambdas是延迟评估的常用技巧之一。
大声思考:可以制作一个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根本不利于这种风格。