4

我对python编程很陌生。我正在尝试获取一个包含两列字符串值的 csv 文件,并希望比较两列之间字符串的相似度。然后我想取值并将比率输出到另一个文件中。

csv 可能如下所示:

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

我希望输出文件为每一行显示第 1 列中的字符串与第 2 列的相似程度。我正在使用 difflib 输出比率分数。

这是我到目前为止的代码:

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()

我得到错误:

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

我觉得我没有正确导入列列表并针对 sequencematcher 函数运行它。

4

5 回答 5

3

这是完成此操作的另一种方法pandas

考虑你的 csv 数据是这样的:

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

代码

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)

结果

Column 1,Column 2 ,diff
tomato,tomatoe ,0.923076923077
potato,potatao ,0.923076923077
apple,appel ,0.8
于 2016-04-23T06:13:23.763 回答
2

for您在此处设置的循环需要类似于您所拥有的数组match_ratio,并且根据您得到的错误判断,这不是您所拥有的。看起来您缺少 的第一个参数difflib.SequenceMatcher,它可能应该是None。请参阅此处的 6.3.1:https ://docs.python.org/3/library/difflib.html

如果没有指定第一个参数,我认为你会从中恢复过来0.0difflib.SequenceMatcher然后试图ratio摆脱它。即使您更正了SequenceMatcher调用,我认为您仍然会尝试迭代ratio返回的单个浮点值。我认为您需要SequenceMatcher在循环内为要比较的每组值调用。

所以你会在你的函数中得到一个更像这样的调用:difflib.SequenceMatcher(None, a, b). 或者,如果您愿意,因为这些是命名参数,您可以执行以下操作difflib.SequenceMatcher(a=a, b=b)

于 2016-04-22T20:21:07.410 回答
1

您的示例文件看起来包含标记标签。假设您实际上正在读取 CSV 文件,您得到的错误是因为 match_ratio 不是可迭代的数据类型,它是一个浮点数——函数的返回值:similar()。在您的代码中,函数调用必须包含在 for 循环中才能为每个 a、b 字符串对调用它。这是我创建的一个工作示例,它取消了显式 for 循环,而是使用列表推导:

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)

除了您收到的错误之外,您在实例化 SequenceMatcher 对象时可能还遇到了问题——您的代码中没有指定它的第一个参数。您可以在 Python 文档中找到有关列表推导SequenceMatcher的更多信息。祝你未来的 Python 编码好运。

于 2016-04-22T21:21:36.763 回答
1

您收到该错误是因为记录 row[0] 或 row[1] 最有可能包含 NaN 值。尝试通过制作 str(row[0]) 和 str(row[1]) 来强制他们先字符串

于 2017-05-16T02:05:19.673 回答
0

您收到错误是因为您在字符串列表上运行 SequenceMatcher,而不是在字符串本身上运行。当你这样做时,你会得到一个浮点值,而不是我认为你期望的配给值列表。

如果我了解您要执行的操作,则无需先阅读行。您可以在遍历行时简单地找到差异比率。

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)
于 2016-04-22T20:21:08.200 回答