¿Cómo generar diagtwigs legibles en pandas cuando se realiza un bucle sobre columnas?

Generar el dataframe para la replicabilidad:

df = pd.DataFrame(np.random.randn(50, 1000), columns=list('')) 

Compruebe la normalidad de la distribución de cada variable (nota: esto tarda mucho tiempo en ejecutarse)

 # Set the column names columns= df.columns # Loop over all columns fig, axs = plt.subplots(len(df.columns), figsize=(5, 25)) for n, col in enumerate(df.columns): df[col].hist(ax=axs[n]) 

El resultado genera histogtwigs ilegibles y tarda mucho tiempo en ejecutarse.

El tiempo está bien, pero tengo curiosidad por saber si alguien tiene sugerencias para generar histogtwigs legibles (no es necesario que sean elegantes), que pueden revisarse rápidamente para todo el dataframe para garantizar la normalidad de las distribuciones.

Me gusta mucho la respuesta de Nathaniel, pero agregaré mis dos centavos.

Me gustaría ir por mar y, en particular, por mar . Esto le permitirá ajustar fácilmente una distribución normal a cada gráfico de histogtwig y facilitar la visualización.

 import seaborn as sns from scipy.stats import norm import numpy as np import pandas as pd import matplotlib.pyplot as plt cols = 1000 df = pd.DataFrame(np.random.normal(0, 1, [50, cols])) from scipy.stats import norm fig, ax = plt.subplots(figsize = (16, 10)) for i, col in enumerate(df.columns): ax=fig.add_subplot(25, 4, i+1) sns.distplot(df[col],fit=norm, kde=False,ax=ax) plt.tight_layout() 

Además, no estoy seguro de si poner columnas con el mismo nombre en su ejemplo se hizo a propósito. Si ese es el caso, la solución más fácil para recorrer las columnas es usar .iloc y el código se vería así:

 import seaborn as sns from scipy.stats import norm import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.DataFrame(np.random.randn(50, 1000), columns=list('')) fig, ax = plt.subplots(figsize = (12, 10)) for i, col in enumerate(df.columns): plt.subplot(25, 40, i+1) sns.distplot(df.iloc[:,i],fit=norm, kde=False,ax=plt.gca()) plt.axis('off') plt.tight_layout() 

introduzca la descripción de la imagen aquí

Este código genera 1000 histogtwigs y le permite ver cada uno con suficiente detalle para comprender qué tan normalmente distribuidas están las columnas:

 import pandas as pd import matplotlib.pyplot as plt cols = 1000 df = pd.DataFrame(np.random.normal(0, 1, [50, cols])) # Loop over all columns fig, ax = plt.subplots(figsize = (16, 10)) for n, col in enumerate(df.columns): plt.subplot(25, 40, n+1) df[col].hist(ax = plt.gca()) plt.axis('off') plt.tight_layout() plt.savefig('1000_histograms.png', bbox_inches='tight', pad_inches = 0, dpi = 200) 

1000 histogramas

