Tiempo estimado de lectura: 5 minutos
En nuestro anterior post sobre cómo comparar archivos CSV para encontrar diferencias, mostramos cómo se podían ver las diferencias, pero ¿qué pasa si quieres ver si un registro coincide al 100% o no?
Aquí vamos a utilizar SequenceMatcher que es una clase de python que permite comparar archivos y devolver si coinciden en un porcentaje.
Veamos el código
Importar declaraciones y leer los archivos CSV. Aquí hacemos lo habitual de importar las bibliotecas que necesitamos y leer los dos archivos CSV que utilizamos:
Tenga en cuenta que aquí también configuramos los ajustes del marco de datos, para que podamos ver el marco de datos correctamente. Ver más abajo.
import pandas as pd
import numpy as np
import math
from difflib import SequenceMatcher
pd.set_option('max_columns', None)
pd.set_option('display.width', None)
#Read in the CSV files
df1 = pd.read_csv('CSV1.csv')
df2 = pd.read_csv('CSV2.csv')
Los dos archivos CSV tienen el siguiente aspecto:
CSV1
CSV2
A continuación, vamos a crear un array. La creación de un array permite completar la comparación, ya que crea índices, y se pueden comparar los índices de cada array y luego calcular la diferencia porcentual.
#Create an array for both dataframes
array1 = np.array(df1)
array2 = np.array(df2)
Nuestro siguiente paso es transferir las matrices a un marco de datos, cambiar todos los valores enteros a una cadena, y luego unir ambos marcos de datos en uno solo.
En este caso, el cambio de valores a una cadena permite iterarsobre esos valores, de lo contrario, obtendrá un error " TypeError: 'int' object is not iterable"
#Transfer the arrays to a dataframe
df_CSV_1 = pd.DataFrame(array1, columns=['No1','Film1','Year1','Length1'])
df_CSV_2 = pd.DataFrame(array2, columns=['No2','Film2','Year2','Length2'])
#Change all the values to a string, as numbers cannot be iterated over.
df_CSV_1['Year1'] = df_CSV_1['Year1'].astype('str')
df_CSV_2['Year2'] = df_CSV_2['Year2'].astype('str')
df_CSV_1['Length1'] = df_CSV_1['Length1'].astype('str')
df_CSV_2['Length2'] = df_CSV_2['Length2'].astype('str')
#join the dataframes
df = pd.concat([df_CSV_1,df_CSV_2], axis=1)
Ahora pasamos a la parte principal del programa, que nos da las respuestas que necesitamos. Aquí creamos una función que hace los cálculos por nosotros:
#Create a function to calculate the differences and show as a ratio.
def create_ratio(df, columna, columnb):
return SequenceMatcher(None,df[columna],df[columnb]).ratio()
A continuación, calculamos las diferencias y formateamos el resultado
#Here we use apply which will pull in the data that needs to be passed to the fuction above.
df['Film_comp'] = df.apply(create_ratio,args=('Film1','Film2'),axis=1)
df['Year_comp'] = df.apply(create_ratio,args=('Year1','Year2'),axis=1)
df['Length_comp'] = df.apply(create_ratio,args=('Length1','Length2'),axis=1)
#This creates the values we are looking for
df['Film_comp'] = round(df['Film_comp'].astype('float'),2)*100
df['Year_comp'] = round(df['Year_comp'].astype('float'),2)*100
df['Length_comp'] = round(df['Length_comp'].astype('float'),2)*100
#this removes the decimal point that is added as a result of using the datatype 'Float'
df['Film_comp'] = df['Film_comp'].astype('int')
df['Year_comp'] = df['Year_comp'].astype('int')
df['Length_comp'] = df['Length_comp'].astype('int')
#Print the output
print(df)
Y el resultado final tiene este aspecto:
Una explicación de la salida
Como se puede observar, las tres últimas columnas son los porcentajes de coincidencia obtenidos, siendo el 100 una coincidencia exacta.
Para el valor de índice 1 hay Joker en el primer archivo, pero Jokers está en el segundo archivo.
El ratio se calcula de la siguiente manera:
El comodín tiene una longitud de 5, los comodines tienen una longitud de 6 = 11 caracteres de longitud
Así que la lógica mira la secuencia, iterando a través de la secuencia puede ver que los primeros 10 caracteres están en el mismo orden, pero el 11º carácter no lo está, como resultado, calcula lo siguiente:
(10/11) * 100 = 90.90
Por último, la función de redondeo establece el valor que buscamos en 91.
En la misma línea, compararemos el año:
2019 y 2008 son un total de ocho caracteres.
En la secuencia, los dos primeros de cada uno coinciden, y como también se encuentran, nos dan cuatro, y la proporción es la siguiente:
4/8 *100 = 50
Para el Índice 20 también comparamos el nombre de la película, en total son 17 caracteres, pero el programa ignora lo que llaman basura, así que el espacio no se incluye, por esa razón el ratio sólo calcula sobre dieciséis caracteres.
Para entenderlo mejor, he recopilado lo siguiente:
Índice 1 | Índice 1 | ||||||
2019 | 2008 | 8 | Joker | Jokers | 11 | ||
2 | Punto correcto | 1 | J | Punto correcto | 1 | ||
0 | Punto correcto | 1 | o | Punto correcto | 1 | ||
1 | Punto incorrecto | 0 | K | Punto correcto | 1 | ||
9 | Punto incorrecto | 0 | e | Punto correcto | 1 | ||
r | Punto correcto | 1 | |||||
2 | Encontrado | 1 | J | Encontrado | 1 | ||
0 | Encontrado | 1 | o | Encontrado | 1 | ||
1 | Encontrado | 0 | K | Encontrado | 1 | ||
9 | Encontrado | 0 | e | Encontrado | 1 | ||
r | Encontrado | 1 | |||||
Total en comparación | 8 | Total en comparación | 11 | ||||
Ratio | 0.50 | Ratio | 0.91 | ||||
Índice 20 | |||||||
La suciedad | La suciedad | 16 | |||||
T | Punto correcto | 1 | |||||
H | Punto correcto | 1 | |||||
E | Punto correcto | 1 | |||||
Punto correcto | 1 | ||||||
T | Encontrado | 1 | |||||
H | Encontrado | 1 | |||||
E | Encontrado | 1 | |||||
D | Punto correcto | 1 | |||||
I | Punto correcto | 1 | |||||
R | Punto correcto | 1 | |||||
T | Punto correcto | 1 | |||||
D | Encontrado | 1 | |||||
I | Encontrado | 1 | |||||
R | Encontrado | 1 | |||||
T | Encontrado | 1 | |||||
Total en comparación | 16 | ||||||
Ratio | 0.94 |