Data Quality - Introducción

Evaluando los conceptos claves a la hora de evaluar la calidad de los datos utilizados en un reporte, pueden formarse algunas guias para automatizar el analisis como etapa fundamental del gobierno de datos.

Llamaremos a estas guias Principios de Calidad, definidos como:

  1. Validez: El formato de los datos es el correcto
  2. Completitud: No hay datos faltantes
  3. Duplicidad: No hay datos duplicados
  4. Integridad: Los datos relacionados entre sí siguen la lógica planeada
  5. Precisión: Los datos no varían más que un umbral definido a lo largo del tiempo

A partir de estos 5 principios, podemos generar Reglas de Calidad, aplicables a lo largo del perimetro de nuestras bases de datos.

Las lineas de trabajo pueden verse de la siguiente manera:

image.png

Importo librerias

In [ ]:
import pandas as pd
import numpy as np
import sklearn as sk

import matplotlib.pyplot as plt
import plotly.express as px
import seaborn as sns
plt.style.use('fivethirtyeight') 
color_pal = sns.color_palette()

import warnings
warnings.filterwarnings('ignore')

from google.colab import drive
drive.mount('/content/drive')

#fechas
import datetime as dt
from datetime import timedelta

Importo dataset

Resumen de la base de datos

Para este caso, tomaremos como ejemplo a una base de datos que contiene las canciones que fueron hits en Spotify. Ademas de enseñarnos el artista y su nombre, nos presenta los atributos de la cancion, como lo es la duracion, y otros mas interesantes, como puede ser la "bailabilidad".

Pueden descargar el archivo aqui: https://www.kaggle.com/code/shreydan/spotify-top-hits-eda/data

In [2]:
df = pd.read_csv('/content/drive/MyDrive/Python/DQ/songs_normalize.csv') #Indicar ruta personal
In [3]:
df.shape
Out[3]:
(2000, 18)
In [4]:
df.head(3)
Out[4]:
artist song duration_ms explicit year popularity danceability energy key loudness mode speechiness acousticness instrumentalness liveness valence tempo genre
0 Britney Spears Oops!...I Did It Again 211160 False 2000 77 0.751 0.834 1 -5.444 0 0.0437 0.3000 0.000018 0.355 0.894 95.053 pop
1 blink-182 All The Small Things 167066 False 1999 79 0.434 0.897 0 -4.918 1 0.0488 0.0103 0.000000 0.612 0.684 148.726 rock, pop
2 Faith Hill Breathe 250546 False 1999 66 0.529 0.496 7 -9.007 1 0.0290 0.1730 0.000000 0.251 0.278 136.859 pop, country

1.Validez

Estudio columnas del dataset

In [5]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2000 entries, 0 to 1999
Data columns (total 18 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   artist            2000 non-null   object 
 1   song              2000 non-null   object 
 2   duration_ms       2000 non-null   int64  
 3   explicit          2000 non-null   bool   
 4   year              2000 non-null   int64  
 5   popularity        2000 non-null   int64  
 6   danceability      2000 non-null   float64
 7   energy            2000 non-null   float64
 8   key               2000 non-null   int64  
 9   loudness          2000 non-null   float64
 10  mode              2000 non-null   int64  
 11  speechiness       2000 non-null   float64
 12  acousticness      2000 non-null   float64
 13  instrumentalness  2000 non-null   float64
 14  liveness          2000 non-null   float64
 15  valence           2000 non-null   float64
 16  tempo             2000 non-null   float64
 17  genre             2000 non-null   object 
dtypes: bool(1), float64(9), int64(5), object(3)
memory usage: 267.7+ KB

Creamos primeras reglas de calidad

Las reglas de calidad tendrán dos (o tres) opciones como resultado:

  1. Texto indicando porcentaje de cumplimiento de la regla de calidad
  2. Conteo de registros en incumplimiento
  3. Detalle de registros en incumplimiento

Regla 1.1: La fecha (año) no puede tener mas que 4 digitos

In [6]:
def regla_1_1(columna,tabla=False):
  
  conteo = len([x for x in df[columna] if len(str(x))!=4])
  if tabla==False:
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/len(df)))*100,2)}% para la columna {columna}')
  else:
    return conteo