Otra forma de determinar la normalidad es con un gráfico QQ, que puede ser más fácil de visualizar en masa en comparación con un histogtwig:

 import statsmodels.api as sm cols = 1000 df = pd.DataFrame(np.random.normal(0,1, [50, cols])) fig, axs = plt.subplots(figsize=(18, 12)) for n, col in enumerate(df.columns): plt.subplot(25,40,n+1) sm.qqplot(df[col], ax=plt.gca(), #line='45', marker='.', markerfacecolor='C0', markeredgecolor='C0', markersize=2) # sm.qqline(ax=plt.gca(), line='45', fmt='lightgray') plt.axis('off') plt.savefig('1000_QQ_plots13.png', bbox_inches='tight', pad_inches=0, dpi=200) 

1000 parcelas QQ

Cuanto más cerca esté cada línea de una diagonal de 45 grados, mayor será la distribución normal de los datos de la columna.

  1. Prueba de trazo vs normalidad
  2. Proposición
  3. Ejemplo de salida
  4. Ejemplo de código correspondiente

Prueba de trazo vs normalidad

Como se analiza en los comentarios a continuación, la pregunta del OP ha cambiado a miles de ttwigs de administración. Desde esa perspectiva, la respuesta de Nathaniel es apropiada .

Sin embargo, sentí que la intención no dicha era decidir si una variable dada se distribuía normalmente o no, con miles de variables a considerar.

Compruebe la normalidad de la distribución de cada variable (nota: esto tarda mucho tiempo en ejecutarse)

Con eso en mente, me parece (que para mí) que tener un humano revisando miles de plots para detectar distribuciones normales / no normales es un método inadecuado. Hay un idioma francés para esto: “usine à gaz” (“fábrica de gas”)

Por lo tanto, esta respuesta se centra en realizar el análisis programáticamente y proporciona algún tipo de informe más conciso.

Proposición

Realizar el análisis de la normalidad de los datos en un gran número de columnas. Se basa en la sugerencia expresada en esta respuesta .

La idea es:

  • Realizar una prueba de distribución (normalidad) para todas las columnas.
  • capitalizar en un dataframe los resultados
  • Reporte en una gráfica las relaciones normal / no normal.
  • Informe los nombres de columna no normales.

Con este método, podemos usar la progtwigción para manipular las columnas normales / no normales. Por ejemplo, podríamos realizar pruebas de distribución adicionales, o trazar solo la distribución no normal, reduciendo así el número de gráficos para observar.

Ejemplo de salida:

 ------------ Columns probably not a normal dist: Column Not_Normal p-value Normality 0 V True 0.0 Not Normal 0 W True 0.0 Not Normal 0 X True 0.0 Not Normal 0 Y True 0.0 Not Normal 0 Z True 0.0 Not Normal 

introduzca la descripción de la imagen aquí

Descargo de responsabilidad: los métodos utilizados pueden no ser estadísticamente “canónicos”. Se debe tener mucho cuidado al usar herramientas estadísticas, ya que cada una como su dominio de uso específico / caso de uso.

Elegí un valor p de 0.01 (1%), ya que podría ser el próximo valor estándar en publicaciones científicas en lugar del 0.05 (5%) habitual

Uno debe leer https://en.wikipedia.org/wiki/Normality_test

Las pruebas de normalidad univariada incluyen las siguientes:

  • Prueba de K-cuadrado de D’Agostino,
  • Prueba de Jarque-Bera,
  • Prueba de Anderson-Darling,
  • Criterio de Cramér-von Mises,
  • Prueba de lilliefors,
  • Prueba de Kolmogorov-Smirnov
  • Prueba de Shapiro-Wilk, y
  • Prueba de chi cuadrado de Pearson.

Código

El comportamiento puede variar en su computadora dependiendo de RNG (generación de números aleatorios). El siguiente ejemplo se realiza con 5 muestreos aleatorios normales y 5 muestreos aleatorios pareto usando numpy. La prueba de normalidad se desempeña bien en estas condiciones (incluso si siento que las pruebas de valor de 0.0 p son sospechosas incluso para una generación aleatoria de Pareto) Sin embargo, creo que podemos estar de acuerdo en que se trata del método , no de los resultados reales.

 import pandas as pd import numpy as np import scipy from scipy import stats import seaborn as sb import matplotlib.pyplot as plt import sys print('System: {}'.format(sys.version)) for module in [pd, np, scipy, sb]: print('Module {:10s} - version {}'.format(module.__name__, module.__version__)) nb_lines = 10000 headers_normal = 'ABCDE' headers_pareto = 'VWXYZ' reapeat_factor = 1 nb_cols = len(list(reapeat_factor * headers_normal)) df_normal = pd.DataFrame(np.random.randn(nb_lines, nb_cols), columns=list(reapeat_factor * headers_normal)) df_pareto = pd.DataFrame((np.random.pareto(12.0, size=(nb_lines,nb_cols )) + 15.) * 4., columns=list(reapeat_factor * headers_pareto)) df = df_normal.join(df_pareto) alpha = 0.01 df_list = list() # normality code taken from https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.normaltest.html cat_map = {True: 'Not Normal', False: 'Maybe Normal'} for col in df.columns: k2, p = stats.normaltest(df[col]) is_not_normal = p < alpha tmp_df = pd.DataFrame({'Column': [col], 'Not_Normal': [is_not_normal], 'p-value': [p], 'Normality': cat_map[is_not_normal] }) df_list.append(tmp_df) df_results = pd.concat(df_list) df_results['Normality'] = df_results['Normality'].astype('category') print('------------') print('Columns names probably not a normal dist:') # full data print(df_results[(df_results['Normality'] == 'Not Normal')]) # only column names # print(df_results[(df_results['Normality'] == 'Not Normal')]['Column']) print('------------') print('Plotting countplot') sb.countplot(data=df_results, y='Normality', orient='v') plt.show() 

Salidas:

 System: 3.7.2 (default, Feb 21 2019, 17:35:59) [MSC v.1915 64 bit (AMD64)] Module pandas - version 0.24.1 Module numpy - version 1.16.2 Module scipy - version 1.2.1 Module seaborn - version 0.9.0 ------------ Columns names probably not a normal dist: Column Not_Normal p-value Normality 0 V True 0.0 Not Normal 0 W True 0.0 Not Normal 0 X True 0.0 Not Normal 0 Y True 0.0 Not Normal 0 Z True 0.0 Not Normal ------------ Plotting countplot 

Intenta algo como esto:

 plt.figure(figsize=(26, 3 * len(df.columns)) for i, col in enumerate(df.columns): plt.subplot(3, 4, i + 1) plt.hist(df[col], color='blue', bins=100) plt.title(col) 

4 es el número de columnas, 3 es el número de filas. Supongo que en lugar de 3 es mejor escribir algo como esto:

 plt.subplot(len(df.columns) / 4, 4, i + 1) 

Intente esto: tight_layout asegura que no se superponga, el tamaño de la figura controla el tamaño de cada gráfico.

 import pandas as pd, numpy as np import matplotlib.pyplot as plt df = pd.DataFrame(np.random.randn(1000, 3*30), columns=list('ABC'*30)) df.hist(figsize=(20,20)) plt.tight_layout() plt.show() 

Sin embargo, si está buscando una prueba de normalidad, sugeriría usar algo como esto: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.normaltest.html en lugar de confiar en la inspección visual, Especialmente si tienes muchas variables.