¿Cómo puedo obtener estadísticas descriptivas de una matriz NumPy?

5 minutos de lectura

avatar de usuario de beta
beta

Uso el siguiente código para crear un numpy-ndarray. El archivo tiene 9 columnas. Escribo explícitamente cada columna:

dataset = np.genfromtxt("data.csv", delimiter=",",dtype=('|S1', float, float,float,float,float,float,float,int))

Ahora me gustaría obtener algunas estadísticas descriptivas para cada columna (min, max, stdev, mean, mediana, etc.). ¿No debería haber una manera fácil de hacer esto?

Intenté esto:

from scipy import stats
stats.describe(dataset)

pero esto devuelve un error: TypeError: cannot perform reduce with flexible type

¿Cómo puedo obtener estadísticas descriptivas de la matriz NumPy creada?

  • Creo que el error es porque hay varios dtypeestá en su matriz. Especialmente una cadena sería problemática para describir estadísticamente. ¿Quizás podría simplemente recorrer cada una de sus columnas y describir las columnas por separado?

    – MT

    26 de julio de 2016 a las 7:39

  • Gracias por la respuesta. ¿Cómo puedo acceder, por ejemplo, a la segunda columna de la matriz? Lo intenté stats.describe(dataset[2]) pero arroja el mismo error que en mi OP.

    – beta

    26 de julio de 2016 a las 7:40

  • ¿Sospecho que tal vez haya algún problema con mi matriz? ¿Cómo debería verse una matriz numpy adecuada basada en un archivo CSV? el mío se ve así, si lo imprimo: pastebin.com/MYyqbSG0

    – beta

    26 de julio de 2016 a las 7:44

  • @beta Si está tratando con datos no uniformes (parece que lo está), debería echar un vistazo a pandas que es mucho más poderoso para este tipo de cosas.

    – Holt

    26 de julio de 2016 a las 7:45

  • Si no se dan nombres de campo, los nombres de campo predeterminados son 'f0', 'f1'etc. Así que en lugar de stats.describe(dataset[2])usar stats.describe(dataset['f2']).

    –Warren Weckesser

    26 de julio de 2016 a las 14:14


import pandas as pd
import numpy as np

df_describe = pd.DataFrame(dataset)
df_describe.describe()

tenga en cuenta que el conjunto de datos es su np.array para describir.

import pandas as pd
import numpy as np

df_describe = pd.DataFrame('your np.array')
df_describe.describe()

  • Creo que esta es, con mucho, la opción más fácil. Ni siquiera necesita crear una nueva variable, simplemente escriba pd.DataFrame(my_array).describe().

    – kyriakosSt

    7 de agosto de 2020 a las 15:58

  • Para el caso que solicita el OP, creo que el código de esta respuesta debería ser pd.read_csv("data.csv").describe() en lugar de implicar que los datos se cargan en una matriz numpy en primer lugar

    – kyriakosSt

    7 ago 2020 a las 16:00

  • Solo una línea, no for loop nada. Esta es la mejor respuesta.

    – agente18

    28 de diciembre de 2020 a las 10:33

Avatar de usuario de MT
MONTE

Esta no es una solución bonita, pero hace el trabajo. El problema es que al especificar múltiples tipos de d, esencialmente está creando una matriz 1D de tuplas (en realidad np.void), que no puede ser descrito por las estadísticas ya que incluye múltiples tipos diferentes, incl. instrumentos de cuerda.

Esto podría resolverse leyéndolo en dos rondas o usando pandas con read_csv.

Si decides quedarte numpy:

import numpy as np
a = np.genfromtxt('sample.txt', delimiter=",",unpack=True,usecols=range(1,9))
s = np.genfromtxt('sample.txt', delimiter=",",unpack=True,usecols=0,dtype="|S1")

from scipy import stats
for arr in a: #do not need the loop at this point, but looks prettier
    print(stats.describe(arr))
#Output per print:
DescribeResult(nobs=6, minmax=(0.34999999999999998, 0.70999999999999996), mean=0.54500000000000004, variance=0.016599999999999997, skewness=-0.3049304880932534, kurtosis=-0.9943046886340534)