Al indicarle unicamente la columna, nos otorga un texto que indica el % de cumplimiento de la regla de calidad

In [7]:
regla_1_1('year')
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna year

En cambio, si entregamos como Verdadero al parametro "tabla", nos otorga unicamente el valor de registros en incumplimiento. En este caso, 0.

In [8]:
regla_1_1('year',tabla=True)
Out[8]:
0

Regla 1.2: No pueden haber valores no permitidos

Un ejempo para esta base de datos puede ser que el año no sea mayor al actual, o que la "danceability" o "energy" no sea mayor a 1, como fue definida.

Confirmamos cuales son las columnas con intervalo [0;1]

In [9]:
numericas = df.select_dtypes( include= ['int64','float64'])
[print(f'Columna {x}: Valor maximo : {max(df[x])}, Valor minimo: {min(df[x])}') for x in numericas.columns][1]
Columna duration_ms: Valor maximo : 484146, Valor minimo: 113000
Columna year: Valor maximo : 2020, Valor minimo: 1998
Columna popularity: Valor maximo : 89, Valor minimo: 0
Columna danceability: Valor maximo : 0.975, Valor minimo: 0.129
Columna energy: Valor maximo : 0.999, Valor minimo: 0.0549
Columna key: Valor maximo : 11, Valor minimo: 0
Columna loudness: Valor maximo : -0.276, Valor minimo: -20.514
Columna mode: Valor maximo : 1, Valor minimo: 0
Columna speechiness: Valor maximo : 0.576, Valor minimo: 0.0232
Columna acousticness: Valor maximo : 0.976, Valor minimo: 1.92e-05
Columna instrumentalness: Valor maximo : 0.985, Valor minimo: 0.0
Columna liveness: Valor maximo : 0.853, Valor minimo: 0.0215
Columna valence: Valor maximo : 0.973, Valor minimo: 0.0381
Columna tempo: Valor maximo : 210.851, Valor minimo: 60.019

Creamos código de la regla de calidad

In [10]:
def regla_1_2(columna,tabla=False):
  
  conteo = len([x for x in df[columna] if x>1 or x<0])

  if tabla==False:
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/len(df)))*100,2)}% para la columna {columna}')
  else: 
    return conteo
In [11]:
columnas = ['danceability','energy','mode','speechiness','acousticness','instrumentalness','valence']

Opcion 1: unicamente % cumplimiento para cada columna

In [12]:
for col in columnas:
  regla_1_2(col)
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna danceability
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna energy
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna mode
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna speechiness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna acousticness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna instrumentalness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna valence

Opcion 2: unicamente N° registros en incumplimiento para cada columna

In [13]:
for col in columnas:
  print(regla_1_2(col,tabla=True))
0
0
0
0
0
0
0

2.Completitud

Regla 2.1: No deben existir registros nulos

In [14]:
def regla_2_1(columna,tabla=False):

  conteo = df[columna].isna().sum()

  if tabla == False:
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/len(df)))*100,2)}% para la columna {columna}')
  else: 
    return conteo

Opcion 1: unicamente resumen

In [15]:
regla_2_1('year')
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna year

Ahora para todas las columnas

In [16]:
for col in df.columns:
  regla_2_1(col)
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna artist
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna song
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna duration_ms
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna explicit
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna year
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna popularity
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna danceability
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna energy
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna key
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna loudness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna mode
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna speechiness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna acousticness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna instrumentalness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna liveness
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna valence
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna tempo
El porcentaje de cumplimiento de la regla de calidad es de 100.0% para la columna genre

Opcion 2: unicamente cantidades

In [17]:
for col in df.columns:
  print(regla_2_1(col,tabla=True))
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

3.Duplicidad

Regla 3.1: No deben haber datos duplicados

Previamente, hay que definir que en que columnas si tiene sentido que hayan duplicados, y descartarlas de este analisis puntual

Observo valores únicos de cada una de ellas

In [18]:
#Funcion para mostrar DataFrames lado por lado
#fuente: https://stackoverflow.com/questions/38783027/jupyter-notebook-display-two-pandas-tables-side-by-side

