2.2. Tratamiento de valores duplicados#

Introducción#

La redundancia de datos se refiere a datos que se repiten en forma exacta, o parcialmente, pero tienen el mismo significado o representan la misma realidad. Además del problema de ocupar espacio innecesario, es muy probale que se generen inconsistencias debido a ella. Esto puede causar errores al realizar la analítica.

Diferencia entre redundancia e inconsistencia#

Vamos a ver un ejemplo de un dataframe que tenga redundacia o datos repetidos para ver las diferencias entre tener redundancias y/o inconsistencias.

Creamos un dataframe con datos de clientes que compran en un kiosko:

import pandas as pd

# Dataset con datos redundantes
df_redundante = pd.DataFrame({
    'id_cliente': [1, 2, 3, 3, 2, 3, 4],
    'nombre': ['Susana', 'Oscar', 'Elena', 'Elena', 'Oscar', 'Elena', 'Lucila'],
    'apellido': ['Horia','Acol',  'Morado', 'Morado','Acol','Morado', 'Nave'],
    'ciudad': ['Neuquén', 'Rosario', 'Córdoba', 'Córdoba', 'Rosario', 'Córdoba', 'Plottier'],
    'producto': ['Palitos de la Selva',  'Chupetín Pico Dulce', 'Rocklets', 'Alfajor Jorgito', 'Sugus', 'Tubby 4', 'Block'],
    'precio': [100, 200, 150, 300, 120, 80, 230]
})

df_redundante
id_cliente nombre apellido ciudad producto precio
0 1 Susana Horia Neuquén Palitos de la Selva 100
1 2 Oscar Acol Rosario Chupetín Pico Dulce 200
2 3 Elena Morado Córdoba Rocklets 150
3 3 Elena Morado Córdoba Alfajor Jorgito 300
4 2 Oscar Acol Rosario Sugus 120
5 3 Elena Morado Córdoba Tubby 4 80
6 4 Lucila Nave Plottier Block 230

Podemos observar que hay mucha redundancia ya que las filas indexadas 1 y 4 son exactamente las mismas, y las filas 2, 3 y 5 también. Sin embargo esa redundancia hasta el momento no genera inconsistencias, ya que son iguales en todas las filas.

Entonces, cuándo hay incosistencias?

Vamos a agregar una fila al dataframe df_redundante que genere una inconsistencia:

# agrego la fila al final con .loc
df_redundante.loc[len(df_redundante)]=[4, 'Lucila', 'Nave', 'Neuquén', 'Flynn Paff', 123]
df_redundante
id_cliente nombre apellido ciudad producto precio
0 1 Susana Horia Neuquén Palitos de la Selva 100
1 2 Oscar Acol Rosario Chupetín Pico Dulce 200
2 3 Elena Morado Córdoba Rocklets 150
3 3 Elena Morado Córdoba Alfajor Jorgito 300
4 2 Oscar Acol Rosario Sugus 120
5 3 Elena Morado Córdoba Tubby 4 80
6 4 Lucila Nave Plottier Block 230
7 4 Lucila Nave Neuquén Flynn Paff 123

Ahora si vemos como al agregar Lucila Nave en el índice 7 se genera una inconsistencia debido a la redundancia, Lucila vive en Plottier o en Neuquén?. Al mismo tiempo si usamos los datos asi para la analítica tenemos una misma persona que vive en dos lugares al mismo tiempo y esto puede ser contado 2 veces.

Duplicados en Pandas#

De esta forma, generalmente es necesario eliminar la redundancia, que en Pandas se traduce como eliminar elementos duplicados.

Manejo de Duplicados en Pandas

Pandas posee algunos métodos específicos para analizar duplicados (que también existen los mismos para NumPy). Son:

  • df.duplicated(): devuelve series booleanas que indican las filas duplicadas. Posee como parámetro:

    • subset = []: en donde se pueden indicar las columnas a identificar

    • keep para determinar cuales duplicados marcar:

      • keep = 'first': marca los duplicados como True, excepto la primera ocurrencia. Es el default

      • keep ='last': marca los duplicados como True, excepto la última ocurrencia

      • keep =False: marca todos los duplicados como True

La información completa esta en pandas.DataFrame.duplicated

  • df.drop_duplicates(): devuelve un dataframe con los valores duplicados eliminados. Tiene los mismos parámetros subset y keep y agrega el ignore_index (predeterminado False), el cual si es True los ejes (axis) se etiquetarán con 0, 1, …, n-1.

La información completa esta en pandas.DataFrame.drop_duplicates

Ejemplos de uso de df.duplicated()#

Utilizando el dataframe df_redundante vamos a probar el uso del método df.duplicated().

Volvemos a ver que tenia el dataframe:

df_redundante
id_cliente nombre apellido ciudad producto precio
0 1 Susana Horia Neuquén Palitos de la Selva 100
1 2 Oscar Acol Rosario Chupetín Pico Dulce 200
2 3 Elena Morado Córdoba Rocklets 150
3 3 Elena Morado Córdoba Alfajor Jorgito 300
4 2 Oscar Acol Rosario Sugus 120
5 3 Elena Morado Córdoba Tubby 4 80
6 4 Lucila Nave Plottier Block 230
7 4 Lucila Nave Neuquén Flynn Paff 123

