Practica PANDAS - Solución

Curso Python para Ciencia de datos

Por Jose R. Zapata - https://joserzapata.github.io/

Invítame a un Café

NOTA: Realizar Primero los ejercicios y luego revisar las soluciones propuestas.

Para realizar los ejercicios prácticos de este capitulo, hacer click en el siguiente enlace que los llevara a Google Colab, donde podrán ejecutar el código y realizar los ejercicios propuestos.

Ejercicios Pandas - click para abrir en colab

Ejercicio SF Salaries Utilizaremos el SF Salaries Dataset Kaggle. Simplemente siga y complete las tareas que se detallan a continuación en negrita. Las tareas serán cada vez más difíciles a medida que avance.

La idea principal es aplicar pandas para organizar informacion, manipularla, buscar información en el dataset

Importe pandas como pd. e imprima la version que esta usando

# Copie el código aca
import pandas as pd

print(f"version de pandas = {pd.__version__}")
version de pandas = 2.2.2

leer el archivo Salaries.csv en un dataframe llamado salarios

salarios = pd.read_csv(
    "https://joserzapata.github.io/courses/python_ciencia_datos/Salaries.csv"
)

Use el método .info() para encontrar cuantas Columnas de atributos hay y que tipo de datos tiene cada una.

# Copie el código aca
salarios.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 148654 entries, 0 to 148653
Data columns (total 13 columns):
 #   Column            Non-Null Count   Dtype
---  ------            --------------   -----
 0   Id                148654 non-null  int64
 1   EmployeeName      148654 non-null  object
 2   JobTitle          148654 non-null  object
 3   BasePay           148045 non-null  float64
 4   OvertimePay       148650 non-null  float64
 5   OtherPay          148650 non-null  float64
 6   Benefits          112491 non-null  float64
 7   TotalPay          148654 non-null  float64
 8   TotalPayBenefits  148654 non-null  float64
 9   Year              148654 non-null  int64
 10  Notes             0 non-null       float64
 11  Agency            148654 non-null  object
 12  Status            0 non-null       float64
dtypes: float64(8), int64(2), object(3)
memory usage: 14.7+ MB
  • Segun la información del dataframe su tamaño es de memory usage: 14.7+ MB

  • las columnas Notes y Status solamente tienen valores NaN, verifique que dice 0 non-null osea 0 valores son diferentes a NaN entonces todos los valores son NaN en esas columnas

Elimine las columnas Notes y Status Recuerde usar el método de forma permanente (inplace), y luego visualice cuantas filas y columnas tiene luego de eliminar las columnas

# Copie el código aca
salarios.drop(["Notes", "Status"], axis="columns", inplace=True)
salarios.shape
(148654, 11)

¿Cual es la nueva información del dataframe?

# Copie el código aca
salarios.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 148654 entries, 0 to 148653
Data columns (total 11 columns):
 #   Column            Non-Null Count   Dtype
---  ------            --------------   -----
 0   Id                148654 non-null  int64
 1   EmployeeName      148654 non-null  object
 2   JobTitle          148654 non-null  object
 3   BasePay           148045 non-null  float64
 4   OvertimePay       148650 non-null  float64
 5   OtherPay          148650 non-null  float64
 6   Benefits          112491 non-null  float64
 7   TotalPay          148654 non-null  float64
 8   TotalPayBenefits  148654 non-null  float64
 9   Year              148654 non-null  int64
 10  Agency            148654 non-null  object
dtypes: float64(6), int64(2), object(3)
memory usage: 12.5+ MB
  • Se puede verificar que al borrar las columnas que no tenian solo NaN se disminuye el tamaño del dataframe a: memory usage: 12.5+ MB

Observe los primeros 5 registros del DataFrame.

# Copie el código aca
salarios.head()

IdEmployeeNameJobTitleBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYearAgency
01NATHANIEL FORDGENERAL MANAGER-METROPOLITAN TRANSIT AUTHORITY167411.180.00400184.25NaN567595.43567595.432011San Francisco
12GARY JIMENEZCAPTAIN III (POLICE DEPARTMENT)155966.02245131.88137811.38NaN538909.28538909.282011San Francisco
23ALBERT PARDINICAPTAIN III (POLICE DEPARTMENT)212739.13106088.1816452.60NaN335279.91335279.912011San Francisco
34CHRISTOPHER CHONGWIRE ROPE CABLE MAINTENANCE MECHANIC77916.0056120.71198306.90NaN332343.61332343.612011San Francisco
45PATRICK GARDNERDEPUTY CHIEF OF DEPARTMENT,(FIRE DEPARTMENT)134401.609737.00182234.59NaN326373.19326373.192011San Francisco

