¿Cómo puedo calcular un histograma (tabla de frecuencia) para una sola serie?

4 minutos de lectura

Avatar de usuario de Abe
abe

¿Cómo puedo generar una tabla de frecuencias (o histograma) para una sola Serie? Por ejemplo, si tengo my_series = pandas.Series([1,2,2,3,3,3])¿cómo puedo obtener un resultado como {1: 1, 2: 2, 3: 3} – es decir, un recuento de cuántas veces aparece cada valor en el Series?

Avatar de usuario de DSM
DSM

Quizás .value_counts()?

>>> import pandas
>>> my_series = pandas.Series([1,2,2,3,3,3, "fred", 1.8, 1.8])
>>> my_series
0       1
1       2
2       2
3       3
4       3
5       3
6    fred
7     1.8
8     1.8
>>> counts = my_series.value_counts()
>>> counts
3       3
2       2
1.8     2
fred    1
1       1
>>> len(counts)
5
>>> sum(counts)
9
>>> counts["fred"]
1
>>> dict(counts)
{1.8: 2, 2: 2, 3: 3, 1: 1, 'fred': 1}

  • .value_counts().sort_index(1) para evitar que la primera columna se desordene un poco

    – smci

    17 de abril de 2013 a las 12:12


  • ¿Existe un equivalente para DataFrame, en lugar de series? Intenté ejecutar .value_counts() en un df y obtuve AttributeError: 'DataFrame' object has no attribute 'value_counts'

    – Manoplas

    3 mayo 2013 a las 14:07

  • ¿Hay una manera fácil de convertir estos conteos en proporciones?

    – dsaxton

    31 de julio de 2015 a las 23:53

  • @dsaxton puede usar .value_counts(normalize=True) para convertir los resultados a proporciones

    – Máximo poder

    30/11/2016 a las 21:01

  • Para usar esto en un marco de datos, conviértalo en su representación de matriz numpy 1-D equivalente, como – pd.value_counts(df.values.ravel()) que devuelve una serie cuya index y values Los atributos contienen los elementos únicos y sus recuentos respectivamente.

    – Nickil Maveli

    20 de diciembre de 2016 a las 10:04

Puede usar la comprensión de listas en un marco de datos para contar las frecuencias de las columnas como tales

[my_series[c].value_counts() for c in list(my_series.select_dtypes(include=['O']).columns)]

Desglose:

my_series.select_dtypes(include=['O']) 

Selecciona solo los datos categóricos

list(my_series.select_dtypes(include=['O']).columns) 

Convierte las columnas de arriba en una lista

[my_series[c].value_counts() for c in list(my_series.select_dtypes(include=['O']).columns)] 

Itera a través de la lista anterior y aplica value_counts() a cada una de las columnas

La respuesta proporcionada por @DSM es simple y directa, pero pensé en agregar mi propio aporte a esta pregunta. Si miras el código de pandas.value_countsverás que están pasando muchas cosas.

Si necesita calcular la frecuencia de muchas series, esto podría llevar un tiempo. Una implementación más rápida sería utilizar numpy.unique con return_counts = True

Aquí hay un ejemplo:

import pandas as pd
import numpy as np

my_series = pd.Series([1,2,2,3,3,3])

print(my_series.value_counts())
3    3
2    2
1    1
dtype: int64

Observe aquí que el artículo devuelto es un pandas.Series

En comparación, numpy.unique devuelve una tupla con dos elementos, los valores únicos y los recuentos.

vals, counts = np.unique(my_series, return_counts=True)
print(vals, counts)
[1 2 3] [1 2 3]

Luego puede combinarlos en un diccionario:

results = dict(zip(vals, counts))
print(results)
{1: 1, 2: 2, 3: 3}

Y luego en un pandas.Series

print(pd.Series(results))
1    1
2    2
3    3
dtype: int64

Avatar de usuario de Harshit Jain
Harshit jainista

para la distribución de frecuencia de una variable con valores excesivos, puede colapsar los valores en clases,

Aquí tengo valores excesivos para employrate variable, y no tiene sentido su distribución de frecuencia con directo values_count(normalize=True)

                country  employrate alcconsumption
0           Afghanistan   55.700001            .03
1               Albania   11.000000           7.29
2               Algeria   11.000000            .69
3               Andorra         nan          10.17
4                Angola   75.699997           5.57
..                  ...         ...            ...
208             Vietnam   71.000000           3.91
209  West Bank and Gaza   32.000000               
210         Yemen, Rep.   39.000000             .2
211              Zambia   61.000000           3.56
212            Zimbabwe   66.800003           4.96

[213 rows x 3 columns]

distribución de frecuencia con values_count(normalize=True) sin clasificación, la longitud del resultado aquí es 139 (parece sin sentido como una distribución de frecuencia):

print(gm["employrate"].value_counts(sort=False,normalize=True))

50.500000   0.005618
61.500000   0.016854
46.000000   0.011236
64.500000   0.005618
63.500000   0.005618

58.599998   0.005618
63.799999   0.011236
63.200001   0.005618
65.599998   0.005618
68.300003   0.005618
Name: employrate, Length: 139, dtype: float64

Poniendo clasificación ponemos todos los valores con un cierto rango es decir.

0-10 as 1,
11-20 as 2  
21-30 as 3, and so forth.
gm["employrate"]=gm["employrate"].str.strip().dropna()  
gm["employrate"]=pd.to_numeric(gm["employrate"])
gm['employrate'] = np.where(
   (gm['employrate'] <=10) & (gm['employrate'] > 0) , 1, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=20) & (gm['employrate'] > 10) , 1, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=30) & (gm['employrate'] > 20) , 2, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=40) & (gm['employrate'] > 30) , 3, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=50) & (gm['employrate'] > 40) , 4, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=60) & (gm['employrate'] > 50) , 5, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=70) & (gm['employrate'] > 60) , 6, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=80) & (gm['employrate'] > 70) , 7, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=90) & (gm['employrate'] > 80) , 8, gm['employrate']
   )
gm['employrate'] = np.where(
   (gm['employrate'] <=100) & (gm['employrate'] > 90) , 9, gm['employrate']
   )
print(gm["employrate"].value_counts(sort=False,normalize=True))

después de la clasificación tenemos una clara distribución de frecuencias. aquí podemos ver fácilmente, que 37.64% de los países tienen una tasa de empleo entre 51-60%
y 11.79% de los países tienen una tasa de empleo entre 71-80%

5.000000   0.376404
7.000000   0.117978
4.000000   0.179775
6.000000   0.264045
8.000000   0.033708
3.000000   0.028090
Name: employrate, dtype: float64

¿Ha sido útil esta solución?