1個好方案,幫你實現複雜資料來源中小區資訊的準確歸一化
閒魚技術-臨耕
背景
小區是租房業務中很重要的資訊,它能夠反映房源的位置和品質。對租客而言,能否瀏覽到準確的小區資訊是高效找房的關鍵。因此,收集和展示準確的小區資訊是提高使用者找房效率的重要方面。為了獲得全面的小區資訊,租房業務通常會依賴多種資料來源獲得小區資料,這些資料格式不一,資訊雜亂無章,含有很多冗餘資訊。為了提高找房效率,必須把同一個小區的不同資料聚合到一起並理清小區資訊之間的從屬關係。本文抓住小區的獨有特徵並利用相似度演算法,設計了一種基於文字匹配的方法來解決這個問題。
目標
現有的小區資料中重複小區很多,比如“福鼎家園”、“福鼎家園曉風苑”、“福鼎家園2幢3單元”、“西溪北苑西區”和“西溪北苑東區”等等。這些小區名雖然不完全一樣,但是其中一些表示的同一個小區或者同一小區的子小區,我們把這些小區名叫做同義小區,比如“福鼎家園”、“福鼎家園曉風苑”、“福鼎家園2幢3單元”。表示整個小區的是父小區,比如福鼎家園、西溪北苑。表示小區下面的部分割槽域的叫做子小區,比如福鼎家園曉風苑、西溪北苑東區。而像“福鼎家園2幢3單元”這樣的小區地址,稱為樓棟地址。
為了房源資訊搜尋和展示的準確與效率,我們需要把解析出每條小區資料對應的小區資訊,以及小區的層級關係,甚至補充一些小區資訊。具體來說,一是把現有小區統一到子小區:子小區是期、區、苑一級,比如‘福鼎家園曉風苑’,‘福鼎家園雨露苑’:1. 子小區是單元、棟、幢的上一級:像單元、棟、幢、xx號樓這樣的名稱,屬於小區樓棟;2. 每個子小區都有唯一的父小區,比如子小區“福鼎家園曉風苑”的父小區是“福鼎家園”;二是能夠補充父小區、子小區資訊:對於小區庫中不存在的父小區或者子小區資訊,可以補充進來;
思路
小區作為一個獨特的地址單位,有下面這些特徵:
- 子小區的父小區通常是多個子小區的最長公共字首:小區的命名是一個層級結構,同一個父小區的子小區通常具有相同的字首,這符合人對於位置的命名習慣;
- 子小區和小區樓棟的名稱有獨特的特徵:比如子小區大多符合這樣的模式:“PP[ww|xx|yy|zz]區”,“PP[ww|xx|yy]期”,“PP[ww|xx|yy]號”以及“PP[ww|xx|yy]座”等等。其中PP是公共字首,也就是確定的虛擬父小區名,ww表示數字,xx表示代表數字的漢字,yy表示大寫或者小寫字母,zz表示方位詞(比如東、西、南、北、東北、西北等)。而小區樓棟地址通常是下面的形式:“PP[ww|xx|yy]幢”,“PP[ww|xx|yy]樓”,“PP[ww|xx|yy]棟”,“PP[ww|xx|yy]單元”以及“PP[ww|xx|yy]號樓”等等
(PP是子小區名,ww,xx和yy代表的含義與上面一樣); - 小區作為一個相對小的地址單位,範圍是較小的,而且同一個小區的不同子小區的距離不可能太遠;
- 同一個小區的不同子小區名稱通常非常相似。
基於上述觀察,我們提出一種以字首匹配和文字相似度為基礎的小區歸一化方案。基本的想法是
- 使用字首匹配演算法對小區實施初步聚類,
- 然後通過計算文字相似度附加距離權重做進一步篩選,
- 最後識別父子小區識別。
資料預處理
我們按照市、區、小區名和經緯度資訊確定一個小區。所有小區資料儲存在一個表plot裡:小區id、市、區、小區名稱、小區gps、來源source(標記出小區的來源),型別type(0表示父小區,1表示虛擬父小區,2表示子小區,3表示樓棟地址),父小區id。我們需要對原始的小區資料做預處理:
- 需要對原始資料做資料處理:市區的格式,整理成類似:杭州,餘杭區;有些小區gps是非高德gps,需要轉換為高德gps
- 有些小區資料只有省市街道小區名,沒有具體的區域和經緯度資訊,需要使用地圖提示進行校正,儘量補全區域和經緯度資訊
- 小區名裡還會夾雜很多標點符號,干擾我們的分析,我們會首先清除掉這些標點,只對中文字元進行匹配分析
歸一化演算法
小區資訊歸一化流程如下圖所示:
主要的思路是先利用字首匹配演算法匹配小區得到近似小區樹,然後在同一個近似小區樹裡面篩選掉不適合的小區,然後在小區樹之間根據相似度演算法匹配,接著合併同義小區樹,得到最終的歸一化小區樹,在每一棵小區樹中可以使用模式匹配識別父子小區。下面重點介紹前四步。
字首匹配聚集小區
前面提到同一個父小區的大多數子小區都擁有相同的字首。我們以這個作為切入點來識別近似的小區,具體方法如下:
對於同一城市同一區域裡的每一個小區,開始搜尋所有以其名稱的前兩個字開頭的所有小區,這些小區擁有公共字首,稱為以該小區為根的近似小區樹。找到所有的近似小區樹,不斷增加字首的長度,近似小區樹不斷分裂成更小的樹,在合適的時候停止字首長度的增加,最後得到的每個小區樹裡面的小區都是近似小區,可以提取出父小區和子小區。但是如何確定字首長度的最大值呢?分下面幾種情況:
- 如果是能夠判斷出本小區的名稱是子小區或者樓棟的,直接抽取出父小區名,如果沒有同名的父小區則新建一個父小區名,然後搜尋所有以該父小區名為字首的小區,構成一棵以父小區為根的近似小區樹;判斷一個小區名代表的是不是子小區或者小區樓棟的方法是通過前文闡釋的小區名進行正則匹配完成。
- 如果存在其他小區以本小區為字首,那麼認為本小區是一個父小區,並且把以本小區為字首的所有小區都聚集在一起。下圖展示了1、2兩種情況的例子,其中藍色是父小區,紅色是樓棟地址,黃色是子小區:
- 對於其他的小區,那麼字首長度的確定有以下原則:以該長度為字首的小區不超過20(除去重複的小區,以及市、區和小區名完全一樣的小區)。一般來說一個小區的子小區不會太多,一個父小區的子小區數量超過20個是非常少見的。舉例來說,如下圖,小區“翡翠城木蘭苑”無法被識別為子小區或者樓棟地址,依靠字首得到了它的近似小區樹,樹的數量小於20,停止字首增長。
對於每一個小區都做這樣一個操作,就會得到每個小區對應的字首樹,也稱為小區樹(使用字首樹實現),這個小區稱為小區樹的根。容易知道一個小區可能在多個小區樹中。在這個過程中也能夠識別一部分小區樓棟、子小區和父小區。
本質上講,這一步是文字聚類的過程。如下圖所示,文字聚類通常對文字分詞,然後使用TF-IDF(Term Frequency-Inverse Document Frequency,詞頻-逆文字頻率)統計出詞頻、設定詞語權重,構建VSM(Vector Space Model,向量空間模型), 為每個文字構建等長向量,最後設定度量標準(歐氏距離、餘弦相似度等),使用聚類演算法對文字聚類。
這種方法不太適合我們的場景:1. 這種方法通常是針對具有多個特徵詞的文件進行聚類,然而小區名稱短,很難提取出有效的特徵詞;2. 小區名稱有一個特徵比較明顯,即父子小區以及樓棟號的名稱按照順序是有層級關係的,然而這個特徵卻不能在文字向量化聚類演算法中體現並利用;3. 常用的聚類演算法如K-Means等選擇合適的k值需要技巧和摸索,而我們的方法利用子小區數量不會太多這一點規避了這個問題。
非同義小區過濾
上一步中得到的是擁有相同字首的小區樹。依靠字首,我們圈選的小區是比較多的,很多不屬於同一個父小區的小區被圈選到同一棵小區樹中了。一般來說,一個小區的不同子小區之間的距離不會太遠。因此,我們過濾掉地理位置較遠的小區。具體來講就是,如果近似小區樹裡面小區A和小區樹的根小區的距離大於2km,那麼把這個小區從小區樹中刪除。
近似小區再聚集
並不是所有的同義小區都有相同的字尾。所以,我們也通過文字相似度,來補充一些被遺漏的同義小區:
計算近似樹字首的編輯距離和gps距離,對於gps距離小於1km,而且相似度大於2的近似樹可以合併為一棵同義小區樹,其中相似度的計算如下:
其中a和b分別是兩棵小區樹的根小區的名稱,max(a,b)是a和b的長度最大值,LevenshteinDistance(a, b)是編輯距離,similarity(a, b)越大表示a和b越相似。
如上圖所示,“西溪風情”不是“大華西溪風情”的字首,所以在第一步的字首匹配聚集中,沒有被加入到“大華西溪風情”的近似小區樹。針對這種字首覆蓋不到的情況,我們計算“西溪風情”和“大華西溪風情”的相似度為3,這個相似度表示文字總長度是文字差異的倍數,越大說明相對差別越小。當這個相似度大於2時,我們把兩棵相似樹合併。
歸一化
在以每個小區為根,聚集得到相應的小區樹之後,小區樹之間會有很多重疊。這一步把有交集的小區樹合併得到最終的小區歸一化結果。合併後的小區樹中的小區可以認為是同義的小區,這一步可以說是最終的小區歸一化。
評估
使用高德地圖中準確區分了同義小區的資料以及人工識別,衡量小區歸一化演算法的準確度。主要從兩個方面:
- 正誤識(false positives): 本來歸於父小區的子小區,未能被識別出來;
- 負誤識(false negatives): 不歸某一父小區的子小區,卻被誤識為這個父小區的子小區;
資料顯示本文介紹的演算法正誤識比率低於8%,負誤識比率低於5%,說明這種歸一化方法的準確度有一定保證。
總結
本文通過觀察小區名稱和層級關係的規律,提出了一種使用文字匹配和近似度分析解決小區資訊歸一化問題的方法。方法實現簡單,有較高的準確度,能夠快速識別近似的小區,為提高房源搜尋的效率和房源釋出的準確度提供了基礎資料保障。
相關文章
- 實現多資料來源混合計算的效能最佳化方案之一
- Spark SQL:JSON資料來源複雜綜合案例實戰SparkSQLJSON
- Spark SQL:Hive資料來源複雜綜合案例實戰SparkSQLHive
- Spark SQL:JDBC資料來源複雜綜合案例實戰SparkSQLJDBC
- 資料變換-歸一化與標準化
- 想要更精準的小程式模版訊息推送?我們來幫你實現
- 資料歸一化
- App抓包其實沒那麼複雜!Charles來幫你搞定APP
- 當查詢的資料來自多個資料來源,有哪些好的分頁策略?
- 金融行業如何利用資料來源實現精準營銷?行業
- Flink接入Kafka資料來源實現精準一次(Exactly-once)的注意點Kafka
- 資料清洗太難了?那是你沒有好工具,讓Smartbi來幫你!
- 7 個步驟幫你編寫一份好的資料分析報告 - modernanalystNaN
- 寫一個構建複雜資料的日曆元件 Kalendar元件
- ECharts與資料視覺化:如何高效使用JavaScript實現複雜圖表Echarts視覺化JavaScript
- 實現多資料來源事務
- Spring系列 之資料來源的配置 資料庫 資料來源 連線池的區別Spring資料庫
- 架構設計複雜度的6個來源架構複雜度
- Python資料預處理:徹底理解標準化和歸一化Python
- 《個人資訊保護法》來了,你準備好了嗎?
- DataPipeline「自定義」資料來源,解決複雜請求邏輯外部資料獲取難題API
- vue+elementUI 複雜表單的驗證、資料提交方案VueUI
- 一個簡化、落地的實時資料倉儲解決方案
- 談談Spring Boot 資料來源載入及其多資料來源簡單實現Spring Boot
- 122個經典SOTA模型、447個演算法實現資源,我們幫你一文彙總了模型演算法
- 一文告訴你資料和資訊的區別
- 中小企業實行資訊化嗎?什麼時候開始比較好?
- 直面不確定性與非線性的複雜現實:邁向複雜性經濟 - Cilliers
- Android ListView中複雜資料流的高效渲染(一)AndroidView
- 1.配置Tomcat資料來源Tomcat
- C語言中的複雜資料型別,你掌握了哪些?C語言資料型別
- SpringBoot 複雜配置資訊讀取Spring Boot
- 實現資料管理現代化的 7 個技巧
- 發現資料異常波動怎麼辦?別慌,指標監控和歸因分析來幫你指標
- Spring-Boot 多資料來源配置+動態資料來源切換+多資料來源事物配置實現主從資料庫儲存分離Springboot資料庫
- 精讀《維護好一個複雜專案》
- 複雜SQL構造資料:SQL
- 從0開始弄一個面向OC資料庫(四)–複雜資料模型儲存資料庫模型