Tenga en cuenta que en este ejemplo la matriz final tiene dtype como floatno intpero se puede convertir fácilmente (si es necesario) a int usando arr.astype(int)

  • Este uso de usecols es bueno. no creo que necesites unpack.

    – hpaulj

    26 de julio de 2016 a las 17:02

  • @hpaulj Si uno accede a los datos de la manera que muestra en su respuesta (que creo que merece ser la respuesta aceptada), entonces no es necesario descomprimir. Aún así, en mi experiencia, tanto con genfromtxt y loadtxt Encuentro que siempre trabajo con columnas (es decir, la transposición de la salida normal) cuando trato con datos científicos de documentos tipo csv. También es menos fácil recorrer los campos de recarray.

    – MT

    27 de julio de 2016 a las 7:04

  • He abierto una pregunta derivada para estructuras anidadas, consulte stackoverflow.com/questions/62385252/…

    – questionto42standswithUkraine

    15 de junio de 2020 a las 9:31

La cuestión de cómo tratar con datos mixtos de genfromtxt aparece a menudo. Las personas esperan una matriz 2d y, en cambio, obtienen una 1d que no pueden indexar por columna. Eso es porque obtienen una matriz estructurada, con un tipo diferente para cada columna.

Todos los ejemplos en el genfromtxt doc muestra esto:

>>> s = StringIO("1,1.3,abcde")
>>> data = np.genfromtxt(s, dtype=[('myint','i8'),('myfloat','f8'),
... ('mystring','S5')], delimiter=",")
>>> data
array((1, 1.3, 'abcde'),
      dtype=[('myint', '<i8'), ('myfloat', '<f8'), ('mystring', '|S5')])

Pero déjame demostrarte cómo acceder a este tipo de datos.

In [361]: txt=b"""A, 1,2,3
     ...: B,4,5,6
     ...: """
In [362]: data=np.genfromtxt(txt.splitlines(),delimiter=",",dtype=('S1,int,float,int'))
In [363]: data
Out[363]: 
array([(b'A', 1, 2.0, 3), (b'B', 4, 5.0, 6)], 
      dtype=[('f0', 'S1'), ('f1', '<i4'), ('f2', '<f8'), ('f3', '<i4')])

Entonces, mi matriz tiene 2 registros (verifique la forma), que se muestran como tuplas en una lista.

accedes fields por nombre, no por número de columna (¿necesito agregar un enlace de documentación de matriz estructurada?)

In [364]: data['f0']
Out[364]: 
array([b'A', b'B'], 
      dtype="|S1")
In [365]: data['f1']
Out[365]: array([1, 4])

En un caso como este podría ser más útil si elijo un dtype con ‘subconjuntos’. Este es un tema de dtype más avanzado

In [367]: data=np.genfromtxt(txt.splitlines(),delimiter=",",dtype=('S1,(3)float'))
In [368]: data
Out[368]: 
array([(b'A', [1.0, 2.0, 3.0]), (b'B', [4.0, 5.0, 6.0])], 
      dtype=[('f0', 'S1'), ('f1', '<f8', (3,))])
In [369]: data['f1']
Out[369]: 
array([[ 1.,  2.,  3.],
       [ 4.,  5.,  6.]])

La columna de caracteres todavía se carga como S1, pero los números ahora están en una matriz de 3 columnas. Tenga en cuenta que todos son flotantes (o int).

In [371]: from scipy import stats
In [372]: stats.describe(data['f1'])
Out[372]: DescribeResult(nobs=2, 
   minmax=(array([ 1.,  2.,  3.]), array([ 4.,  5.,  6.])),
   mean=array([ 2.5,  3.5,  4.5]), 
   variance=array([ 4.5,  4.5,  4.5]), 
   skewness=array([ 0.,  0.,  0.]), 
   kurtosis=array([-2., -2., -2.]))

Documentación oficial de Scipy Ejemplo

#INPUT
from scipy import stats
a = np.arange(10)
stats.describe(a)

#OUTPUT
DescribeResult(nobs=10, minmax=(0, 9), mean=4.5, variance=9.166666666666666,
               skewness=0.0, kurtosis=-1.2242424242424244)

#INPUT
b = [[1, 2], [3, 4]]
stats.describe(b)

#OUTPUT
DescribeResult(nobs=2, minmax=(array([1, 2]), array([3, 4])),
               mean=array([2., 3.]), variance=array([2., 2.]),
               skewness=array([0., 0.]), kurtosis=array([-2., -2.]))

¿Ha sido útil esta solución?