Ahora aplicamos el método a todo df_redundante:

# pregunto que filas estan duplicadas, y aquellas que lo estan, devuelva True
df_redundante.duplicated(keep = False)
0    False
1    False
2    False
3    False
4    False
5    False
6    False
7    False
dtype: bool

Como vemos ninguna fila estaba duplicada (devolvió todo False), esto es cierto ya que ninguna fila se repite por completo.

Vamos a probar con algunas columnas nada mas:

# pregunto si las columnas id_cliente y nombre tienen duplicados, 
#y aquellas que lo estan, devuelva True
df_redundante.duplicated(['id_cliente', 'nombre'], keep = False)
0    False
1     True
2     True
3     True
4     True
5     True
6     True
7     True
dtype: bool

La única fila que no posee duplicados es la primera, indexada con 0 (Susana Horia).

Ahora podemos probar con el valor keep = 'first' para que marque True a los duplicados excepto la primera vez que aparece.

Lo hacemos para la columna ciudad:

# pregunto si la columna ciudad tiene duplicados, 
#y marque True desde la 2da ocurrencia
df_redundante.duplicated(['ciudad'], keep = 'first')
0    False
1    False
2    False
3     True
4     True
5     True
6    False
7     True
dtype: bool

Otro método que podemos utilizar para ver valores duplicados es value_counts().

Método value_counts()

El método value_counts() cuenta la frecuencia de ocurrencias de cada valor en un dataframe o series. Algunos de sus parámetros son:

  • normalize=True que devuelve proporciones en lugar de la cantidad

  • sort=False para no ordenar los resultados

  • ascending=True para ordenar de menor a mayor

  • dropna=False para que incluya los NaN cuando cuenta

Vemos algunos ejemplos de value_counts():

# en proporcion, cantidad de iguales para nombre y apellido
df_redundante[['nombre', 'apellido']].value_counts(normalize=True)
nombre  apellido
Elena   Morado      0.375
Lucila  Nave        0.250
Oscar   Acol        0.250
Susana  Horia       0.125
Name: proportion, dtype: float64
# en cantidad,  ordenado
df_redundante[['nombre', 'apellido']].value_counts(ascending=True)
nombre  apellido
Susana  Horia       1
Lucila  Nave        2
Oscar   Acol        2
Elena   Morado      3
Name: count, dtype: int64

Ejemplos de uso de df.drop_duplicates()#

El método df.drop_duplicates() permite eliminar duplicados devolviendo un nuevo dataframe único.

Probamos el método en df_redundante:

# aplicamos drop_duplicates para eliminar filas duplicadas
# en todo df_redundante
df_redundante.drop_duplicates()
id_cliente nombre apellido ciudad producto precio
0 1 Susana Horia Neuquén Palitos de la Selva 100
1 2 Oscar Acol Rosario Chupetín Pico Dulce 200
2 3 Elena Morado Córdoba Rocklets 150
3 3 Elena Morado Córdoba Alfajor Jorgito 300
4 2 Oscar Acol Rosario Sugus 120
5 3 Elena Morado Córdoba Tubby 4 80
6 4 Lucila Nave Plottier Block 230
7 4 Lucila Nave Neuquén Flynn Paff 123

Como vimos no se modificó nada, porque ninguna fila estaba duplicada en forma completa.

Vamos a eliminar las filas que contengan duplicados en nombre y apellido:

# borrar filas, donde nombre y apellido sean redundantes
df_sin_redundantes = df_redundante.drop_duplicates(['nombre', 'apellido'])
df_sin_redundantes
id_cliente nombre apellido ciudad producto precio
0 1 Susana Horia Neuquén Palitos de la Selva 100
1 2 Oscar Acol Rosario Chupetín Pico Dulce 200
2 3 Elena Morado Córdoba Rocklets 150
6 4 Lucila Nave Plottier Block 230

Vamos a crear un nuevo dataframe que contenga solo el nombre, apellido y ciudad de df_redundante:

# creamos un nuevo df con solo nombre, apellido y ciudad
df_redundante_chico = df_redundante[['nombre', 'apellido', 'ciudad']]
df_redundante_chico
nombre apellido ciudad
0 Susana Horia Neuquén
1 Oscar Acol Rosario
2 Elena Morado Córdoba
3 Elena Morado Córdoba
4 Oscar Acol Rosario
5 Elena Morado Córdoba
6 Lucila Nave Plottier
7 Lucila Nave Neuquén

y ahora si vamos a aplicar .drop_duplicates() a todo el `dataframe:

df_redundante_chico.drop_duplicates()
nombre apellido ciudad
0 Susana Horia Neuquén
1 Oscar Acol Rosario
2 Elena Morado Córdoba
6 Lucila Nave Plottier
7 Lucila Nave Neuquén