【问题标题】:Comparing two columns of a csv and outputting string similarity ratio in another csv比较一个csv的两列并在另一个csv中输出字符串相似率
【发布时间】:2016-08-16 14:15:18
【问题描述】:

我对 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 函数运行它。

【问题讨论】:

    标签: python pandas csv difflib sequencematcher


    【解决方案1】:

    您收到该错误是因为记录 row[0] 或 row[1] 最有可能包含 NaN 值。 尝试通过创建 str(row[0]) 和 str(row[1])

    来强制他们先字符串

    【讨论】:

      【解决方案2】:

      这是使用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
      

      【讨论】:

      • 这非常有效。我需要更多地探索熊猫。谢谢!
      【解决方案3】:

      您的示例文件看起来包含标记标签。假设您实际上正在读取 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 文档中找到更多关于 list comprehensionsSequenceMatcher 的信息。祝你在未来的 Python 编码中好运。

      【讨论】:

        【解决方案4】:

        您收到错误是因为您在字符串列表上运行 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)
        

        【讨论】:

        • 哇,这比我的干净多了。我尝试运行此代码和示例 csv 文件并产生此错误: writer.writerows(match_list) _csv.Error: sequence expected
        • 对不起,我更新了我的帖子来解决这个问题。 writerows 期待一个可迭代的迭代,但我的解决方案是传递一个可迭代的浮点数。
        【解决方案5】:

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

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

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

        【讨论】:

        • 我还要补充一点,将row_arow_b 重命名为ab 中途真的很混乱。很容易忘记您在这里处理的是两个列表,而不是您可以比较的两个字符串值。
        • 啊,这很有意义。我明白你指的是什么。
        猜你喜欢
        • 2016-11-10
        • 2013-06-24
        • 1970-01-01
        • 2018-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        相关资源
        最近更新 更多