from IPython.display import display_html
from itertools import chain,cycle
def display_side_by_side(*args,titles=cycle([''])):
    html_str=''
    for df,title in zip(args, chain(titles,cycle(['</br>'])) ):
        html_str+='<th style="text-align:center"><td style="vertical-align:top">'
        html_str+=f'<h2>{title}</h2>'
        html_str+=df.to_html().replace('table','table style="display:inline"')
        html_str+='</td></th>'
    display_html(html_str,raw=True)


def valores_unicos(columna):
    data_frame = pd.DataFrame(df[columna].value_counts())
    data_frame['share']=data_frame[columna]/sum(data_frame[columna])*100 
    return data_frame

for col in df.columns:
    display_side_by_side(valores_unicos(col).head(),titles = [col])

artist

artist share
Rihanna 25 1.25
Drake 23 1.15
Eminem 21 1.05
Calvin Harris 20 1.00
Britney Spears 19 0.95

song

song share
Sorry 5 0.25
Don't 3 0.15
Closer 3 0.15
Breathe 3 0.15
It's My Life 3 0.15

duration_ms

duration_ms share
212106 4 0.20
240040 3 0.15
207506 3 0.15
202066 3 0.15
243533 3 0.15

explicit

explicit share
False 1449 72.45
True 551 27.55

year

year share
2012 115 5.75
2017 111 5.55
2001 108 5.40
2018 107 5.35
2010 107 5.35

popularity

popularity share
0 126 6.30
69 76 3.80
68 75 3.75
73 69 3.45
74 69 3.45

danceability

danceability share
0.736 12 0.60
0.688 12 0.60
0.687 11 0.55
0.682 11 0.55
0.791 11 0.55

energy

energy share
0.783 15 0.75
0.862 12 0.60
0.768 11 0.55
0.800 10 0.50
0.791 10 0.50

key

key share
1 267 13.35
11 199 9.95
0 198 9.90
7 197 9.85
5 182 9.10

loudness

loudness share
-6.366 5 0.25
-5.595 4 0.20
-5.153 4 0.20
-3.782 4 0.20
-5.611 3 0.15

mode

mode share
1 1107 55.35
0 893 44.65

speechiness

speechiness share
0.0432 13 0.65
0.0290 12 0.60
0.0322 11 0.55
0.0363 10 0.50
0.1090 9 0.45

acousticness

acousticness share
0.230 7 0.35
0.107 7 0.35
0.150 7 0.35
0.191 6 0.30
0.157 6 0.30

instrumentalness

instrumentalness share
0.000000 1087 54.35
0.001300 3 0.15
0.000108 3 0.15
0.000002 3 0.15
0.000139 3 0.15

liveness

liveness share
0.104 25 1.25
0.111 23 1.15
0.107 20 1.00
0.108 19 0.95
0.118 19 0.95

valence

valence share
0.418 11 0.55
0.740 9 0.45
0.400 8 0.40
0.446 8 0.40
0.801 8 0.40

tempo

tempo share
140.022 4 0.20
97.954 3 0.15
83.066 3 0.15
127.999 3 0.15
120.003 3 0.15

genre

genre share
pop 428 21.40
hip hop, pop 277 13.85
hip hop, pop, R&B 244 12.20
pop, Dance/Electronic 221 11.05
pop, R&B 178 8.90

En este caso, solo tiene sentido contar duplicados para canciones repetidas.

Como las canciones pueden tener mismo nombre para distintos artistas, en este caso utilizaremos como primary key a Artist y Song

In [19]:
df['primary_key']=df['artist']+df['song']

Creamos codigo de regla

In [20]:
def regla_3_1(columna,error=False, tabla=False):
  
  conteo = len(df) - len(df.drop_duplicates(columna))
  errores = df[df.duplicated(columna)]

  if error==True and tabla==True:
    raise TypeError('Solo podes poner True a uno de los dos parametros')



  ### Por si queremos ver unicamente el numero  
  elif tabla == True:
    return conteo

  ### Por si queremos ver las incidencias
 
  elif error==True: 
    return pd.DataFrame(errores[columna].values,columns=[columna])

  ### Por si queremos ver solo la compliance

  else: 
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/len(df)))*100,2)}% para la columna {columna}')

