Tempo di lettura stimato: 5 minuti
Nel nostro post precedente su come confrontare i file CSV per le differenze abbiamo mostrato come puoi vedere le differenze, ma cosa succede se vuoi vedere se un record corrisponde al 100% o no?
Qui useremo SequenceMatcher che è una classe python che permette di confrontare i file e restituire se corrispondono in percentuale.
Vediamo il codice
Importare le dichiarazioni e leggere i file CSV. Qui facciamo il solito lavoro di importazione delle librerie di cui abbiamo bisogno e leggiamo i due file CSV che usiamo:
Notate che qui abbiamo anche impostato le impostazioni del data frame, in modo da poter vedere il data frame correttamente. Vedere più in basso.
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')
I due file CSV si presentano così:
CSV1
CSV2
Successivamente, creeremo una matrice. La creazione di una matrice permette di completare il confronto in quanto crea degli indici, e gli indici in ogni matrice possono essere confrontati e poi si può calcolare la differenza percentuale.
#Create an array for both dataframes
array1 = np.array(df1)
array2 = np.array(df2)
Il passo successivo è trasferire gli array in un frame di dati, cambiare tutti i valori interi in stringhe e quindi unire entrambi i frame di dati in uno solo.
In questo caso il cambiamento dei valori in una stringa permette di iterare quei valori, altrimenti si otterrà un errore " 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)
Passiamo ora alla parte principale del programma, che ci dà le risposte di cui abbiamo bisogno. Qui creiamo una funzione che fa i calcoli per noi:
#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()
Poi calcoliamo le differenze e formattiamo l'output
#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)
E l'output finale appare così:
Una spiegazione dell'uscita
Come si può notare, le ultime tre colonne sono le percentuali di corrispondenza ottenute, con 100 come corrispondenza esatta.
Per il valore dell'indice 1 c'è Joker nel primo file, ma Jokers è nel secondo file.
Il rapporto è calcolato come segue:
Joker è la lunghezza 5, Jokers è la lunghezza 6 = 11 caratteri in lunghezza
Quindi la logica guarda la sequenza, iterando attraverso la sequenza può vedere che i primi 10 caratteri sono nello stesso ordine, ma l'11° carattere non lo è, di conseguenza, calcola quanto segue:
(10/11) * 100 = 90.90
Infine, la funzione round imposta il valore che stiamo cercando a 91.
Sulla stessa linea, confronteremo l'anno:
Il 2019 e il 2008 sono un totale di otto caratteri.
Nella sequenza, i primi due di ciascuno corrispondono, e poiché si trovano anche loro, ne otteniamo quattro, e il rapporto è il seguente:
4/8 *100 = 50
Per l'indice 20 abbiamo anche confrontato il nome del film, in totale ci sono 17 caratteri, ma il programma ignora quello che chiamano spazzatura, quindi lo spazio non è incluso, per questo motivo il rapporto calcola solo oltre i sedici caratteri.
Per capire meglio questo ho compilato il seguente:
Indice 1 | Indice 1 | ||||||
2019 | 2008 | 8 | Joker | Jokers | 11 | ||
2 | Punto corretto | 1 | J | Punto corretto | 1 | ||
0 | Punto corretto | 1 | o | Punto corretto | 1 | ||
1 | Punto errato | 0 | K | Punto corretto | 1 | ||
9 | Punto errato | 0 | e | Punto corretto | 1 | ||
r | Punto corretto | 1 | |||||
2 | Trovato | 1 | J | Trovato | 1 | ||
0 | Trovato | 1 | o | Trovato | 1 | ||
1 | Trovato | 0 | K | Trovato | 1 | ||
9 | Trovato | 0 | e | Trovato | 1 | ||
r | Trovato | 1 | |||||
Totale a confronto | 8 | Totale a confronto | 11 | ||||
Rapporto | 0.50 | Rapporto | 0.91 | ||||
Indice 20 | |||||||
Lo sporco | Lo sporco | 16 | |||||
T | Punto corretto | 1 | |||||
H | Punto corretto | 1 | |||||
E | Punto corretto | 1 | |||||
Punto corretto | 1 | ||||||
T | Trovato | 1 | |||||
H | Trovato | 1 | |||||
E | Trovato | 1 | |||||
D | Punto corretto | 1 | |||||
I | Punto corretto | 1 | |||||
R | Punto corretto | 1 | |||||
T | Punto corretto | 1 | |||||
D | Trovato | 1 | |||||
I | Trovato | 1 | |||||
R | Trovato | 1 | |||||
T | Trovato | 1 | |||||
Totale a confronto | 16 | ||||||
Rapporto | 0.94 |