Contando índices en pandas

8

Siento que esta es una pregunta rudimentaria, pero soy muy nuevo en esto y simplemente no he podido descifrarla / encontrar la respuesta.

En última instancia, lo que intento hacer aquí es contar valores únicos en una determinada columna y luego determinar cuáles de esos valores únicos tienen más de un valor único en una columna coincidente.

Entonces, para estos datos, lo que estoy tratando de determinar es "quién" tiene "más de un recibo" para todas las compras, luego determine la misma información en función de cada categoría de producto.

Mi enfoque hasta ahora:

Tenemos un conjunto de datos como este:

receipt,name,etc,category
1,george,xxx,fish
1,george,xxx,cat
2,george,xxx,fish
3,bill,xxx,fish
3,bill,xxx,dog
4,jill,xxx,cat
5,bill,xxx,cat
5,bill,xxx,cat
5,bill,xxx,dog
6,george,xxx,fish

Entonces puedo hacer esto:

df.set_index(['name','receipt'])

Y consigue lo más interesante

                etc category
name   receipt
george 1        xxx     fish
       1        xxx      cat
       2        xxx     fish
bill   3        xxx     fish
       3        xxx      dog
jill   4        xxx      cat
bill   5        xxx      cat
       5        xxx      cat
       5        xxx      dog
george 6        xxx     fish

En este punto, me parece que es fácil trabajar con los datos, pero no lo he descubierto.

Una cosa que me interesa es que si clasifico los datos por nombre antes de indexarlos, los datos se muestran agrupados por nombre. En ambos casos, el índice es el mismo, así que no sé cómo jugar con la representación de los datos después de la indexación.

Es fácil encontrar los datos por categoría usando

>>> orders.loc[orders['category'] == 'fish']
                etc category
name   receipt
george 1        xxx     fish
       2        xxx     fish
bill   3        xxx     fish
george 6        xxx     fish

Pero lo que no puedo entender es cómo decirle a los pandas "Encuéntrame la lista de nombres que tienen más de un recibo".

Preguntas más pequeñas:

  • ¿Cuál es la "forma de los pandas" para obtener la longitud de los nombres como parte del índice? Supongo que podría convertir la namecolumna en un conjunto y obtener la longitud de eso. Pero tengo curiosidad por los índices.

Editar / Actualizar

Gracias por esas respuestas! Aquí hay una aclaración sobre lo que estoy buscando:

Estoy tratando de encontrar "clientes habituales": personas con más de un recibo.

Entonces mi conjunto de todos los clientes sería:

names: ['george','bill','jill'], ratio: 1.0

Mis clientes habituales:

names: ['george','bill'], ratio 0.66

Todos los clientes 'peces':

names: ['george','bill'], ratio: 0.666

Mis clientes habituales de 'pescado':

names: ['george'], ratio: 0.333

Creo que los ejemplos dados parecen útiles, pero siéntase libre de agregar cualquier cosa.

Señor hasquestions
fuente
¿Puedes publicar un conjunto de datos resultante deseado (esperado)?
MaxU

Respuestas:

5

Creo que tal vez estás buscando:

receipts_by_name_x_cat = df.groupby(['name','category']).count()

O, si solo desea el total en todas las categorías:

receipts_by_name = df.groupby(['name']).count()

Luego, puede buscar aquellos que tienen más de uno:

receipts_by_name[receipts_by_name['receipt']>1]

Y, puede encontrar la longitud de un índice escribiendo:

len(df.index.get_level_values(0))

Suponiendo que el nombre fuera la primera columna de índice (de lo contrario, sustituya 1, 2, etc.)

atkat12
fuente
Esto es extremadamente útil. Sin embargo, formulé mal mi pregunta. "Más de un recibo" debe ser "Más de una transacción, lo que significa que tienen más de un recibo único ".
Sr. Hasquestions
Alegra oírlo. Re: tu pregunta, ¿cómo son los dos diferentes? ¿Qué define un recibo único? ¿Es la columna 'recibo' la identificación del recibo? y la categoría es todos los artículos que compraron en ese recibo? Si es así, puede intentar receipts_by_name = df.groupby(['name']).unique()y luego tomar la respuesta en la columna 'recibo', creo. Solo necesita aplicar una función groupby diferente.
atkat12
Correcto, entonces, una forma de pensarlo es que cada fila del conjunto de datos representa una partida en una compra, por lo que el recibo es la "ID del recibo" de esa transacción. Entonces, por ejemplo, Bill compró dos artículos de gato durante la transacción # 5 y él es responsable de la transacción # 2. Por lo tanto, él es un "comprador que repite", pero no es un "comprador que repite el gato", ya que sus compras de dos gatos ocurrieron durante la misma transacción.
Sr. Hasquestions
3

No está del todo claro qué está tratando de lograr exactamente (sería útil comprender sus objetivos si publicara los conjuntos de datos deseados / esperados) ...

Pero intentaré adivinar;)

Datos:

In [100]: df
Out[100]:
   receipt    name  etc category
0        1  george  xxx     fish
1        1  george  xxx      cat
2        2  george  xxx     fish
3        3    bill  xxx     fish
4        3    bill  xxx      dog
5        4    jill  xxx      cat
6        5    bill  xxx      cat
7        5    bill  xxx      cat
8        5    bill  xxx      dog
9        6  george  xxx     fish

Configurando la columna virtual count, mostrando el número de filas agrupadas namey filtrándolas (consultando) usando el .query()método:

In [101]: (df.assign(count=df.groupby('name').receipt.transform('size'))
     ...:    .query("category in ['dog','cat'] and count > 1"))
     ...:
Out[101]:
   receipt    name  etc category  count
1        1  george  xxx      cat      4
4        3    bill  xxx      dog      5
6        5    bill  xxx      cat      5
7        5    bill  xxx      cat      5
8        5    bill  xxx      dog      5

o puede agrupar por varias columnas y filtrar los grupos resultantes:

In [102]: df.groupby(['name','category']).filter(lambda x: len(x) > 2)
Out[102]:
   receipt    name  etc category
0        1  george  xxx     fish
2        2  george  xxx     fish
9        6  george  xxx     fish
MaxU
fuente