我有数据框:
import pandas as pd
id = [0,0,0,0,0,1,1,1,1,1]
value = [1,3,2,5,4,4,3,2,1,5]
test = pd.DataFrame(zip(id, value), columns = ['id', 'value'])
我想要一个扩展的应用函数来识别我们是否达到给定id的新最大值。生成的数据框应如下所示:
id value new_max
0 0 1 1
1 0 3 1
2 0 2 0
3 0 5 1
4 0 4 0
5 1 4 1
6 1 3 0
7 1 2 0
8 1 1 0
9 1 5 1
我似乎无法将两列传递给扩展应用函数。
我试过创建一个新列:
test['id_value'] = zip(test['id'], test['value'])
传递元组:
def new_max(x):
v, w = list(zip(*x)[0]), list(zip(*x)[1])
last_id = v[-1]
last_value = w[-1]
if any(j >= last_value for j in [w[i] for i, k in enumerate(v[0:-1]) if k == last_id]):
return 0
else:
return 1
test['new_max'] = test['id_value'].apply(lambda x: pd.expanding_apply(x, new_max))
但我收到错误:
AttributeError: 'tuple' object has no attribute 'dtype'
任何建议都将不胜感激!
循环通过两列的一个解决方案 (虽然通过传递两列知道如何做到这一点仍然很好)
def new_max2(x):
if any(j >= x[-1] for j in x[0:-1]):
return 0
else:
return 1
test.groupby('id')['value'].apply(lambda x: pd.expanding_apply(x, new_max2))
答案 0 :(得分:1)
这解决了问题,而不是传递多列的一般问题:我会使用groupby
和cummax
,然后看看我们是否达到了新值。例如:
grouped = df.groupby("id")["value"]
cummax = grouped.cummax()
cummax_is_new_value = cummax != cummax.groupby(df.id).shift()
df["new_max"] = cummax_is_new_value.astype(int)
给了我
>>> df
id value new_max
0 0 1 1
1 0 3 1
2 0 2 0
3 0 5 1
4 0 4 0
5 1 4 1
6 1 3 0
7 1 2 0
8 1 1 0
9 1 5 1
10 2 1 1
10 2 1 0
10 2 0 0
10 2 1 0
10 3 1 1
最初我只检查该值是否与之前的值相同,但是在[1,0,1]等情况下失败,其中第二个1都等于累积最大值而不是与以前的价值。这样我们就可以始终使用分组的累积值,因此我们实际上只是按组获取新的累积值。
答案 1 :(得分:0)
自从我与apply
一起工作已经很长一段时间了,就像几个发布前的最低版本一样,所以我的回忆可能很糟糕,或者事情可能已经改变了。但是,正如我记得的那样,分组数据作为第一个参数自动传递。
将自己的功能传递给apply
时的诱惑就是这样做:
def user_func(df, arg1, arg2):
return whatever_you_like
DF = pd.DataFrame(your_data)
DF.groupby('col1').appy(user_func(arg1, arg2))
但这不是正确的语法。事实上,最后一行的正确语法是
DF.groupby('col1').apply(user_func, arg1, arg2)
expanding_apply
是否以我不知道的方式工作,这可能都完全过时,但可能值得一试。