combinações únicas de valores em colunas selecionadas no quadro de dados e contagem do pandas

99

Eu tenho meus dados no quadro de dados do pandas da seguinte forma:

df1 = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],
                   'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})

Então, meus dados se parecem com este

----------------------------
index         A        B
0           yes      yes
1           yes       no
2           yes       no
3           yes       no
4            no      yes
5            no      yes
6           yes       no
7           yes      yes
8           yes      yes
9            no       no
-----------------------------

Eu gostaria de transformá-lo em outro quadro de dados. A saída esperada pode ser mostrada no seguinte script Python:

output = pd.DataFrame({'A':['no','no','yes','yes'],'B':['no','yes','no','yes'],'count':[1,2,4,3]})

Então, minha saída esperada é assim

--------------------------------------------
index      A       B       count
--------------------------------------------
0         no       no        1
1         no      yes        2
2        yes       no        4
3        yes      yes        3
--------------------------------------------

Na verdade, posso encontrar todas as combinações e contá-las usando o seguinte comando: mytable = df1.groupby(['A','B']).size()

No entanto, verifica-se que tais combinações estão em uma única coluna. Gostaria de separar cada valor em uma combinação em colunas diferentes e também adicionar mais uma coluna para o resultado da contagem. É possível fazer isso? Posso ter suas sugestões? Agradeço antecipadamente.

Ratchainant Thammasudjarit
fonte

Respostas:

166

Você pode groupbynas colunas 'A' e 'B' e chamar sizee então reset_indexe renamea coluna gerada:

In [26]:

df1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})
Out[26]:
     A    B  count
0   no   no      1
1   no  yes      2
2  yes   no      4
3  yes  yes      3

atualizar

Uma pequena explicação, ao agrupar nas 2 colunas, agrupa as linhas onde os valores A e B são iguais, chamamos sizeque retorna o número de grupos únicos:

In[202]:
df1.groupby(['A','B']).size()

Out[202]: 
A    B  
no   no     1
     yes    2
yes  no     4
     yes    3
dtype: int64

Portanto, agora, para restaurar as colunas agrupadas, chamamos reset_index:

In[203]:
df1.groupby(['A','B']).size().reset_index()

Out[203]: 
     A    B  0
0   no   no  1
1   no  yes  2
2  yes   no  4
3  yes  yes  3

Isso restaura os índices, mas a agregação de tamanho é transformada em uma coluna gerada 0, então temos que renomear isso:

In[204]:
df1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})

Out[204]: 
     A    B  count
0   no   no      1
1   no  yes      2
2  yes   no      4
3  yes  yes      3

groupbyaceita o arg as_indexque poderíamos ter definido para Falsenão tornar as colunas agrupadas o índice, mas isso gera um seriese você ainda terá que restaurar os índices e assim por diante ....:

In[205]:
df1.groupby(['A','B'], as_index=False).size()

Out[205]: 
A    B  
no   no     1
     yes    2
yes  no     4
     yes    3
dtype: int64
EdChum
fonte
1

Ligeiramente relacionado, eu estava procurando as combinações únicas e descobri este método:

def unique_columns(df,columns):

    result = pd.Series(index = df.index)

    groups = meta_data_csv.groupby(by = columns)
    for name,group in groups:
       is_unique = len(group) == 1
       result.loc[group.index] = is_unique

    assert not result.isnull().any()

    return result

E se você deseja apenas afirmar que todas as combinações são únicas:

df1.set_index(['A','B']).index.is_unique
Martin Alexandersson
fonte
Não sabia sobre set_index(). Continuei tentando usar groupby()para agrupar linhas com um determinado par comum de colunas. Incrível, obrigado!
user3290553
0

Colocando a ótima resposta de @EdChum em uma função count_unique_index. O método exclusivo funciona apenas em séries de pandas, não em quadros de dados. A função abaixo reproduz o comportamento da função única em R:

unique retorna um vetor, quadro de dados ou array como x, mas com elementos / linhas duplicados removidos.

E adiciona uma contagem das ocorrências solicitadas pelo OP.

df1 = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],                                                                                             
                    'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})                                                                                               
def count_unique_index(df, by):                                                                                                                                                 
    return df.groupby(by).size().reset_index().rename(columns={0:'count'})                                                                                                      

count_unique_index(df1, ['A','B'])                                                                                                                                              
     A    B  count                                                                                                                                                                  
0   no   no      1                                                                                                                                                                  
1   no  yes      2                                                                                                                                                                  
2  yes   no      4                                                                                                                                                                  
3  yes  yes      3
Paul Rougieux
fonte
0

Eu não fiz teste de tempo com isso, mas foi divertido de tentar. Basicamente, converta duas colunas em uma coluna de tuplas. Agora converta isso para um dataframe, faça 'value_counts ()' que encontra os elementos únicos e os conta. Brinque com o zip novamente e coloque as colunas na ordem que desejar. Você provavelmente pode tornar as etapas mais elegantes, mas trabalhar com tuplas me parece mais natural para este problema

b = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})

b['count'] = pd.Series(zip(*[b.A,b.B]))
df = pd.DataFrame(b['count'].value_counts().reset_index())
df['A'], df['B'] = zip(*df['index'])
df = df.drop(columns='index')[['A','B','count']]
MikeB2019x
fonte