Python 基于模糊匹配的列表中值的查找与替换

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 代码如

我试图循环使用熊猫中某列的值,并更改所有类似的值,使它们协调一致。我首先将该列提取为一个列表,并希望对每一行进行循环,在找到类似的值时将其替换为类似的值,然后将列表放回dataframe中替换该列。例如,一个列,如:

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)