Opcion 1: Unicamente % de cumplimientos

In [21]:
regla_3_1('primary_key')
El porcentaje de cumplimiento de la regla de calidad es de 96.3% para la columna primary_key

Opcion 2: N° de incumplimientos

In [22]:
regla_3_1('primary_key',tabla=True)
Out[22]:
74

Opcion 3: Detalle de errores

In [23]:
regla_3_1('primary_key',error=True)
Out[23]:
primary_key
0 Craig DavidFill Me In
1 Destiny's ChildIndependent Women, Pt. 1
2 GabrielleRise
3 Linkin ParkIn the End
4 Kylie MinogueSpinning Around
... ...
69 Jax JonesBreathe
70 Cardi BBodak Yellow
71 Travis ScottSICKO MODE
72 Billie Eilishlovely (with Khalid)
73 Post MaloneBetter Now

74 rows × 1 columns

Solo podremos ver uno de los tipos

In [24]:
regla_3_1('primary_key',error=True,tabla=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-4840ea4fb6fa> in <module>
----> 1 regla_3_1('primary_key',error=True,tabla=True)

<ipython-input-20-c45a89b85b4b> in regla_3_1(columna, error, tabla)
      5 
      6   if error==True and tabla==True:
----> 7     raise TypeError('Solo podes poner True a uno de los dos parametros')
      8 
      9 

TypeError: Solo podes poner True a uno de los dos parametros

4.Integridad

Las reglas de integridad tienen como objetivo hacer controles de consistencia entre distintas columnas de un mismo objeto

Regla 4.1: Valores altos de acustica deben venir con valores bajos de instrumental

In [25]:
def regla_4_1(threshold_down,threshold_up,col1,col2,tabla=False):

  temp = df.copy()
  temp['4.1']=['error' if x > threshold_down and  y > threshold_up else 'ok' for x,y in zip(df[col1],df[col2])]
  conteo= len(temp[temp['4.1']=='error'])
  conteo_df=len(temp)
  canciones = temp[temp['4.1']=='error'].iloc[:, 1].values
  
  if tabla==False:  
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/conteo_df))*100,2)}% para las columnas {col1,col2}. \nLas canciones que no cumplen la regla son {canciones}')

  else:
    return conteo

Si queremos ver el detalle completo:

In [26]:
regla_4_1(threshold_down=0.4,threshold_up=0.7,col1='acousticness',col2='instrumentalness')
El porcentaje de cumplimiento de la regla de calidad es de 99.9% para las columnas ('acousticness', 'instrumentalness'). 
Las canciones que no cumplen la regla son ['Intro' 'Sunset Lover']

Si solo queremos ver el numero de indicidencias:

In [27]:
regla_4_1(threshold_down=0.4,threshold_up=0.7,col1='acousticness',col2='instrumentalness',tabla=True)
Out[27]:
2

5.Precisión

Podemos crear una regla de calidad que se fije, en este caso particular, si la variacion del total de hits por año no sea mayor a un parametro que le indiquemos.

Regla 5.1: La variacion del total de registros por año/mes/dia no puede ser mayor a un parametro definido.

In [28]:
def regla_5_1(fecha,parametro,tabla=False):

  conteo_df = df.groupby(fecha)[fecha].agg(['count'])
  conteo_df['lag'] = conteo_df['count'].shift(1)
  conteo_df['var']  = round(abs((conteo_df['count'] / conteo_df['lag']) - 1 )*100,2)
  fallas = conteo_df[conteo_df['var'] > parametro].index.tolist()
  fallados = conteo_df[conteo_df['var'] > parametro]['var'].values.tolist()
  conteo = len(conteo_df[conteo_df['var'] > parametro].index.tolist())  
  
  if tabla == False:
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/len(conteo_df)))*100,2)}% para la columna {fecha}. \nLas fechas que no cumplen la variacion del {parametro} son {fallas}, variando {fallados} ')
  else:
    return conteo

