Estadistica descriptiva para proyectos #1

Analizando nuestros datos

Hoy vamos a analizar nuestro dataset de proyectos utilizando la «Analítica descriptiva», que segun la Wikipedia es:

«La estadística descriptiva es la técnica matemática que obtiene, organiza, presenta y describe un conjunto de datos con el propósito de facilitar el uso, generalmente con el apoyo de tablas, medidas numéricas o gráficas.»

Empezaremos como siempre, importando las librerías que vamos a utilizar, y cargando nuesto ataSet de proyectos en una variable.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import statsmodels.api as sm
import scipy.stats as ss


plt.style.use('seaborn-darkgrid') 

sns.set()

df = pd.read_csv ('PROYECTOS_2019-2020_v2.csv')

Una de las primeras cosas que podemos hacer, es crear tres de histogramas con las variables de precio, días de proyecto,, y personas asignadas al proyecto.

Un histograma, basicamente, y volviendo a la Wikiedia es:

En estadística, un histograma es una representación gráfica de una variable en forma de barras, donde la superficie de cada barra es proporcional a la frecuencia de los valores representados. Sirven para obtener una «primera vista» general, o panorama, de la distribución de la población, o de la muestra, respecto a una característica, cuantitativa y continua (como la longitud o el peso). De esta manera ofrece una visión de grupo permitiendo observar una preferencia, o tendencia, por parte de la muestra o población por ubicarse hacia una determinada región de valores dentro del espectro de valores posibles (sean infinitos o no) que pueda adquirir la característica.

Así pues, podemos evidenciar comportamientos, observar el grado de homogeneidad, acuerdo o concisión entre los valores de todas las partes que componen la población o la muestra, o, en contraposición, poder observar el grado de variabilidad, y por ende, la dispersión de todos los valores que toman las partes, también es posible no evidenciar ninguna tendencia y obtener que cada miembro de la población toma por su lado y adquiere un valor de la característica aleatoriamente sin mostrar ninguna preferencia o tendencia, entre otras cosas.

No voy a entrar muy en detalle en definiciones, ya que mi intención es mas trabajar la programación practica, que no mostrar mucha teoría, así que me voy a apoyar en la wikipedia para las definiciones teóricas, y si alguien quiere mas información, seguro que puede buscar recursos mucho mas interesantes que los que yo puedo ofrecer.

A continuación os muestro el código para realizarlos.

BinsDias=np.arange(min(df['DIAS_PROYECTO']), max(df['DIAS_PROYECTO']) + 50, 50)
BindsPrecio=np.arange(min(df['PRECIO']), max(df['PRECIO']) + 100000, 100000)
BindsPersonas = np.arange(min(df['PERSONAS_ASIGNADAS']), max(df['PERSONAS_ASIGNADAS']) + 2, 2)

plt.figure(figsize=(16,16))

#Creamos el primer grafico con este formato plt.subplot(filas, columnas, No de grafico)
plt.subplot(221)
plt.title('Histograma Dias proyectos',fontsize = 12)
plt.ylabel('Frecuencia')
plt.xlabel("Duración de los proyectos en dias (%.0f - %.0f)" % (min(df['DIAS_PROYECTO']),max(df['DIAS_PROYECTO']) ))
plt.hist(df['DIAS_PROYECTO'], 
         bins=BinsDias, 
         color='#86bf91',
         alpha=0.5)

plt.subplot(222)
plt.title('Histograma Precio proyectos',fontsize = 12)
plt.ylabel('Frecuencia')
plt.xlabel("Precios de los proyectos (%.0f - %.0f)" % (min(df['PRECIO']),max(df['PRECIO']) ))

plt.hist(df['PRECIO'], 
         bins=BindsPrecio, 
         color='#86bf91',
         alpha=0.5)

plt.subplot(223)
plt.title('Histograma personas asignadas a proyecto',fontsize = 12)
plt.ylabel('Frecuencia')
plt.xlabel("Personas asignadas (%.0f - %.0f)" % (min(df['PERSONAS_ASIGNADAS']),max(df['PERSONAS_ASIGNADAS']) ))

plt.hist(df['PERSONAS_ASIGNADAS'], 
         bins=BindsPersonas, 
         color='#86bf91',
         alpha=0.5)

plt.show()

Con estos gráficos, ya empezamos a intuir hacia donde van a ir los sesgos

