Python 按组将唯一值与参数相加

Python 按组将唯一值与参数相加,python,pandas,dataframe,group-by,pandas-groupby,Python,Pandas,Dataframe,Group By,Pandas Groupby,我得到了这样一个数据帧: data = { 'YEAR' : [2018,2018,2017,2018,2018,2018], 'SEASON': ['SPRING', 'SPRING', 'WINTER', 'SPRING', 'SPRING', 'SPRING'], 'CODE': ['A', 'A', 'A', 'B', 'C', 'D'], 'BUDGET': [500,200,300,4000,700,0], 'QUANTI

我得到了这样一个数据帧:

data = {
    'YEAR' :    [2018,2018,2017,2018,2018,2018],
    'SEASON':   ['SPRING', 'SPRING', 'WINTER', 'SPRING', 'SPRING', 'SPRING'],
    'CODE':     ['A', 'A', 'A', 'B', 'C', 'D'],
    'BUDGET':   [500,200,300,4000,700,0],
    'QUANTITY': [1000,1000,1000,2000,300,4000]
}

df = pd.DataFrame(data)

'''
   BUDGET CODE  QUANTITY  SEASON  YEAR
0     500    A      1000  SPRING  2018
1     200    A      1000  SPRING  2018
2     300    A      1000  WINTER  2017
3    4000    B      2000  SPRING  2018
4     700    C       300  SPRING  2018
5       0    D      4000  SPRING  2018
'''
对于每个代码我得到了正确的预算数量,但不幸的是在数量栏中,我得到了每个[年度,季节]内该代码的总数量

我正在使用一个函数来聚合作为输入的不同级别的数据帧:例如,我给这个函数一个如下的列表

my_list = [
  ['YEAR']
  ['YEAR', 'SEASON']
]
该函数将输出按每个子列表分组的一系列数据帧

这里的问题是,我可以使用pd.Series.nunique聚合代码,我可以对预算列进行求和,但如果我对数量列进行求和,我的求和显然会超出我的期望。我需要的是uniquesYEARseashCODE的某种sumUniques函数

def sumUniques(x):
    return '???'

print(df.groupby(['YEAR', 'SEASON']).agg({
    'CODE': pd.Series.nunique,
    'BUDGET': sum,
    'QUANTITY' : sumUniques
}))

'''
             CODE  BUDGET QUANTITY
YEAR SEASON                       
2017 WINTER     1     300      ???
2018 SPRING     4    5400      ???


--> EXPECTED RESULT:
             CODE  BUDGET QUANTITY
YEAR SEASON                       
2017 WINTER     1     300      1000
2018 SPRING     4    5400      7300

'''
我在问自己,哪一种可能是实现这一目标的最佳方式,我发现:我已经尝试过了,因为我似乎没有正确地应用它,或者这不适用于我的问题,因为它引发了一个关键错误:

print(df.groupby(['YEAR', 'SEASON']).agg({
    'CODE': pd.Series.nunique,
    'BUDGET': sum,
    'QUANTITY' : lambda x: x.groupby('CODE').QUANTITY.first().sum()
}))

'''
KeyError: 'CODE'
'''
np.random.seed(123)
N = 1000000
a = ['WINTER', 'AUTUMN', 'SUMMER', 'SPRING']
b = list('ABCDEFGHIJKL')
c = range(1990, 2018)

data = {
    'YEAR' :    np.random.choice(c, N),
    'SEASON':   np.random.choice(a, N),
    'CODE':     np.random.choice(b, N),
    'BUDGET':    np.random.randint(1000,size= N),
    'QUANTITY': np.random.randint(1000,size= N)
}

df = pd.DataFrame(data)
print (df.head())
   BUDGET CODE  QUANTITY  SEASON  YEAR
0      92    L        95  SUMMER  2003
1     961    A       696  SPRING  1992
2     481    G       351  WINTER  1992
3     296    A        51  SPRING  1996
4     896    G        58  AUTUMN  2007

我想知道什么是最好的方式使这项工作,希望这将有助于其他人了

根据您的意见,需要一个稍微复杂一些的程序来获得您的结果。
QUANTITY
的解决方案与jezrael回答的
apply
非常相似,因此感谢他

df

   BUDGET CODE  QUANTITY  SEASON  YEAR
0     500    A      1000  SPRING  2018
1     200    A      1000  SPRING  2018
2     300    A      1000  WINTER  2017
3    4000    B      2000  SPRING  2018
4     700    C       300  SPRING  2018
5       0    D      4000  SPRING  2018
6     500    E      1000  SPRING  2018

f = {
        'CODE' : 'nunique', 
        'BUDGET' : 'sum'
}

g = df.groupby(['YEAR', 'SEASON'])
v1 = g.agg(f)
v2 = g.agg(lambda x: x.drop_duplicates('CODE', keep='first').QUANTITY.sum())

df = pd.concat([v1, v2.to_frame('QUANTITY')], 1)

df

             CODE  BUDGET  QUANTITY
YEAR SEASON                        
2017 WINTER     1     300      1000
2018 SPRING     5    5900      8300

通过自定义函数使用
groupby
+
apply

def f(x):
   a = x['CODE'].nunique()
   b =  x['BUDGET'].sum()
   c = x.drop_duplicates('CODE').QUANTITY.sum()
   #Or:
   #c = x.groupby('CODE').QUANTITY.first().sum()
   return pd.Series([a,b,c], index=['CODE','BUDGET','QUANTITY'])


print (df.groupby(['YEAR', 'SEASON']).apply(f) )

             CODE  BUDGET  QUANTITY
YEAR SEASON                        
2017 WINTER     1     300      1000
2018 SPRING     4    5400      7300
另一个解决方案:

df1 = df.groupby(['YEAR', 'SEASON']).agg({ 'CODE' : 'nunique', 'BUDGET' : 'sum'})
s = df.drop_duplicates(['YEAR', 'SEASON','CODE']).groupby(['YEAR', 'SEASON'])['QUANTITY'].sum()

df = df1.join(s.rename('QUANTITY'))
print (df)
             BUDGET  CODE  QUANTITY
YEAR SEASON                        
2017 WINTER     300     1      1000
2018 SPRING    5900     5      8300
计时

print(df.groupby(['YEAR', 'SEASON']).agg({
    'CODE': pd.Series.nunique,
    'BUDGET': sum,
    'QUANTITY' : lambda x: x.groupby('CODE').QUANTITY.first().sum()
}))

'''
KeyError: 'CODE'
'''
np.random.seed(123)
N = 1000000
a = ['WINTER', 'AUTUMN', 'SUMMER', 'SPRING']
b = list('ABCDEFGHIJKL')
c = range(1990, 2018)

data = {
    'YEAR' :    np.random.choice(c, N),
    'SEASON':   np.random.choice(a, N),
    'CODE':     np.random.choice(b, N),
    'BUDGET':    np.random.randint(1000,size= N),
    'QUANTITY': np.random.randint(1000,size= N)
}

df = pd.DataFrame(data)
print (df.head())
   BUDGET CODE  QUANTITY  SEASON  YEAR
0      92    L        95  SUMMER  2003
1     961    A       696  SPRING  1992
2     481    G       351  WINTER  1992
3     296    A        51  SPRING  1996
4     896    G        58  AUTUMN  2007



您的输出完全相反。检查代码和预算栏。我也不明白。这也很奇怪。我也无缘无故地投了反对票。我想有人把它拿了回去,但我的答案上还有一个。你能做什么,它发生了。我加了一些时间,似乎申请是最快的。但可能与实际数据不同。OP已经为我们的答案计时,我的答案大约需要2秒,而你的答案需要5秒。是的,但我添加了另一个带有
agg
的解决方案,我认为OP可以测试它,而且我认为它会更快,因为逻辑不同。如果你的问题得到解决,请接受帮助你的答案。谢谢。我添加了带有计时的新解决方案,你能用你的真实数据检查一下吗?我相信你的2018年春季分组数量应该是7300,而不是8300。忽略不计。我看到你改变了原来的df。