问题描述
我有一个包含分类列和数字列的数据框,并且我希望对数字列的值(最大值,最小值,总和...)进行一些汇总(因此,我必须创建每个分类列可以采用的每个值都有一个新列)。
为了使其更加不稳定,最好举一个玩具示例。
说我有这个数据框:
import pandas as pd
df = pd.DataFrame({
'ref' : [1,1,2,3],'value_type' : ['A','B','A','C','A'],'amount' : [100,50,20,300,150,70]
}).set_index(['ref'])
value_type amount
ref
1 A 100
1 B 50
1 A 20
2 C 300
2 C 150
3 A 70
我想将value_type值上的金额分组,也为每个引用分组。在这种情况下(假设只需要总和)的结果就是这个:
df_result = pd.DataFrame({
'ref' : [1,'sum_amount_A' : [120,70],'sum_amount_B' : [50,0],'sum_amount_C' : [0,450,0]
}).set_index('ref')
sum_amount_A sum_amount_B sum_amount_C
ref
1 120 50 0
2 0 0 450
3 70 0 0
我尝试了一些可行的方法,但是效率极低。处理几分钟大约需要30.000行。
我所做的是这样的:(我有一个数据框,其中每个索引引用只有一行,称为df_final)
df_grouped = df.groupby(['ref'])
for ref in df_grouped.groups:
df_aux = df.loc[[ref]]
column = 'A' # I have more columns,but for illustration one is enough
for value in df_aux[column].unique():
df_aux_column_value = df_aux.loc[df_aux[column] == value]
df_final.at[ref,'sum_' + column + '_' + str(value)] = np.sum(df_aux_columna_valor[column])
我确定应该有更好的方法来进行这种强化...预先感谢!
编辑:
当只有一列要分组时,给出的答案是正确的。在实际的数据框中,我有几列要计算agg函数,但要分别计算每列的值。我的意思是我不希望为列值的每种组合提供一个汇总值,而只是希望对列本身进行汇总。
让我们举个例子。
import pandas as pd
df = pd.DataFrame({
'ref' : [1,'sexo' : ['Hombre','Hombre','Mujer','Hombre'],'lugar_trabajo' : ['Campo','Ciudad','Campo','Campo'],'dificultad' : ['Alta','Media','Alta','Baja','Alta'],70]
}).set_index(['ref'])
此数据框如下所示:
sexo lugar_trabajo dificultad amount
ref
1 Hombre Campo Alta 100
1 Hombre Ciudad Media 50
1 Hombre Campo Alta 20
2 Mujer Ciudad Media 300
2 Mujer Ciudad Baja 150
3 Hombre Campo Alta 70
如果我将几列分组,或创建一个数据透视表(据我所知,这在某种意义上是等效的),请执行以下操作:
df.pivot_table(index='ref',columns=['sexo','lugar_trabajo','dificultad'],values='amount',aggfunc=[np.sum,np.min,np.max,len],dropna=False)
我将获得一个包含48列的数据框(因为我有3个 2 2个不同的值和4个agg函数)。
一种实现我想要的结果的方法是:
df_agregado = pd.DataFrame(df.index).set_index('ref')
for col in ['sexo','dificultad']:
df_agregado = pd.concat([df_agregado,df.pivot_table(index='ref',columns=[col],len])],axis=1)
我每个人单独做一个小组,并把它们全部合并。这样我得到28列(2 4 + 3 4 + 2 * 4)。它可以运行并且速度很快,但是不是很优雅。还有另一种方法来获得此结果吗?
解决方法
更有效的方法是使用Pandas内置函数而不是for
循环。您应该采取两个主要步骤。
首先,您不仅需要按索引分组,还需要按索引和列进行分组:
res = df.groupby(['ref','value_type']).sum()
print(res)
此步骤的输出如下:
amount
ref value_type
1 A 120
B 50
2 C 450
3 A 70
第二,您需要按如下所示拆开多重索引:
df2 = res.unstack(level='value_type',fill_value=0)
输出将是您想要的输出:
amount
value_type A B C
ref
1 120 50 0
2 0 0 450
3 70 0 0
作为可选步骤,您可以使用droplevel
将其展平:
df2.columns = df2.columns.droplevel()
value_type A B C
ref
1 120 50 0
2 0 0 450
3 70 0 0