1. 程式人生 > >pandas讀取中文檔案的UnicodeDecodeError編碼問題彙總

pandas讀取中文檔案的UnicodeDecodeError編碼問題彙總

Outline

  • 批量處理檔案
  • 獲取檔案編碼
  • 不能decode bytes …
  • python的異常處理
  • read_csv中的error_bad_line引數
  • 小感

批量處理檔案

為了批量處理檔案,當然是想辦法獲取檔名,通過檔名形成檔案路徑從而批處理檔案。
我以前繞過大彎,根據檔案的命名規律,尤其是其中的數字遞增規律來建立路徑,自從發現os庫裡的listdir函式才知道自己有多蠢!

獲取資料夾下所有檔案的filename
files = os.listdir(r'C:\Users\didi\Desktop\work\perf\perform_1')

files是perform_1資料夾下所有檔案的檔名形成的列表,再迴圈處理

all_data = []
for file in files:
    file_path = 'C:/Users/didi/Desktop/work/perf/perform_1/' + file
    encoding = get_encoding(file_path)
    print(encoding)
    f = open(file_path,encoding=encoding,errors='ignore')
    new_data = []
    for line in f.readlines():
        # each_line = line.replace('\n','').split(',')
new_data.append(line) new_data = new_data[1:] for i in new_data: all_data.append(i) print(all_data)

獲取檔案編碼

# 獲取檔案編碼型別
def get_encoding(file):
    # 二進位制方式讀取,獲取位元組資料,檢測型別
    with open(file, 'rb') as f:
        return chardet.detect(f.read())['encoding']

不能decode bytes …

原因:有些編碼是不相容的,比如utf-8不能gbk的,GB2312不能解碼GBK中的有些字元,我們需要知道檔案本身的編碼是什麼

解決辦法:
1、我們用上一個<獲取檔案編碼>裡的方法得到檔案的編碼,然後在open函式中設定encoding引數為檔案自身的編碼

encoding = get_encoding(file_path)
f = open(file_path,encoding=encoding)

2、對於中文字元的問題,我們已知底下的排序,按照編碼方式包含的字元數的多少從少到多進行排序。因為GB2312編碼的,我們可以試圖用GBK或者更高的GB18030來開啟。
GB2312 < GBK < GB18030

3、如果繼續出現UnicodeDecodeError問題,則可以設定open函式中的error引數來控制錯誤的策略。

預設的引數就是strict,代表遇到非法字元時丟擲異常; 如果設定為ignore,則會忽略非法字元; 如果設定為replace,則會用?取代非法字元; 如果設定為xmlcharrefreplace,則使用XML的字元引用

因此最終我是這麼解決我的問題的:

df = pd.DataFrame()
files = os.listdir('intern/perform/')
for file in files:
    file_path = 'perform/' + file
    encoding = get_encoding(file_path) # get_encoding函式在上文
    f = open(file_path, encoding=encoding,errors='replace')
    data = pd.read_csv(f, skiprows=1, header=None)
    df = df.append(data)

想設定成replace是因為我想知道未解碼成功的字元在哪些位置,當然也可以選擇ignore進行處理

python的異常處理

read_csv中的error_bad_line引數

發覺read_csv中有用的引數真的特別多,skiprows header sep parse_dates等等等等

而今天發現的error_bad_line引數是當你遇到特別異常的記錄時,比如某一行的逗號較其他行多,導致資料的列數不匹配,這會引起異常,也不會返回相應的dataframe。而如果設定error_bad_line = False,可以選擇返回的dataframe裡面捨棄掉“bad_line”
這裡寫圖片描述
而另一個與之相匹配的引數是warn_bad_lines,通過True or False選擇是否提示跳過的line

data = pd.read_csv(f, skiprows=1, header=Noneerror_bad_lines = False,warn_bad_lines=True)

小感

實際問題場景中,資料遠比我們的想象的要髒很多,各種亂七八糟的想象不到的問題,而你眼中所見的也會迷惑你,不管怎樣,兵來將擋水來土掩,養成良好的獨立搜尋解決問題的習慣,形成自己的知識結構以及對資料的敏感度和處理經驗,是最重要的~