Vamos a obtener ahora la media, mediana, moda, sesgo, varianza y desviación estándar (links a cada definición de la Wikipedia).de las personas asignadas al proyecto, los días de duración de un proyecto, y de su precio total una vez finalizado.

mediaDias = int(df["DIAS_PROYECTO"].mean())
medianaDias = int(df["DIAS_PROYECTO"].median())
modaDias = df["DIAS_PROYECTO"].mode().get_values()[0]
CoefAsimetriaDias = ss.skew(df["DIAS_PROYECTO"])
varianzaDias =  np.var(df["DIAS_PROYECTO"])
DesvEstandarDias = np.std(df["DIAS_PROYECTO"])


print("> MEDIA:      %.2f" % (mediaDias))
print("> MEDIANA:    %.2f" % (medianaDias))
print("> MODA:       %.2f" % modaDias)
print("> SESGO:      %.2f" % (CoefAsimetriaDias))
print("> VARIANZA:   %.2f" % (varianzaDias))
print("> DESV. EST:  %.2f" % (DesvEstandarDias))
Valores para df[«DIAS_PROYECTO»]

Cambiamos la variable df["DIAS_PROYECTO"]por la variable df["PRECIO"]y los resultados son los siguientes:

mediaPrecio = int(df["PRECIO"].mean())
medianaPrecio = int(df["PRECIO"].median())
modaPrecio = df["PRECIO"].mode().get_values()[0]
CoefAsimetriaPrecio = ss.skew(df["PRECIO"])
varianzaPrecio =  np.var(df["PRECIO"])
DesvEstandarPrecio = np.std(df["PRECIO"])


print("> MEDIA:      %.2f" % (mediaPrecio))
print("> MEDIANA:    %.2f" % (medianaPrecio))
print("> MODA:       %.2f" % modaPrecio)
print("> SESGO:      %.2f" % (CoefAsimetriaPrecio))
print("> VARIANZA:   %.2f" % (varianzaPrecio))
print("> DESV. EST:  %.2f" % (DesvEstandarPrecio))
Valores para df[«PRECIO»]

Realizamos la misma operación para las personas asignadas a los proyectos:

mediaPersonas = int(df["PERSONAS_ASIGNADAS"].mean())
medianaPersonas = int(df["PERSONAS_ASIGNADAS"].median())
modaPersonas = df["PERSONAS_ASIGNADAS"].mode().get_values()[0]
CoefAsimetriaPersonas = ss.skew(df["PERSONAS_ASIGNADAS"])
varianzaPersonas =  np.var(df["PERSONAS_ASIGNADAS"])
DesvEstandarPersonas = np.std(df["PERSONAS_ASIGNADAS"])



print("> MEDIA:      %.2f" % (mediaPersonas))
print("> MEDIANA:    %.2f" % (medianaPersonas))
print("> MODA:       %.2f" % modaPersonas)
print("> SESGO:      %.2f" % (CoefAsimetriaPersonas))
print("> VARIANZA:   %.2f" % (varianzaPersonas))
print("> DESV. EST:  %.2f" % (DesvEstandarPersonas))
Valores para df[«PERSONAS_ASIGNADAS»]

En la variable PRECIO, la media se ve afectada por los valores que existen a la izquierda del histograma (precio entre 0 – 100.000), que es donde tenemos mas proyectos.

Gracias a tener calculado el sesgo, ya podemos saber que: 

  • Si el coeficiente de sesgo tiene un valor positivo se dice que la distribución es SESGADA a LA DERECHA o que tiene SESGO POSITIVO.
  • Si el coeficiente de sesgo tiene un valor negativo se dice que la distribución es SESGADA a LA IZQUIERDA o que tiene SESGO NEGATIVO.
  • Si el coeficiente de sesgo tiene un valor 0 se dice que la distribución tiene SESGO CERO
En punteado amarillo: la media, en punteado azul: la moda. Fuente Wikipedia

A la Varianza, y la desviación estándar probablemente les dedique algo más de espacio en alguna otro post.

Volveremos en otra entrada sobre todo esto, pero ahora vamos a ver estos datos en un gráfico:

# Dibujamos el historgrama de frecuencias. 

plt.figure(figsize=(35,26))
sns.set(color_codes = True)

plt.subplot(221)

axDias = sns.distplot(df['DIAS_PROYECTO'], 
                      bins=BinsDias,  
                      color='#86bf91',
                      label = 'Distribución Dias')

