Pandas - Python: Apply()和if/then逻辑

5

I have the following DataFrames:

example  = pd.DataFrame({"dirr":[1,0,-1,-1,1,-1,0], 
                         "value": [125,130,80,8,150,251,18], 
                         "result":[np.NaN for _ in range(7)]})

我想使用cummin()和cummax()对其执行以下操作:
example["result"].apply(lambda x : x= example["value"].cummax() if example["dirr"]==1
                           else x= example["value"].cummin() if example["dirr"]==-1
                           else x= NaN if if example["dirr"]==0
                              )

这是返回结果:错误:语法无效。有谁能帮我搞清楚这个问题吗?预期输出为:
example  = pd.DataFrame({"dirr":[1,0,-1,-1,1,-1,0], 
                         "value": [125,130,80,8,150,251,18], 
                         "result":[125, NaN, 80, 8, 150, 8, NaN]})

编辑:

根据@su79eu7k的答案,以下函数可以实现:

def calc(x):
    if x['dirr'] == 1:
        return np.diag(example["value"].cummax())
    elif x['dirr'] == -1:
        return np.diag(example["value"].cummin())
    else:
        return np.nan

我应该能够将其塞入lambda中,但仍然被语法错误阻止...我仍然看不到哪里出错了?

example["result"]=example.apply(lambda x : np.diag(x["value"].cummax()) if x["dirr"]==1
                               else np.diag(x["value"].cummin()) if x["dirr"]==-1
                               else NaN if x["dirr"]==0
                              )

希望你们最后能给个小提示,这对我们来说将受益匪浅。


结果应该是 [125, NaN, 80, 8, 150, 8, NaN] 还是 [125, NaN, 125, 80, 150, 8, NaN] - 3novak
@3novak:是的,你说得对。已编辑。 - jim jarnac
3个回答

2

我认为使用单独的行比使用apply函数更有意义。如果您确实要使用apply函数,应该创建一个单独的函数并将其传递,而不是使用三行lambda表达式。

example.loc[example['dirr'] == 1, 'result'] = \
            example.loc[example['dirr'] == 1, 'value'].cummax()
example.loc[example['dirr'] == -1, 'result'] = \
            example.loc[example['dirr'] == -1, 'value'].cummin()

>>> example
   dirr  result  value
0     1   125.0    125
1     0     NaN    130
2    -1    80.0     80
3    -1     8.0      8
4     1   150.0    150
5    -1     8.0    251
6     0     NaN     18

以下是另一种 应用 的方法。
current_max = 0
current_min = 9999

def func(df):
    global current_max
    global current_min
    if df['dirr'] == 1:
        current_max = max(current_max, df['value'])
        return current_max
    elif df['dirr'] == -1:
        current_min = min(current_min, df['value'])
        return current_min
    else:
        return np.nan

example['result'] = example.apply(func, axis=1)

谢谢您的回复,它确实有效。但是我真的不理解这个逻辑:您将布尔列表作为位置参数传递?如果您要将其作为函数并通过apply()传递,您会如何处理? - jim jarnac
正确的,我们对数据框的一部分进行索引以进行赋值,然后我们对影响返回数据的部分进行子集操作。我已经修改了我的帖子以提供另一种应用函数,但全局变量使得它有点复杂。 - 3novak
我可以使用Pandas.mask()来完成相同的操作。这是我以前用过的方法。但我不喜欢这种语法,想要在一行中定义“result”值。 - jim jarnac

1
我认为@3novak的解决方案简单且快速。但如果你真的想使用apply函数,
def calc(x):
    if x['dirr'] == 1:
        return example["value"].cummax()
    elif x['dirr'] == -1:
        return example["value"].cummin()
    else:
        return np.nan

example['result']  = np.diag(example.apply(calc, axis=1))

print example

   dirr  result  value
0     1   125.0    125
1     0     NaN    130
2    -1    80.0     80
3    -1     8.0      8
4     1   150.0    150
5    -1     8.0    251
6     0     NaN     18

谢谢,这很有趣:从我看到的内容来看,您创建的函数本质上与我在问题中提到的函数相同,除了两件事:1)语法是正确的!为什么在我的问题中它不能工作?(我试着用elif替换第二个else,但还是出错了)。2)np.diag()函数,它具体做什么?理想情况下,我想保留我的原始lambda函数。我认为为它编写3行代码可以,并且可以使代码更清晰。 - jim jarnac
https://google.github.io/styleguide/pyguide.html?showone=Lambda_Functions#Lambda_Functions和https://dev59.com/QWYr5IYBdhLWcg3wAFk1解决期望lambda的缺点和不可能性。 - 3novak
@su79eu7k:好的,我明白了,在lambda表达式中不能在if/else语句中使用语句。关于我的第二个问题,为什么会有numpy.diag()函数?为什么不直接使用example['result'] = example.apply(calc, axis=1)呢? - jim jarnac
实际上,我更接近@su79eu7k使用的表达方式,将我的lambda重述为example[result].apply(lambda x : example["value"].cummax() if x["dirr"]==1 ...。Lambda中没有更多的语句,但仍然返回error:invalid syntax。为什么?PS:不感兴趣为什么一个16行的函数更好的意见... - jim jarnac
@3novak example.apply(calc, axis=1)) 生成计算结果数据框,其中包含基于dirr的cummax或cummin列。最后,np.diag选择其对角线数字。尝试print example.apply(calc, axis=1))以便理解可能会有所帮助。 - su79eu7k
@su79eu7k 非常感谢!你能看一下我在问题中所做的编辑吗?谢谢。 - jim jarnac

0

所有的numpy

v = example.value.values
d = example.dirr.values
mx = np.maximum.accumulate(v)
mn = np.minimum.accumulate(v)
example['result'] = np.where(d == 1, mx, np.where(d == -1, mn, np.nan))
example

   dirr  result  value
0     1   125.0    125
1     0     NaN    130
2    -1    80.0     80
3    -1     8.0      8
4     1   150.0    150
5    -1     8.0    251
6     0     NaN     18

时间控制

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接