Python 基于模糊匹配的列表中值的查找与替换
我试图循环使用熊猫中某列的值,并更改所有类似的值,使它们协调一致。我首先将该列提取为一个列表,并希望对每一行进行循环,在找到类似的值时将其替换为类似的值,然后将列表放回dataframe中替换该列。例如,一个列,如:Python 基于模糊匹配的列表中值的查找与替换,python,pandas,dataframe,replace,fuzzywuzzy,Python,Pandas,Dataframe,Replace,Fuzzywuzzy,我试图循环使用熊猫中某列的值,并更改所有类似的值,使它们协调一致。我首先将该列提取为一个列表,并希望对每一行进行循环,在找到类似的值时将其替换为类似的值,然后将列表放回dataframe中替换该列。例如,一个列,如: Cool Awesome cool CoOl Awesum Awesome Mathss Math Maths Mathss 将成为: CoOl Awesome coOol CoOl Awesome Awesome Mathss Mathss Mathss Mathss 代码如
Cool
Awesome
cool
CoOl
Awesum
Awesome
Mathss
Math
Maths
Mathss
将成为:
CoOl
Awesome
coOol
CoOl
Awesome
Awesome
Mathss
Mathss
Mathss
Mathss
代码如下:
def matchbrands():
conn = sqlite3.connect('/Users/XXX/db.sqlite3')
c = conn.cursor()
matchbrands_df = pd.read_sql_query("SELECT * from removeduplicates", conn)
brands = [x for x in matchbrands_df['brand']]
i=1
for x in brands:
if fuzz.token_sort_ratio(x, brands[i]) > 85:
x = brands[i]
else:
i += 1
n = matchbrands_df.columns[7]
matchbrands_df.drop(n, axis=1, inplace=True)
matchbrands_df[n] = brands
matchbrands_df.to_csv('/Users/XXX/matchedbrands.csv')
matchbrands_df.to_sql('removeduplicates', conn, if_exists="replace")
但是,这根本不会更改列。我不知道为什么。任何帮助都将不胜感激您的代码毫无意义 第一:使用
x=…
您不能更改列表品牌上的值。您需要品牌[索引]=…
第二:它需要嵌套,以便
-循环将x
与品牌中的所有其他单词进行比较
for index, word in enumerate(brands):
for other in brands[index+1:]:
#print(word, other, fuzz.token_sort_ratio(word, other))
if fuzz.token_sort_ratio(word, other) > 85:
brands[index] = other
最小工作代码
import pandas as pd
import fuzzywuzzy.fuzz as fuzz
data = {'brands':
'''Cool
Awesome
cool
CoOl
Awesum
Awesome
Mathss
Math
Maths
Mathss'''.split('\n')
} # rows
df = pd.DataFrame(data)
print('--- before ---')
print(df)
brands = df['brands'].to_list()
print('--- changes ---')
for index, word in enumerate(brands):
#for other_index, other_word in enumerate(brands):
for other_index, other_word in enumerate(brands[index+1:], index+1):
#if word != other_word:
result = fuzz.token_sort_ratio(word, other_word)
if result > 85:
print(f'OK | {result:3} | {index:2} {word:7} -> {other_index:2} {other_word}')
elif result > 50:
print(f' | {result:3} | {index:2} {word:7} -> {other_index:2} {other_word}')
if result > 85:
brands[index] = other_word
#break
#word = other_word
df['brands'] = brands
print('--- after ---')
print(df)
结果:
--- before ---
brands
0 Cool
1 Awesome
2 cool
3 CoOl
4 Awesum
5 Awesome
6 Mathss
7 Math
8 Maths
9 Mathss
--- changes ---
OK | 100 | 0 Cool -> 2 cool
OK | 100 | 0 Cool -> 3 CoOl
| 77 | 1 Awesome -> 4 Awesum
OK | 100 | 1 Awesome -> 5 Awesome
OK | 100 | 2 cool -> 3 CoOl
| 77 | 4 Awesum -> 5 Awesome
| 80 | 6 Mathss -> 7 Math
OK | 91 | 6 Mathss -> 8 Maths
OK | 100 | 6 Mathss -> 9 Mathss
OK | 89 | 7 Math -> 8 Maths
| 80 | 7 Math -> 9 Mathss
OK | 91 | 8 Maths -> 9 Mathss
--- after ---
brands
0 CoOl
1 Awesome
2 CoOl
3 CoOl
4 Awesum
5 Awesome
6 Mathss
7 Maths
8 Mathss
9 Mathss
它不会将Awesum
更改为Awesome
,因为它得到77
它不会将Math
更改为maths
,因为它得到80
。但是对于数学
,它得到了89
如果在for
-循环中使用word=other\uword
,则它可以将Math
转换为Math
(89
),然后将Math
转换为Maths
(91
)。但这样一来,它可能会改变很多次,最后变成原来的单词,这个单词的值比85
小得多。您还可以为75
而不是85
获得预期结果
但是这种方法得到的最后一个单词的值是85,而不是最大的值,因此可能会有更好的匹配单词,并且不会使用它。使用break it获得第一个单词,使用>85
。也许它应该获取所有具有>85
的单词,并选择具有最大值的单词。它必须跳过相同但在不同行中的单词。但所有这些都会造成奇怪的情况
在代码注释中,我保留了其他修改意见
编辑:
与>75和颜色相同
上面的代码应该是一个最小的可复制示例。可能首先使用print()
检查变量中的内容。当启动x=…
不会更改品牌中的原始值时
-您必须使用索引并执行品牌[index]=brands[i]
。对于
,所有这些-循环看起来很奇怪,我不相信它是否真的能满足您的要求。您应该在此for
-循环中使用print()
,检查它的功能。对我来说,可能需要第二个循环才能正确执行,但我不知道如何使用fuzz.token\u sort\u ratio
。也许可以用.apply代替将列转换为list.shorter:brands=matchbrands\u df['brand'])。to\u list()
或brands=list(matchbrands\u df['brand'])
这太棒了,谢谢muchI想用df.apply(func)
但这只会减少
-loop`的外部,对于
-loop它仍然需要内部,对于其他索引,其他单词
内部func
顺便说一句:我对设置颜色的代码做了一些更改。并添加了打印('-')
。
import pandas as pd
import fuzzywuzzy.fuzz as fuzz
from colorama import Fore as FG, Back as BG, Style as ST
data = {'brands':
'''Cool
Awesome
cool
CoOl
Awesum
Awesome
Mathss
Math
Maths
Mathss'''.split('\n')
} # rows
df = pd.DataFrame(data)
print('--- before ---')
print(df)
brands = df['brands'].to_list()
print('--- changes ---')
for index, word in enumerate(brands):
print('-', index, '-')
#for other_index, other_word in enumerate(brands):
for other_index, other_word in enumerate(brands[index+1:], index+1):
#if word != other_word:
result = fuzz.token_sort_ratio(word, other_word)
if result > 85:
color = ST.BRIGHT + FG.GREEN
info = 'OK'
elif result > 75:
color = ST.BRIGHT + FG.YELLOW
info = ' ?'
elif result > 50:
color = ST.BRIGHT + FG.WHITE
info = ' '
else:
color = ST.BRIGHT + FG.RED
info = ' -'
print(f'{color}{info} | {result:3} | {index:2} {word:7} -> {other_index:2} {other_word}{ST.RESET_ALL}')
if result > 75:
brands[index] = other_word
#break
#word = other_word
df['brands'] = brands
print('--- after ---')
print(df)