天天看點

拓展vlookup的difflib模糊比對

拓展vlookup的difflib模糊比對

  • ​​背景​​
  • ​​完整代碼​​
  • ​​代碼解讀​​
  • ​​錯誤代碼​​

背景

手裡頭有兩份excel資料,一份是大表,一份是小表。其中大表名為比對表機構.xlsx,有20000多個小區名稱和對應的租金坪效字段,小表名為待比對表.xlsx,隻有一部分小區名稱,現在要為小表中這些小區比對出租金坪效值。本來想用excel的vlookup()函數比對一番,發現比對效果不好,因為兩份資料來源不同,小區命名規則略有不同,最後隻比對出6層,有些因為小區一點點差别導緻比對補上,比如“中冶·尚城”,而大表裡面有一個“中冶尚城”,兩者差别僅僅存在中間一點,一個多了“·”,一個少了“·”,其實兩者在實際中是表示同一個小區,此時vlookup沒法比對,于是琢磨着用difflib子產品進行模糊的比對。

待比對裡面某小區名可能與大表裡面好幾個相似的小區名稱,其中vlookup隻能比對出完全一緻,此時,相似度為1,那現在把相似度設定低一點,比如0.8,此時“同仁小區”就能和大表裡面的“上海同仁小區”比對上了。通過調節相似來找出最比對的小區字段,然後給小表裡面所有小區名稱比對出大表裡面最相似的小區名稱,通過大表的小區名稱再來比對對應的租金坪效值。完整代碼如下

拓展vlookup的difflib模糊比對

完整代碼

# -*- coding: utf-8 -*-
"""
project_name:excel模糊比對
@author: 帥帥de三叔
Created on Wed Aug 21 13:12:09 2019
"""
import pandas as pd #資料分析子產品
import difflib #導入文本對比子產品
origin_data=pd.read_excel("比對表機構.xlsx",index_col='id') #讀取比對庫資料
target_data=pd.read_excel("待比對表.xlsx",index_col='id') #讀取待比對資料
pool_item=origin_data['key'] #比對庫
search_item=target_data['key'] #待比對目标
print(len(pool_item),len(search_item))

def get_closest(str,sequences): #定義擷取最近似函數,該函數實作從sequences找出與str最相近的字元串傳回,并給出相似度量
    result=difflib.get_close_matches(str,sequences,n=1,cutoff=0.3)[0] #get_close_matches傳回一個相似清單,并按照相似度排列,第一個為最佳比對
    ratio=difflib.SequenceMatcher(None,str,result).ratio() #計算str和result的相似度
    print(str,result,ratio) #測試比對
    return result,ratio

target=[] #用來存最佳比對字元串
ratios=[] #用來存放相似度
for item in search_item: #對待比對目标進行循環
    target.append(get_closest(item,pool_item)[0]) #追加最佳比對值
    ratios.append(get_closest(item,pool_item)[1]) #追加相似度
    
match={"原小區名":search_item,"比對小區名":target,"相似度":ratios} #字典化
match=pd.DataFrame(match) #資料框化
match.to_excel("比對結果_機構.xlsx") #儲存比對結果      

代碼解讀

主要用到difflib子產品,該子產品主要用來區分兩個文本的相似性,并給出文本的相似度量,具體實作過程定義了 get_closest() 函數,該函數調用了difflib.get_close_matches() 内置函數找出最佳比對小區名稱,并且調用difflib.SequenceMatcher(None,str,result).ratio() 函數給出衡量比對好壞的相似度。有了這兩個關鍵字段,最後和原小表裡面的小區名稱和比對出來的大表小區名稱以及相似度三個字段構成新的資料框,寫入到 “比對結果_機構.xlsx”,之後就可以用vlookup函數來做租金坪效比對了。

錯誤代碼

如果程式運作出現如下錯誤代碼,說明原資料裡面有空值,将其删除即可,或者用pandas 把空值填充。

File "D:\Python35\lib\difflib.py", line 726, in get_close_matches
    if s.real_quick_ratio() >= cutoff and \
  File "D:\Python35\lib\difflib.py", line 683, in real_quick_ratio
    la, lb = len(self.a), len(self.b)
TypeError: object of type 'float' has no len()