Gostaria de calcular a média para cada grupo relevante. Cada nome possui dois grupos e um valor. Quero definir qual é o grupo relevante para cada nome e depois obter a média do valor desse grupo relevante. A justificativa é que quero ter certeza de que há instâncias suficientes para que esse grupo calcule minha média para ter certeza de que ela é significativa.
Meu conjunto de dados brutos:
a=pd.DataFrame({'Name':['Jack','Peter','Jim','Alex','Dan','Chris'],
'Group':['A','B','C','C','A','A'],
'Sub Group':['a','b','b','c','c','c'],
'Value':[3,5,2,6,7,1]})
Meu resultado esperado:
b=pd.DataFrame({'Name':['Jack','Peter','Jim','Alex','Dan','Chris'],
'Label':['A',np.nan,np.nan,'c','A',' A'],
'Average':[(3+7+1)/3,np.nan,np.nan,(6+7+1)/3,(3+7+1)/3,(3+7+1)/3]})
Para ilustrar a lógica, aqui está o exemplo, quero primeiro verificar se há pelo menos três pessoas em cada grupo. Eu primeiro verifico o Grupo, se não, vou para o próximo Subgrupo. Por exemplo, Jack tem um "Rótulo" de "A", isso ocorre porque há três "A" no Grupo, portanto não há necessidade de verificar o Subgrupo. Para o Peter, primeiro verifico se tem “B” no Grupo, não tem. Depois vou verificar se há três “b” no Subgrupo, também não existe, então Peter tem um “Rótulo” de NA. Para Alex, pela mesma lógica, existem apenas dois "C" no Grupo, então vou para o Subgrupo, há três "c" no Subgrupo, então Alex obteve um "Rótulo" de "c".
Quanto ao valor médio, Jack obteve a média de “A”, que é (3+7+1)/3, Alex obteve a média de “c”, que é (6+7+1)/3.
Isto é o que eu fiz:
a['Group Count']=a.groupby('Group')['Name'].transform('count')
a['Sub Group Count']=a.groupby('Sub Group')['Name'].transform('count')
a['Label']=np.where(a['Group Count']>=3,'Group', np.where(a['Sub Group Count']>=3,'Sub Group',np.nan))
a['Group Name']=np.where(a['Label']=='Group',a['Group'], np.where(a['Label']=='Sub Group',a['Sub Group'],np.nan))
group=a.groupby('Group')['Value'].mean().to_dict()
sub_group=a.groupby('Sub Group')['Value'].mean().to_dict()
a['Average']=np.where(a['Label']=='Group', a['Group Name'].map(group),
np.where( a['Label']=='Sub Group', a['Group Name'].map(sub_group),np.nan))
Existe alguma solução mais elegante? Porque tenho vários grupos em um conjunto de dados real e uma dúzia de valores para os quais preciso calcular a média.
Você pode definir uma função para fazer o cálculo e aplicá-la ao seu quadro de dados.
Então use-o. Se você também quiser que seja feito inline, aqui está um exemplo:
Você pode usar uma função personalizada
groupby.transform
efunctools
'sreduce
epartial
:Saída:
Observe que a ordem dos grupos é importante, se você usar
groups = ['Sub Group', 'Group']
,c
terá prioridadeA
nas 2 últimas linhas:Você pode definir quantos grupos desejar, seguindo o exemplo abaixo e
groups = ['Group', 'Sub Group', 'Sub Sub Group']
:Variante para manter as colunas originais (exceto os grupos):
Saída:
Como funciona
Para cada nome em
group
if calcule a média nos grupos válidos:Então você pode combinar as saídas em ordem com:
reduce
automatiza essa lógica para um número arbitrário de grupos, equivalente a:E
partial
transforme a funçãoavg_thresh
em uma função vinculadaa
(exigindo apenas "col") como parâmetro.Essas funções não são estritamente necessárias, mas ajudam a tornar o código mais curto.