Detalle:

In [29]:
regla_5_1(fecha='year',parametro= 30)
El porcentaje de cumplimiento de la regla de calidad es de 82.61% para la columna year. 
Las fechas que no cumplen la variacion del 30 son [1999, 2000, 2001, 2020], variando [3700.0, 94.74, 45.95, 96.63] 

Solo el numero:

In [30]:
regla_5_1(fecha='year',parametro= 30,tabla=True)
Out[30]:
4

Regla 5.2: La métrica no puede superar un umbral determinado (por ejemplo, la acustica no puede ser mayor a 0.9)

In [31]:
def regla_5_2(columna,umbral,tabla=False):
  conteo_df = df[df[columna]>umbral]
  conteo = len(conteo_df)
  errores = conteo_df['song'].values

  if tabla==False:
    return print(f'El porcentaje de cumplimiento de la regla de calidad es de {round((1-(conteo/len(df)))*100,2)}% para la columna {columna}. \nLos registros que sobrepasan el umbral de {umbral} son {errores} ')

  else:
    return conteo

Detalle

In [32]:
regla_5_2('acousticness',0.9)
El porcentaje de cumplimiento de la regla de calidad es de 99.6% para la columna acousticness. 
Los registros que sobrepasan el umbral de 0.9 son ['Everytime' 'Mad World (Feat. Michael Andrews)' 'Goodbye My Lover' 'Stay'
 'When I Was Your Man' 'All of Me' 'lovely (with Khalid)'
 'lovely (with Khalid)'] 

Cantidad

In [33]:
regla_5_2('acousticness',0.9,tabla=True)
Out[33]:
8

Drilldown

Tambien puede hacerse lo mismo pero segun un drilldown, cual ayude a agrupar los resultados según la poblacion que se quiera analizar.

Por ejemplo, podemos ver los saltos en las reglas de calidad según el genero de cada cancion:

Corregimos formato para que sea genero unico

In [34]:
df['genre']=df['genre'].apply(lambda x: x.split(',')[0].lower())

Creamos regla

In [35]:
def regla_5_3(columna,umbral,drilldown=False,col_drilldown = None):
  
  conteo_df = df[df[columna]>umbral]
  
  if drilldown==False:
    
    conteo = len(conteo_df)
    errores = conteo_df['song'].values
    return round((1-(conteo/len(df)))*100,2)
    
  else:
    
    conteo = pd.DataFrame(conteo_df.groupby(col_drilldown)['song'].count().sort_values(ascending=False))
    return conteo
In [36]:
regla_5_3('acousticness',0.6)
Out[36]:
96.85

Ahora con drilldown segun el genero de la canción

In [37]:
regla_5_3('acousticness',0.6,drilldown=True,col_drilldown='genre')
Out[37]:
song
genre
pop 38
hip hop 13
rock 4
set() 2
country 1
dance/electronic 1
folk/acoustic 1
latin 1
metal 1
world/traditional 1

Visualizamos los resultados de la regla de calidad

In [38]:
data = regla_5_3('acousticness',0.6,drilldown=True,col_drilldown='genre')

sns.barplot(data=data
            ,x=data.index,
            y='song',
            palette='Blues_r')
            
plt.title('Incidencias regla 5.3 según Genero musical', fontsize = 15)
plt.xticks(rotation=45)
plt.grid(False)

plt.show()

Resultados

Creamos dataframes particulares con los resultados de cada regla de calidad, para las columnas utilizadas en los ejemplos enseñados previamente.

Luego, los unimos en un dataframe final llamado resultados

In [39]:
rdos_validez_1 = pd.DataFrame([regla_1_1.__name__,regla_1_1('year',tabla=True),'year'],index=['Regla','Errores','Variable']).T

rdos_validez_2 = pd.DataFrame([[regla_1_2.__name__,regla_1_2(col,tabla=True),col] for col in columnas]
             ,columns=['Regla','Errores','Variable'])


rdos_completitud = pd.DataFrame([[regla_2_1.__name__,regla_2_1(col,tabla=True),col] for col in columnas]
             ,columns=['Regla','Errores','Variable'])

