我想计算groupby上有多少一致增量,以及第一个元素和最后一个元素之间的差异。但我无法在groupby上应用该功能。在groupby之后,它是一个列表吗?还有“应用”和“聚合”之间的区别是什么?对不起,我刚刚碰了几天蟒蛇。
def promotion(ls):
pro =0
if len(ls)>1:
for j in range(1,len(ls)):
if ls[j]>ls[j-1]:
pro + = 1
return pro
def growth(ls):
head= ls[0]
tail= ls[len(ls)-1]
gro= tail-head
return gro
titlePromotion= JobData.groupby("candidate_id")["TitleLevel"].apply(promotion)
titleGrowth= JobData.groupby("candidate_id")["TitleLevel"].apply(growth)
数据是:
candidate_id TitleLevel othercols
1 2 foo
2 1 bar
2 2 goo
2 1 gar
The result should be
titlePromotion
candidate_id
1 0
2 1
titleGrowth
candidate_id
1 0
2 0
答案 0 :(得分:3)
import pandas as pd
def promotion(ls):
return (ls.diff() > 0).sum()
def growth(ls):
return ls.iloc[-1] - ls.iloc[0]
jobData = pd.DataFrame(
{'candidate_id': [1, 2, 2, 2],
'TitleLevel': [2, 1, 2, 1]})
grouped = jobData.groupby("candidate_id")
titlePromotion = grouped["TitleLevel"].agg(promotion)
print(titlePromotion)
# candidate_id
# 1 0
# 2 1
# dtype: int64
titleGrowth = grouped["TitleLevel"].agg(growth)
print(titleGrowth)
# candidate_id
# 1 0
# 2 0
# dtype: int64
一些提示:
如果您定义通用功能
def foo(ls):
print(type(ls))
并致电
jobData.groupby("candidate_id")["TitleLevel"].apply(foo)
Python将打印
<class 'pandas.core.series.Series'>
这是一种低调但有效的方式,可以发现调用jobData.groupby(...)[...].apply(foo)
将Series
传递给foo
。
apply
方法为每个组调用foo
一次。它可以返回一个Series或一个DataFrame,并将生成的块粘在一起。当apply
返回一个对象(如数值或字符串)时,可以使用foo
,但在这种情况下,我认为使用agg
是首选。使用apply
的典型用例是,当您想要对组中的每个值进行平方时,因此需要返回相同形状的新组。
transform
方法在这种情况下也很有用 - 当你想转换组中的每个值,因此需要返回相同形状的东西时 - 但结果可以与apply
不同,因为可以将不同的对象传递给foo
(例如,使用foo
时,分组数据框的每一列都会传递给transform
虽然使用foo
时整个群组都会传递给apply
。理解这一点的最简单方法是尝试使用简单的数据框和通用foo
。)
agg
方法为每个组调用foo
一次,但与apply
不同,它应该为每个组返回一个数字。该组聚合成为一个值。使用agg
的典型用例是当您想要计算组中的项目数时。
您可以使用通用foo
函数调试并了解原始代码出现的问题:
In [30]: grouped['TitleLevel'].apply(foo)
0 2
Name: 1, dtype: int64
--------------------------------------------------------------------------------
1 1
2 2
3 1
Name: 2, dtype: int64
--------------------------------------------------------------------------------
Out[30]:
candidate_id
1 None
2 None
dtype: object
这会显示传递给foo
的系列。请注意,在第二个系列中,索引值为1和2.因此,ls[0]
会引发KeyError
,因为第二个系列中没有值为0
的标签。
你真正想要的是系列中的第一个项目。这就是iloc
的用途。
总而言之,使用ls[label]
选择索引值为label
的系列行。使用ls.iloc[n]
选择系列的n
行。
因此,要使用最少量的更改来修复代码,可以使用
def promotion(ls):
pro =0
if len(ls)>1:
for j in range(1,len(ls)):
if ls.iloc[j]>ls.iloc[j-1]:
pro += 1
return pro
def growth(ls):
head= ls.iloc[0]
tail= ls.iloc[len(ls)-1]
gro= tail-head
return gro
答案 1 :(得分:1)
VAR0 VAR1
1 1
1 2
1 3
1 4
2 5
2 6
2 7
2 8
你可以在申请中使用lambda:
下面的代码将减去第一个
中的所有值grp = df.groupby('VAR0')['VAR1'].apply(lambda x: x.iloc[0] - x)
如果您尝试使用agg:
grp = df.groupby('VAR0')['VAR1'].agg(lambda x: x.iloc[0] - x)
它不起作用,因为agg需要为每个组获取一个值
如果你减去特定单元格的值,则agg和apply之间没有区别,它们都为每个组创建一个值
grp = df.groupby('VAR0')['VAR1'].apply(lambda x: x.iloc[0] - x.iloc[-1])
grp = df.groupby('VAR0')['VAR1'].agg(lambda x: x.iloc[0] - x.iloc[-1])
print grp
VAR0
1 -3
2 -3
Name: VAR1, dtype: int64
如果您希望例如从上一行中减去每一行的值(为了获得每行的增量),您可以使用如下变换:
grp = df.groupby('VAR0')
def subtr(x):
y=x.copy()
for i in range(1,len(x.index)):
x.iloc[i]=y.iloc[i]-y.iloc[i-1]
return x
new_var = grp['VAR1'].transform(subtr)
print new_var
0 1
1 1
2 1
3 1
4 5
5 1
6 1
7 1
Name: VAR1, dtype: int64
或更容易,对于这个特殊问题:
grp = df.groupby('VAR0')['VAR1'].apply(lambda x: x - x.shift())