Observe los ultimos 5 registros del DataFrame.

# Copie el código aca
salarios.tail()

IdEmployeeNameJobTitleBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYearAgency
148649148650Roy I TilleryCustodian0.00.00.000.00.000.002014San Francisco
148650148651Not providedNot providedNaNNaNNaNNaN0.000.002014San Francisco
148651148652Not providedNot providedNaNNaNNaNNaN0.000.002014San Francisco
148652148653Not providedNot providedNaNNaNNaNNaN0.000.002014San Francisco
148653148654Joe LopezCounselor, Log Cabin Ranch0.00.0-618.130.0-618.13-618.132014San Francisco

¿Cuantas filas y columnas tiene el dataframe?

# Copie el código aca
salarios.shape
(148654, 11)

Observe los 10 registros que estan desde el indice 3000

# Copie el código aca
salarios.iloc[3000:3010]

IdEmployeeNameJobTitleBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYearAgency
30003001WILLIAM BOYLEFIREFIGHTER105934.6518530.9816389.60NaN140855.23140855.232011San Francisco
30013002ALAN LINELECTRONIC MAINTENANCE TECHNICIAN98965.8041504.40380.00NaN140850.20140850.202011San Francisco
30023003WILLIAM CONLEYSERGEANT III (POLICE DEPARTMENT)130457.783131.427256.39NaN140845.59140845.592011San Francisco
30033004ROBERT MCDONALDLIEUTENANT, FIRE DEPARTMENT123104.991833.5615897.68NaN140836.23140836.232011San Francisco
30043005MICHAEL COSTELLOPOLICE OFFICER III112401.087957.7420466.93NaN140825.75140825.752011San Francisco
30053006EDNA HOMANAGER V140821.370.000.00NaN140821.37140821.372011San Francisco
30063007RODRIGO CONELREGISTERED NURSE126120.003981.7810714.21NaN140815.99140815.992011San Francisco
30073008VICTOR HURTADOFIREFIGHTER105934.6713112.7621763.50NaN140810.93140810.932011San Francisco
30083009DONALD LANDRYTRANSIT POWER LINE WORKER92861.5039789.328135.86NaN140786.68140786.682011San Francisco
30093010FRANK LEEINSPECTOR III, (POLICE DEPARTMENT)130481.56725.409579.58NaN140786.54140786.542011San Francisco

La columna Benefits tiene valores NaN, ¿Cuantos NaN tiene la columna Benefits? (TIP: Seleccione la Columna y vefique cuantos Na tiene .isna() luego sumelos .sum() )

# Copie el código aca
salarios["Benefits"].isna().sum()
36163

Al parecer los valores faltantes en la columna Benefits es por que no se le pagan beneficios entonces:

Reemplace los valores NaN de la Columna Benefits por el valor de cero (Recuerde usar el método de forma inplace) y mostrar los primeros 10 elementos de la lista

# Copie el código aca
salarios["Benefits"].fillna(value=0, inplace=True)
salarios.head(10)

IdEmployeeNameJobTitleBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYearAgency
01NATHANIEL FORDGENERAL MANAGER-METROPOLITAN TRANSIT AUTHORITY167411.180.00400184.250.0567595.43567595.432011San Francisco
12GARY JIMENEZCAPTAIN III (POLICE DEPARTMENT)155966.02245131.88137811.380.0538909.28538909.282011San Francisco
23ALBERT PARDINICAPTAIN III (POLICE DEPARTMENT)212739.13106088.1816452.600.0335279.91335279.912011San Francisco
34CHRISTOPHER CHONGWIRE ROPE CABLE MAINTENANCE MECHANIC77916.0056120.71198306.900.0332343.61332343.612011San Francisco
45PATRICK GARDNERDEPUTY CHIEF OF DEPARTMENT,(FIRE DEPARTMENT)134401.609737.00182234.590.0326373.19326373.192011San Francisco
56DAVID SULLIVANASSISTANT DEPUTY CHIEF II118602.008601.00189082.740.0316285.74316285.742011San Francisco
67ALSON LEEBATTALION CHIEF, (FIRE DEPARTMENT)92492.0189062.90134426.140.0315981.05315981.052011San Francisco
78DAVID KUSHNERDEPUTY DIRECTOR OF INVESTMENTS256576.960.0051322.500.0307899.46307899.462011San Francisco
89MICHAEL MORRISBATTALION CHIEF, (FIRE DEPARTMENT)176932.6486362.6840132.230.0303427.55303427.552011San Francisco
910JOANNE HAYES-WHITECHIEF OF DEPARTMENT, (FIRE DEPARTMENT)285262.000.0017115.730.0302377.73302377.732011San Francisco