# creamos las 'Labels'
LMediaDias    = 'Media: {:,.0f}'.format(mediaDias).replace(',', '.')
LMedianaDias  = 'Mediana: {:,.0f}'.format(medianaDias).replace(',', '.')
LModaDias     = 'Moda: {:,.0f}'.format(modaDias).replace(',', '.')
LNormDias     = "Distribución dias proyecto"

# Ggraficamos las lineas con las medias, etc
plt.axvline(mediaDias, color='r', linestyle='--', label = LMediaDias )
plt.axvline(medianaDias, color='g', linestyle='-', label = LMedianaDias)
plt.axvline(modaDias, color='b', linestyle=':', label = LModaDias)

#Creamos la leyenda
plt.legend([LMediaDias, LMedianaDias, LModaDias, LNormDias])


plt.title('Distribución de dias proyectos 2019',fontsize = 16)
plt.ylabel('Frecuencia')
plt.xlabel('Dias Proyecto - Sesgo: %.2f' % (CoefAsimetriaDias))


plt.subplot(222)

axDias = sns.distplot(df['PRECIO'], 
                      bins=BindsPrecio,   
                      color='#86bf91',
                      label = 'Distribución Precio')

# creamos las 'Labels'
LMediaPrecio   = 'Media: {:,.0f}'.format(mediaPrecio).replace(',', '.')
LMedianaPrecio = 'Mediana: {:,.0f}'.format(medianaPrecio).replace(',', '.')
LModaPrecio    = 'Moda: {:,.0f}'.format(modaPrecio).replace(',', '.')
LNormPrecio    = "Distribución Precios proyecto"

# Ggraficamos las lineas con las medias, etc
plt.axvline(mediaPrecio, color='r', linestyle='--', label = LMediaPrecio )
plt.axvline(medianaPrecio, color='g', linestyle='-', label = LMedianaPrecio)
plt.axvline(modaPrecio, color='b', linestyle=':', label = LModaPrecio)

#Creamos la leyenda
plt.legend([LMediaPrecio, LMedianaPrecio, LModaPrecio, LNormPrecio])


plt.title('Distribución precio de proyectos 2019',fontsize = 16)
plt.ylabel('Frecuencia')
plt.xlabel('Precio Proyecto - Sesgo: %.2f' % (CoefAsimetriaPrecio))


plt.subplot(223)

axDias = sns.distplot(df['PERSONAS_ASIGNADAS'], 
                      bins=BindsPersonas,   
                      color='#86bf91',
                      label = 'Distribución Personas')

# creamos las 'Labels'
LMediaPersonas   = 'Media: {:,.0f}'.format(mediaPersonas).replace(',', '.')
LMedianaPersonas = 'Mediana: {:,.0f}'.format(medianaPersonas).replace(',', '.')
LModaPersonas    = 'Moda: {:,.0f}'.format(modaPersonas).replace(',', '.')
LNormPersonas    = "Distribución personas por proyecto"

# Ggraficamos las lineas con las medias, etc
plt.axvline(mediaPersonas, color='r', linestyle='--', label = LMediaPersonas )
plt.axvline(medianaPersonas, color='g', linestyle='-', label = LMedianaPersonas)
plt.axvline(modaPersonas, color='b', linestyle=':', label = LModaPersonas)

#Creamos la leyenda
plt.legend([LMediaPersonas, LMedianaPersonas, LModaPersonas, LNormPersonas])


plt.title('Distribución de personas por proyecto 2019',fontsize = 16)
plt.ylabel('Frecuencia')
plt.xlabel('Personas Proyecto - Sesgo: %.2f' % (CoefAsimetriaPersonas))
plt.show()

El siguiente paso seria crear una tabla de frecuencias con la Frecuencia Absoluta, Relativa, y Acumulada de las clases de proyectos que tenemos.

La clase de proyecto que tenemos esta definida en el campo  df['TIPO_PROYECTO']  y puede ser:

INTERNO

EXTERNO 

OPORTUNIDAD COMERCIAL

#Creamos un Dataframe que contendrá las clases únicamente

# Sacamos los datos únicos de data
clases = df['TIPO_PROYECTO'].unique()
#Creamos el dataframe que contendrá las clases
dat = pd.DataFrame(clases, columns=["Clases"])
#Eliminamos los Nan
dat = dat.dropna()

#Obtenemos las frecuencias absolutas de cada clase
DataFrecAbs = pd.value_counts(df['TIPO_PROYECTO'])
#Creamos una lista con los valores de las frecuencias
listaFrecAbs = DataFrecAbs.values
#Agregamos la columna al dataframe
dat["Frec. Absoluta"] = listaFrecAbs

#Tabla de frecuencia relativa
DataFrecRel = 100 * dat["Frec. Absoluta"] /(sum(dat["Frec. Absoluta"]))
DataFercRel = DataFrecRel.values
#Agregamos nueva columna de frecuentas relativas
dat["Frec. Relativa"] = DataFrecRel

#Obtenemos las frecuencias absolutas acumuladas
#Sacamos una lista de los valores 
DataFrecAbsAcc = dat["Frec. Relativa"].values

#Recorremos la lista para ir creando una nueva lista con las sumas
#Obtener la frecuencia absoluta acumulada
a = []
b = 0
for c in DataFrecAbsAcc:
    b = c + b
    a.append(b)

#Agregamos la nueva columna Fi al Dataframe dat
dat["Frec. Acumulada"] = a
dat
Tabla de frecuencias de la clase «Tipo de Proyecto»

Vamos a ver estos datos en un gráfico:

bins=np.arange(min(dat["Frec. Absoluta"]), max(dat["Frec. Absoluta"]) + 100, 100)

plt.figure(figsize=(10,6))
plt.title('Frecuencia absoluta por tipo de proyecto',fontsize = 18)
plt.ylabel('Frecuencia Absoluta',fontsize = 16)
plt.xlabel("Tipo de proyecto",fontsize = 16)

plt.bar(dat["Clases"], dat["Frec. Absoluta"], 
        align='center',
        color='#86bf91',
        alpha=0.5)
plt.show()

Vamos a calcular la correlación existente entre entre las  variables  PRECIO y DIAS_PROYECTO y PERSONAS_ASIGNADAS

Básicamente, La correlación estadística constituye una técnica estadística que nos indica si dos variables están relacionadas o no.

Se utiliza para entender:

  1. si la relación es positiva o negativa
  2. la fuerza de la relación.

La correlación estadística es medida por lo que se denomina coeficiente de correlación (r). Su valor numérico varía de 1,0 a -1,0. Nos indica la fuerza de la relación.

En general, r> 0 indica una relación positiva y r <0 indica una relación negativa, mientras que r = 0 indica que no hay relación (o que las variables son independientes y no están relacionadas). 

Cuanto más cerca estén los coeficientes de +1,0 y -1,0, mayor será la fuerza de la relación entre las variables.

Como norma general, las siguientes directrices sobre la fuerza de la relación son útiles (aunque muchos expertos podrían disentir con la elección de los límites).

Valor de r Fuerza de relación
-1,0 A -0,5 o 1,0 a 0,5 Fuerte
-0,5 A -0,3 o 0,3 a 0,5 Moderada
-0,3 A -0,1 o 0,1 a 0,3 Débil
-0,1 A 0,1 Ninguna o muy débil

La correlación es solamente apropiada para examinar la relación entre datos cuantificables significativos (por ejemplo, la presión atmosférica o la temperatura) en vez de datos categóricos, tales como el sexo, el color favorito, etc.

Fuente: https://explorable.com/es/la-correlacion-estadistica

Correlacion = df[['PRECIO','PERSONAS_ASIGNADAS','DIAS_PROYECTO']].corr()
print(Correlacion)
Correlación

Con esto podemos observar que:

Tenemos una Relación positiva fuerte entre PRECIO /DIAS_PROYECTO y PRECIO / PERSONAS_ASIGNADAS

También tenemos una Relación Positiva «Muy débil» entre DIAS_PROYECTO y PERSONAS_ASIGNADAS

Vamos a ver esto de manera visual, con un gráfico:

#cambiar la forma de la matriz de rectangular a triangular
matrix = np.triu(Correlacion)

plt.figure(figsize=(16,6))
plt.title('Matriz de Correlación (Precio / Dias de Proyecto / Personas Asignadas)', fontsize = 16)

ax = sns.heatmap(
    Correlacion, 
    annot = True,
    mask=matrix,
    fmt='.2g',
    vmin=-1, vmax=1, center=0,
    cmap=sns.diverging_palette(20, 220, n=200),
    square=True
)
ax.set_xticklabels(
    ax.get_xticklabels(),
    rotation=45,
    horizontalalignment='right');

plt.show()

Nos vemos en próximas entradas!!

¿Te ha gustado? ¡¡Compártelo con el mundo!!