一峦嗤、背景描述
開發(fā)環(huán)境:python2.7院水,spyder腊徙。
問題:行為評分卡做模型監(jiān)控(樣本外驗證),對驗證月份數據集進行數據分箱檬某,中文類變量無法正確判斷是否相同撬腾,導致數據分箱錯誤。
示例:教育程度變量(尰帜眨科民傻,本科,碩士)场斑,由于中文比較一致錯誤漓踢,導致變量分箱均分到了最后一組碩士。
初步分析:在建模過程中做測試漏隐、驗證集的分箱未發(fā)生此問題喧半,因此懷疑主要是在數據持久化的時候pickle(模型及數據字典的保存)、pandas(dataframe基礎數據)對數據的編碼方式存在差異青责。
解決思路:py2本身對中文支持不友好薯酝,由于編碼不同所以導致同一中文在py2中判斷一致性時判斷為False,那么決定在讀取數據后爽柒,對數據統一為同一編碼格式是最簡單的吴菠。(修改源代碼、研究那兩庫會消耗更多時間浩村,不劃算)做葵。
吐槽:原始代碼的作者和團隊負責人都不太靠譜,其實就我們的應用場景而言心墅,python3完全可以滿足酿矢,遷移也很簡單榨乎,不過剛好也想搞明白python的編碼機制,那就這樣吧瘫筐。
二蜜暑、python2的編碼原理
參考文章:https://www.cnblogs.com/liaohuiqiang/p/7247393.html
參考文章說的非常詳細,不贅述策肝,這里總結幾個自己覺得比較重要的點:
1肛捍、通過chardet檢查自己數據的編碼類型,方便后續(xù)轉碼
示例:chardet.detect(df['char_apply_education_info'][0])
2之众、默認中文編碼格式:py2:utf-8拙毫,py3:unicode,其中py2默認使用ascii碼讀取源文件棺禾,所以程序文件開始還需聲明:# encoding=utf8缀蹄。
據說py2中在字符串前加u可以轉換為unicode編碼,不過我沒太搞明白對我的用處膘婶。
還有個據說缺前,設置sys的setdefaultencoding('utf8'),影響print輸出格式悬襟,其中有篇文章做了很詳細的分析衅码,我覺得也沒啥用。
import sys
reload(sys)
sys.setdefauleencoding('utf8')
3古胆、py2編碼的順序(后續(xù)解決問題的關鍵)
str -> decode(根據指定編碼格式解碼) -> unicode -> encode(根據指定編碼格式編碼) -> str
py2中比較字符串時肆良,如果A是unicode而B不是筛璧,那么將對B使用系統默認編碼進行解碼逸绎。
三、問題解決方法
思路想清楚了其實很簡單夭谤,分兩步:
1棺牧、選取df中的object類變量做編碼轉換(注意先處理空值,不然會報錯朗儒,空值沒有decode方法)
示例:str(type(df['char_apply_education_info'])) == '''<type 'numpy.string_'>'''
應該是有更好的方法做類型判斷颊乘,比如pandas自帶的select等方法,項目時間有限醉锄,就先解決問題了乏悄。
2、查看數據編碼格式差異恳不,然后轉換為同一種編碼格式
示例:df['char_apply_education_info'][0].decode('gb2312').encode('utf8')
其中檩小,gb2312是df的編碼格式,utf8是model通過pickle讀取到內存后的編碼格式烟勋。
至于為什么轉換df而不轉換model规求,是因為在我這這么操作更方便筐付,不能一概而論,但道理上是這樣的阻肿,同一編碼即可瓦戚。