rdos_duplicidad = pd.DataFrame([regla_3_1.__name__,regla_3_1('primary_key',tabla=True),'primary_key'],index=['Regla','Errores','Variable']).T

rdos_integridad = pd.DataFrame([regla_4_1.__name__,regla_4_1(threshold_down=0.4,threshold_up=0.7,col1='acousticness',col2='instrumentalness',tabla=True),'acousticness-instrumentalness'],index=['Regla','Errores','Variable']).T

rdos_precision_1 = pd.DataFrame([regla_5_1.__name__,regla_5_1(fecha='year',parametro= 30,tabla=True),'year'],index=['Regla','Errores','Variable']).T

rdos_precision_2 = pd.DataFrame([[regla_5_2.__name__,regla_5_2(col,0.9,tabla=True),col] for col in ['danceability','energy','speechiness','acousticness','instrumentalness','valence']]
                                ,columns=['Regla','Errores','Variable'])

resultados = pd.concat([rdos_validez_1,rdos_validez_2,rdos_completitud,rdos_duplicidad,rdos_integridad,rdos_precision_1,rdos_precision_2]).reset_index(drop=True)
resultados
Out[39]:
Regla Errores Variable
0 regla_1_1 0 year
1 regla_1_2 0 danceability
2 regla_1_2 0 energy
3 regla_1_2 0 mode
4 regla_1_2 0 speechiness
5 regla_1_2 0 acousticness
6 regla_1_2 0 instrumentalness
7 regla_1_2 0 valence
8 regla_2_1 0 danceability
9 regla_2_1 0 energy
10 regla_2_1 0 mode
11 regla_2_1 0 speechiness
12 regla_2_1 0 acousticness
13 regla_2_1 0 instrumentalness
14 regla_2_1 0 valence
15 regla_3_1 74 primary_key
16 regla_4_1 2 acousticness-instrumentalness
17 regla_5_1 4 year
18 regla_5_2 70 danceability
19 regla_5_2 224 energy
20 regla_5_2 0 speechiness
21 regla_5_2 8 acousticness
22 regla_5_2 3 instrumentalness
23 regla_5_2 94 valence

Visualizamos resultados

In [40]:
saltos_x_col = resultados.groupby('Variable')['Errores'].agg(['sum'])
saltos_x_regla = resultados.groupby('Regla')['Errores'].agg(['sum'])


plt.figure(figsize = (12,5))
plt.subplot(1,2,1)

ax = sns.barplot(x=saltos_x_col.index , y= 'sum',data=saltos_x_col, palette = 'coolwarm_r')

plt.title('Incidencias por variable', fontsize = 15)
plt.xticks(rotation=90,fontsize=10)
plt.ylabel('Incidencias')
plt.grid(False)


plt.subplot(1,2,2)
ax2= sns.barplot(x=saltos_x_regla.index , y= 'sum',data=saltos_x_regla, palette= 'coolwarm_r')

plt.title('Incidencias por regla de calidad', fontsize = 15)

plt.ylabel('Incidencias')

plt.xticks(rotation=90,fontsize=10)

plt.grid(False)
In [44]:
import plotly.io as pio
pio.renderers.default = "notebook"
In [45]:
px.bar(saltos_x_col, x=saltos_x_col.index , y= 'sum',title='Incidencias por variable',labels={
                     "sum": "Incidencias",
                     "Variable": "Variable"
                 },
       color_discrete_sequence=px.colors.sequential.RdBu,width=800, height=400)
In [46]:
px.bar(saltos_x_regla, x=saltos_x_regla.index , y= 'sum',title='Incidencias por regla de calidad',labels={
                     "sum": "Incidencias",
                     "Regla": "Regla"
                 },
       color_discrete_sequence=px.colors.sequential.Plasma,width=800, height=400)

Pasamos a HTML

In [43]:
%%shell

jupyter nbconvert --to html ///content/DQ.ipynb
[NbConvertApp] Converting notebook ///content/DQ.ipynb to html
[NbConvertApp] Writing 590078 bytes to ///content/DQ.html
Out[43]: