combinaciones únicas de valores en columnas seleccionadas en el marco de datos y recuento de pandas

111

Tengo mis datos en el marco de datos de pandas de la siguiente manera:

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']})

Entonces, mis datos se ven así

----------------------------
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
-----------------------------

Me gustaría transformarlo en otro marco de datos. El resultado esperado se puede mostrar en la siguiente secuencia de comandos de Python:

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

Entonces, mi salida esperada se ve así

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

En realidad, puedo lograr encontrar todas las combinaciones y contarlas usando el siguiente comando: mytable = df1.groupby(['A','B']).size()

Sin embargo, resulta que tales combinaciones están en una sola columna. Me gustaría separar cada valor en una combinación en una columna diferente y también agregar una columna más para el resultado del recuento. ¿Es posible hacer eso? ¿Puedo tener sus sugerencias? Gracias de antemano.

Ratchainant Thammasudjarit
fuente

Respuestas:

178

Puede groupbyen las columnas 'A' y 'B' y llamar sizey luego reset_indexy renamela columna generada:

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

actualizar

Una pequeña explicación, al agrupar en las 2 columnas, esto agrupa filas donde los valores A y B son iguales, llamamos sizeque devuelve el 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

Entonces, ahora para restaurar las columnas agrupadas, llamamos 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

Esto restaura los índices, pero la agregación de tamaño se convierte en una columna generada 0, por lo que tenemos que renombrar esto:

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

groupbyacepta el argumento as_indexque podríamos haber establecido para Falseque no convierta las columnas agrupadas en el índice, pero esto genera un seriesy aún tendría que restaurar los índices y así sucesivamente ....:

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
fuente
2

Ligeramente relacionado, estaba buscando combinaciones únicas y se me ocurrió 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

Y si solo quiere afirmar que todas las combinaciones son únicas:

df1.set_index(['A','B']).index.is_unique
Martin Alexandersson
fuente
No lo sabía set_index(). Seguí intentando usar groupby()para agrupar filas con un par de columnas común particular. ¡Increíble, gracias!
user3290553
0

Colocando la muy buena respuesta de @ EdChum en una función count_unique_index. El método único solo funciona en series de pandas, no en marcos de datos. La siguiente función reproduce el comportamiento de la función única en R:

unique devuelve un vector, marco de datos o matriz como x pero con elementos / filas duplicados eliminados.

Y agrega un recuento de las ocurrencias según lo solicitado por el 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
fuente
0

No he hecho una prueba de tiempo con esto, pero fue divertido intentarlo. Básicamente, convierta dos columnas en una columna de tuplas. Ahora convertir que a una trama de datos, hacer 'value_counts ()' que encuentra los elementos únicos y los recuentos de ellos. Juega con zip de nuevo y coloca las columnas en el orden que quieras. Probablemente pueda hacer que los pasos sean más elegantes, pero trabajar con tuplas me parece más 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
fuente