Comparando dos columnas de un csv y generando una relación de similitud de cadenas en otro csv

Soy muy nuevo en la progtwigción de python. Estoy intentando tomar un archivo csv que tiene dos columnas de valores de cadena y quiero comparar la proporción de similitud de la cadena entre ambas columnas. Luego quiero tomar los valores y dar salida a la relación en otro archivo.

El csv puede verse así:

Column 1|Column 2 tomato|tomatoe potato|potatao apple|appel 

Quiero que el archivo de salida muestre para cada fila, qué tan similar es la cadena en la Columna 1 a la Columna 2. Estoy usando difflib para generar el puntaje de relación.

Este es el código que tengo hasta ahora:

 import csv import difflib f = open('test.csv') csf_f = csv.reader(f) row_a = [] row_b = [] for row in csf_f: row_a.append(row[0]) row_b.append(row[1]) a = row_a b = row_b def similar(a, b): return difflib.SequenceMatcher(a, b).ratio() match_ratio = similar(a, b) match_list = [] for row in match_ratio: match_list.append(row) with open("output.csv", "wb") as f: writer = csv.writer(f, delimiter=',') writer.writerows(match_list) f.close() 

Me sale el error:

 Traceback (most recent call last): File "comparison.py", line 24, in  for row in match_ratio: TypeError: 'float' object is not iterable 

Siento que no estoy importando la lista de columnas correctamente y ejecutándola contra la función de secuenciador.

Aquí hay otra manera de hacer esto usando pandas :

Considera que tus datos csv son así:

 Column 1,Column 2 tomato,tomatoe potato,potatao apple,appel 

CÓDIGO

 import pandas as pd import difflib as diff #Read the CSV df = pd.read_csv('datac.csv') #Create a new column 'diff' and get the result of comparision to it df['diff'] = df.apply(lambda x: diff.SequenceMatcher(None, x[0].strip(), x[1].strip()).ratio(), axis=1) #Save the dataframe to CSV and you could also save it in other formats like excel, html etc df.to_csv('outdata.csv',index=False) 

Resultado

 Column 1,Column 2 ,diff tomato,tomatoe ,0.923076923077 potato,potatao ,0.923076923077 apple,appel ,0.8 

El bucle for que estás configurando aquí espera algo como una matriz donde tienes match_ratio , y a juzgar por el error que estás obteniendo, eso no es lo que tienes. Parece que te estás perdiendo el primer argumento para difflib.SequenceMatcher , que probablemente debería ser None . Consulte 6.3.1 aquí: https://docs.python.org/3/library/difflib.html

Sin ese primer argumento especificado, creo que estás recuperando 0.0 de difflib.SequenceMatcher y luego intentas correr la ratio de eso. Incluso si corriges tu llamada de SequenceMatcher , creo que todavía estarás intentando iterar en un solo valor flotante que la ratio está devolviendo. Creo que necesitas llamar a SequenceMatcher dentro del bucle para cada conjunto de valores que estás comparando.

Entonces terminaría con una llamada más como esta en su función: difflib.SequenceMatcher(None, a, b) . O si lo prefiere, ya que estos son argumentos con nombre, podría hacer algo como esto: difflib.SequenceMatcher(a=a, b=b) .

Su archivo de muestra parece que contiene tags de marcado. Suponiendo que realmente está leyendo un archivo CSV, el error que está obteniendo es porque match_ratio no es un tipo de datos iterable, es un número de punto flotante: el valor de retorno de su función: similar (). En su código, la llamada a la función debería estar contenida dentro de un bucle for para llamarla para cada par de cadenas a, b. Aquí hay un ejemplo de trabajo que creé que elimina lo explícito de los bucles y en su lugar usa una comprensión de lista:

 import csv from difflib import SequenceMatcher path_in = 'csv1.csv' path_out = 'csv2.csv' with open(path_in, 'r') as csv_file_in: csv_reader = csv.reader(csv_file_in) col_headers = csv_reader.next() for row in csv_reader: results = [[row[0], row[1], SequenceMatcher(None, row[0], row[1]).ratio()] for row in csv_reader] with open(path_out, 'wb') as csv_file_out: col_headers.append('Ratio') out_rows = [col_headers] + results writer = csv.writer(csv_file_out, delimiter=',') writer.writerows(out_rows) 

Además del error que recibió, es posible que también haya tenido un problema al crear una instancia del objeto SequenceMatcher: su primer parámetro no se especificó en su código. Puede encontrar más en la lista de comprensión y SequenceMatcher en los documentos de Python. Buena suerte en tu futura encoding de Python.

Recibes ese error porque los registros fila [0] o fila [1] contienen muy probablemente valores de NaN. Intente forzarlos a encadenar primero haciendo str (fila [0]) y str (fila [1])

Recibirá el error porque está ejecutando SequenceMatcher en la lista de cadenas, en lugar de en las mismas cadenas. Cuando haces esto, recuperas un solo valor flotante, en lugar de la lista de valores de ración que creo que estabas esperando.

Si entiendo lo que está tratando de hacer, entonces no necesita leer primero las filas. Simplemente puede encontrar la relación de diferencias a medida que recorre las filas.

 import csv import difflib match_list = [] with open('test.csv') as f: csv_f = csv.reader(f) for row in csv_f: match_list.append([difflib.SequenceMatcher(a=row[0], b=row[1]).ratio()]) with open('output.csv', 'w') as f: writer = csv.writer(f, delimiter=',') writer.writerows(match_list)