Os pandas somam por agrupamento, mas excluem certas colunas

88

Qual é a melhor maneira de agrupar em um dataframe do Pandas, mas excluir algumas colunas desse agrupamento? por exemplo, eu tenho o seguinte dataframe:

Code   Country      Item_Code   Item    Ele_Code    Unit    Y1961    Y1962   Y1963
2      Afghanistan  15          Wheat   5312        Ha      10       20      30
2      Afghanistan  25          Maize   5312        Ha      10       20      30
4      Angola       15          Wheat   7312        Ha      30       40      50
4      Angola       25          Maize   7312        Ha      30       40      50

Desejo agrupar pela coluna Country e Item_Code e apenas calcular a soma das linhas que se enquadram nas colunas Y1961, Y1962 e Y1963. O dataframe resultante deve ser assim:

Code   Country      Item_Code   Item    Ele_Code    Unit    Y1961    Y1962   Y1963
2      Afghanistan  15          C3      5312        Ha      20       40       60
4      Angola       25          C4      7312        Ha      60       80      100

Agora estou fazendo isso:

df.groupby('Country').sum()

No entanto, isso adiciona os valores na coluna Item_Code também. Existe alguma maneira de especificar quais colunas incluir na sum()operação e quais excluir?

user308827
fonte

Respostas:

117

Você pode selecionar as colunas de um groupby:

In [11]: df.groupby(['Country', 'Item_Code'])[["Y1961", "Y1962", "Y1963"]].sum()
Out[11]:
                       Y1961  Y1962  Y1963
Country     Item_Code
Afghanistan 15            10     20     30
            25            10     20     30
Angola      15            30     40     50
            25            30     40     50

Observe que a lista passada deve ser um subconjunto das colunas, caso contrário, você verá um KeyError.

Andy Hayden
fonte
1
Como incluir a contagem de registros para cada país e código de item como outra coluna?
Sushant Kulkarni
Você pode criar uma coluna fictícia antes de agrupar por que contém apenas 1. então a soma irá somar todos criando uma contagem.
Matt W.
Se você deseja apenas excluir uma ou duas colunas, obtém todos os nomes das colunas como em listColumns = list(df.columns), remove as colunas que não deseja listColumns.remove('Y1964')e , por fim, faz sua soma:df.groupby(['Country', 'Item_Code'])[listColumns].sum()
Roberto Stelling
Muito obrigado. Posso fazer o groupby trabalhar, mas não a parte da seleção. A lista de colunas que coloquei está entre o dataframe, mas continua aumentando ValueError:cannot reindex from a duplicate axis
Bowen Liu
@BowenLiu se você tiver várias colunas com o mesmo nome irá mostrar este erro. Nesse caso, você terá que usar iloc to ou loc para obter as colunas que deseja, acho que você terá que fazer isso antes do groupby.
Andy Hayden
40

A aggfunção fará isso por você. Passe as colunas e funcione como um dicionário com coluna, saída:

df.groupby(['Country', 'Item_Code']).agg({'Y1961': np.sum, 'Y1962': [np.sum, np.mean]})  # Added example for two output columns from a single input column

Isso exibirá apenas o grupo por colunas e as colunas agregadas especificadas. Neste exemplo, incluí duas funções agg aplicadas a 'Y1962'.

Para obter exatamente o que você esperava ver, inclua as outras colunas no agrupamento por e aplique somas às variáveis ​​Y no quadro:

df.groupby(['Code', 'Country', 'Item_Code', 'Item', 'Ele_Code', 'Unit']).agg({'Y1961': np.sum, 'Y1962': np.sum, 'Y1963': np.sum})
leroyJr
fonte
1
obrigado, isso pode ser generalizado? Eu tenho muitas colunas no formato Y1961 ... então eu gerei uma lista como esta: yrs = ['Y' + str (x) para x no intervalo (1961, 2010 + 1, 1)]. Sua solução pode usar 'yrs' dentro do agg?
user308827
Eu realmente gosto dessa ideia. O truque é construir este dict com o valor sendo a função de soma numpy. Por outro lado, se tudo o que você deseja fazer é somar todas as colunas restantes, sua solução original funcionaria se todas as colunas agrupadas estivessem incluídas na instrução agrupar por.
leroyJr
11

Se você está procurando uma maneira mais generalizada de aplicar a muitas colunas, o que pode fazer é construir uma lista de nomes de colunas e passá-la como o índice do dataframe agrupado. No seu caso, por exemplo:

columns = ['Y'+str(i) for year in range(1967, 2011)]

df.groupby('Country')[columns].agg('sum')
Super estrela
fonte