¿Cual es la nueva información del dataframe?

# Copie el código aca
salarios.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 148654 entries, 0 to 148653
Data columns (total 11 columns):
 #   Column            Non-Null Count   Dtype
---  ------            --------------   -----
 0   Id                148654 non-null  int64
 1   EmployeeName      148654 non-null  object
 2   JobTitle          148654 non-null  object
 3   BasePay           148045 non-null  float64
 4   OvertimePay       148650 non-null  float64
 5   OtherPay          148650 non-null  float64
 6   Benefits          148654 non-null  float64
 7   TotalPay          148654 non-null  float64
 8   TotalPayBenefits  148654 non-null  float64
 9   Year              148654 non-null  int64
 10  Agency            148654 non-null  object
dtypes: float64(6), int64(2), object(3)
memory usage: 12.5+ MB

Cuantos valores unicos hay en las columnas categoricas?

# Copie el código aca
salarios[["EmployeeName", "JobTitle", "Agency"]].nunique()
EmployeeName    110811
JobTitle          2159
Agency               1
dtype: int64
  • la columna Agency solamente tiene un valor unico, entonces no aporta informacion, por lo tanto se puede eliminar

Elimine la columna Agency del dataframe

# Copie el código aca
salarios.drop(columns=["Agency"], inplace=True)

Cual es el promedio de BasePay ?

# Copie el código aca
salarios["BasePay"].mean()
66325.4488404877

Cual es la cantidad mas alta de OvertimePay en el dataset ?

# Copie el código aca
salarios["OvertimePay"].max()
245131.88

Realice una descripcion estadistica de las columnas numericas?

# Copie el código aca
salarios.describe()

IdBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYear
count148654.000000148045.000000148650.000000148650.000000148654.000000148654.000000148654.000000148654.000000
mean74327.50000066325.4488405066.0598863648.76729718924.23283974768.32197293692.5548112012.522643
std42912.85779542764.63549511454.3805598056.60186617165.27949550517.00527462793.5334831.117538
min1.000000-166.010000-0.010000-7058.590000-33.890000-618.130000-618.1300002011.000000
25%37164.25000033588.2000000.0000000.0000000.00000036168.99500044065.6500002012.000000
50%74327.50000065007.4500000.000000811.27000023214.02000071426.61000092404.0900002013.000000
75%111490.75000094691.0500004658.1750004236.06500033468.980000105839.135000132876.4500002014.000000
max148654.000000319275.010000245131.880000400184.25000096570.660000567595.430000567595.4300002014.000000

En este dataset las variables Id y Year representan variables categorica, convertir estas columnas a su formato correcto

# Copie el código aca
# convertir las columnas Id y Year en categoricas ordinales
salarios["Id"] = salarios["Id"].astype("category")
salarios["Year"] = salarios["Year"].astype("category")

la variable Year es categorica ordinal, primero detecte cuales son los valores unicos que tiene la columna

# Copie el código aca
salarios["Year"].unique()
[2011, 2012, 2013, 2014]
Categories (4, int64): [2011, 2012, 2013, 2014]

Apartir de la información anterior convierta la columna Year en variable categorica ordinal y visualice la columna

# Copie el código aca
salarios["Year"] = salarios["Year"].cat.set_categories(
    [2011, 2012, 2013, 2014], ordered=True
)
salarios["Year"]
0         2011
1         2011
2         2011
3         2011
4         2011
          ...
148649    2014
148650    2014
148651    2014
148652    2014
148653    2014
Name: Year, Length: 148654, dtype: category
Categories (4, int64): [2011 < 2012 < 2013 < 2014]

Realice nuevamente una descripcion estadistica de las columnas numericas?

# Copie el código aca
salarios.describe()

BasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefits
count148045.000000148650.000000148650.000000148654.000000148654.000000148654.000000
mean66325.4488405066.0598863648.76729718924.23283974768.32197293692.554811
std42764.63549511454.3805598056.60186617165.27949550517.00527462793.533483
min-166.010000-0.010000-7058.590000-33.890000-618.130000-618.130000
25%33588.2000000.0000000.0000000.00000036168.99500044065.650000
50%65007.4500000.000000811.27000023214.02000071426.61000092404.090000
75%94691.0500004658.1750004236.06500033468.980000105839.135000132876.450000
max319275.010000245131.880000400184.25000096570.660000567595.430000567595.430000

¿Cuál es el título de trabajo de JOSEPH DRISCOLL? Nota: Utilice mayúsculas, de lo contrario, puede obtener una respuesta que no coincida.

