在 pandas 中使用 Levenshtein 比较字符串时提高 Python 代码性能
Improving Python code performance when comparing strings using Levenshtein in pandas
我有这段代码可以正常运行并产生我正在寻找的结果:
from thefuzz import fuzz
import pandas as pd
df = pd.read_csv('/folder/folder/2011_05-rc.csv', dtype=str, lineterminator='\n')
df_compare = pd.DataFrame(
df['text'].apply(lambda row: [fuzz.partial_ratio(x, row) for x in df['text']]).to_list())
for i in df_compare.index:
for j in df_compare.columns[i:]:
df_compare.iloc[i, j] = 0
df[df_compare.max(axis=1) < 75].to_csv('/folder/folder/2011_05-ready.csv', index=False)
print('Done did')
但是,由于字符串比较是一项成本非常高的操作,因此该脚本非常慢,并且只能处理 5000-7000 行的相对较小的 CSV 文件。任何大的(超过 12MB)都需要几天才能抛出与内存相关的错误消息。我尝试 运行 在 32 个内核和 32 GB 内存上使用 modin,但它没有改变任何东西,我最终得到了相同的结果。
import glob
from thefuzz import fuzz
import modin.pandas as pd
files = glob.glob('/folder/folder/2013/*.csv')
for file in files:
df = pd.read_csv(file, dtype=str, lineterminator='\n')
f_compare = pd.DataFrame(
df['text'].apply(lambda row: [fuzz.partial_ratio(x, row) for x in df['text']]).to_list())
for i in df_compare.index:
for j in df_compare.columns[i:]:
df_compare.iloc[i, j] = 0
df[df_compare.max(axis=1) < 75].to_csv(f'{file[:-4]}-done.csv', index=False)
print(f'{file} has been done')
它作为一项单独的工作处理较小的文件 运行,但文件太多而无法单独完成。有没有办法优化此代码或其他一些可能的解决方案?
数据是推文的集合,而只有一列被比较(大约 30 列)。它看起来像这样:
ID
Text
11213
I am going to the cinema
23213
Black is my favourite colour
35455
I am going to the cinema with you
421323
My friends think I am a good guy.
看来要求是将每个句子与其他句子进行比较。鉴于这里的整体方法,我认为没有一个好的答案。您正在查看 n^2 个比较。随着您的行数变大,整体处理要求会很快变成一个怪物。
为了弄清楚可行性,您可以 运行 一些较小的测试来计算该测试的 n^2 以获得每秒评估行数指标。然后为您要执行的大数据集计算 n^2,以了解所需的处理时间。那是假设您的内存可以处理它。也许已经完成了处理 n^2 问题的工作。可能想四处寻找类似的东西。
您所做的工作是您需要做的工作的两倍多。你将所有事物与所有事物进行两次比较,并与自身进行比较。但即便如此,当事情变大时,如果你只是进行组合,n(n-1)/2 仍然是巨大的。
我有这段代码可以正常运行并产生我正在寻找的结果:
from thefuzz import fuzz
import pandas as pd
df = pd.read_csv('/folder/folder/2011_05-rc.csv', dtype=str, lineterminator='\n')
df_compare = pd.DataFrame(
df['text'].apply(lambda row: [fuzz.partial_ratio(x, row) for x in df['text']]).to_list())
for i in df_compare.index:
for j in df_compare.columns[i:]:
df_compare.iloc[i, j] = 0
df[df_compare.max(axis=1) < 75].to_csv('/folder/folder/2011_05-ready.csv', index=False)
print('Done did')
但是,由于字符串比较是一项成本非常高的操作,因此该脚本非常慢,并且只能处理 5000-7000 行的相对较小的 CSV 文件。任何大的(超过 12MB)都需要几天才能抛出与内存相关的错误消息。我尝试 运行 在 32 个内核和 32 GB 内存上使用 modin,但它没有改变任何东西,我最终得到了相同的结果。
import glob
from thefuzz import fuzz
import modin.pandas as pd
files = glob.glob('/folder/folder/2013/*.csv')
for file in files:
df = pd.read_csv(file, dtype=str, lineterminator='\n')
f_compare = pd.DataFrame(
df['text'].apply(lambda row: [fuzz.partial_ratio(x, row) for x in df['text']]).to_list())
for i in df_compare.index:
for j in df_compare.columns[i:]:
df_compare.iloc[i, j] = 0
df[df_compare.max(axis=1) < 75].to_csv(f'{file[:-4]}-done.csv', index=False)
print(f'{file} has been done')
它作为一项单独的工作处理较小的文件 运行,但文件太多而无法单独完成。有没有办法优化此代码或其他一些可能的解决方案?
数据是推文的集合,而只有一列被比较(大约 30 列)。它看起来像这样:
ID | Text |
---|---|
11213 | I am going to the cinema |
23213 | Black is my favourite colour |
35455 | I am going to the cinema with you |
421323 | My friends think I am a good guy. |
看来要求是将每个句子与其他句子进行比较。鉴于这里的整体方法,我认为没有一个好的答案。您正在查看 n^2 个比较。随着您的行数变大,整体处理要求会很快变成一个怪物。
为了弄清楚可行性,您可以 运行 一些较小的测试来计算该测试的 n^2 以获得每秒评估行数指标。然后为您要执行的大数据集计算 n^2,以了解所需的处理时间。那是假设您的内存可以处理它。也许已经完成了处理 n^2 问题的工作。可能想四处寻找类似的东西。
您所做的工作是您需要做的工作的两倍多。你将所有事物与所有事物进行两次比较,并与自身进行比较。但即便如此,当事情变大时,如果你只是进行组合,n(n-1)/2 仍然是巨大的。