# Copie el código aca
salarios[salarios["EmployeeName"] == "JOSEPH DRISCOLL"]["JobTitle"]
24    CAPTAIN, FIRE SUPPRESSION
Name: JobTitle, dtype: object

¿Cuanto gana JOSEPH DRISCOLL (incluyendo beneficios)?

# Copie el código aca
salarios[salarios["EmployeeName"] == "JOSEPH DRISCOLL"]["TotalPayBenefits"]
24    270324.91
Name: TotalPayBenefits, dtype: float64

¿Cual es el nombre de la persona con mejor pago (incluyendo beneficios)?

# Copie el código aca
salarios[salarios["TotalPayBenefits"] == salarios["TotalPayBenefits"].max()]

IdEmployeeNameJobTitleBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYear
01NATHANIEL FORDGENERAL MANAGER-METROPOLITAN TRANSIT AUTHORITY167411.180.0400184.250.0567595.43567595.432011

¿Cual es el nombre de la persona peor paga (incluyendo beneficios)? ¿Notan algo extraño sobre cuánto le pagan?

# Copie el código aca
salarios[salarios["TotalPayBenefits"] == salarios["TotalPayBenefits"].min()]

IdEmployeeNameJobTitleBasePayOvertimePayOtherPayBenefitsTotalPayTotalPayBenefitsYear
148653148654Joe LopezCounselor, Log Cabin Ranch0.00.0-618.130.0-618.13-618.132014

Cuantos registros tienen un valor de TotalPayBeneficts menor que cero

# Copie el código aca
# el numero de filas donde el valor de TotalPayBenefits sea menor a 0
salarios[salarios["TotalPayBenefits"] < 0].shape[0]
4

¿Cual es el promedio (mean) BasePay de todos los empleados por año? los años van entre (2011-2014)? (Tip: Usar groupby)

# Copie el código aca
salarios.groupby("Year")["BasePay"].mean()
Year
2011    63595.956517
2012    65436.406857
2013    69630.030216
2014    66564.421924
Name: BasePay, dtype: float64

¿Cuantos titulos de trabajos (JobTitle) unicos existen?

# Copie el código aca
salarios["JobTitle"].nunique()
2159

¿Cuales son los 5 trabajos mas comunes?

# Copie el código aca
salarios["JobTitle"].value_counts().head(5)
Transit Operator                7036
Special Nurse                   4389
Registered Nurse                3736
Public Svc Aide-Public Works    2518
Police Officer 3                2421
Name: JobTitle, dtype: int64

¿Cuántos puestos de trabajo Unicos existieron en 2013? (Ejemplo, los títulos de trabajo con solo una ocurrencia en 2013?)

# Copie el código aca
# Se recomienda usar la variable YEAR_TO_COMPARE para hacer la comparacion
# para mejorar la legibilidad y el mantenimiento del código

YEAR_TO_COMPARE = 2013
sum(salarios[salarios["Year"] == YEAR_TO_COMPARE]["JobTitle"].value_counts() == 1)
202

¿Cuántas personas tienen la palabra Chief en el título de su trabajo? Apoyese en los métodos para manipular strings y en el método .apply()

# Copie el código aca

Una forma simple seria:

def chief_string(title):
    if "chief" in title.lower():
        return True
    else:
        return False

sum(salarios["JobTitle"].apply(lambda x: chief_string(x)))

Este código es valido, se recomienda hacer el código mas simple y agregar typing y documentación, por ejemplo asi:

def chief_string(title: str) -> bool:
    """
    Responde con True si la palabra "chief" esta en el titulo del trabajo,
    en caso contrario responde False

    Parameters:
    title : str : el titulo del trabajo

    Returns:
    bool :  True si la palabra "chief" esta en el titulo del trabajo,
            False en caso contrario
    """
    return "chief" in title.lower()


sum(salarios["JobTitle"].apply(lambda x: chief_string(x)))
627

Bono: ¿Existe una correlación entre la longitud del nombre del Título del trabajo y el Salario?

crea una nueva columna donde se guarde la longitud del titulo del trabajo. tip: usar el método .apply()

# Copie el código aca
salarios["title_len"] = salarios["JobTitle"].apply(len)
salarios["title_len"]
0         46
1         31
2         31
3         36
4         44
          ..
148649     9
148650    12
148651    12
148652    12
148653    26
Name: title_len, Length: 148654, dtype: int64

Utilice el método .corr() de Pandas para calcular la correlacion

# Copie el código aca
salarios[["title_len", "TotalPayBenefits"]].corr()

title_lenTotalPayBenefits
title_len1.000000-0.036878
TotalPayBenefits-0.0368781.000000