在Pandas中读取CSV文件时出现UnicodeDecodeError错误。

696
我正在运行一个处理30,000个类似文件的程序。其中随机数量的文件停止并产生此错误...
  File "C:\Importer\src\dfman\importer.py", line 26, in import_chr
    data = pd.read_csv(filepath, names=fields)
  File "C:\Python33\lib\site-packages\pandas\io\parsers.py", line 400, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "C:\Python33\lib\site-packages\pandas\io\parsers.py", line 205, in _read
    return parser.read()
  File "C:\Python33\lib\site-packages\pandas\io\parsers.py", line 608, in read
    ret = self._engine.read(nrows)
  File "C:\Python33\lib\site-packages\pandas\io\parsers.py", line 1028, in read
    data = self._reader.read(nrows)
  File "parser.pyx", line 706, in pandas.parser.TextReader.read (pandas\parser.c:6745)
  File "parser.pyx", line 728, in pandas.parser.TextReader._read_low_memory (pandas\parser.c:6964)
  File "parser.pyx", line 804, in pandas.parser.TextReader._read_rows (pandas\parser.c:7780)
  File "parser.pyx", line 890, in pandas.parser.TextReader._convert_column_data (pandas\parser.c:8793)
  File "parser.pyx", line 950, in pandas.parser.TextReader._convert_tokens (pandas\parser.c:9484)
  File "parser.pyx", line 1026, in pandas.parser.TextReader._convert_with_dtype (pandas\parser.c:10642)
  File "parser.pyx", line 1046, in pandas.parser.TextReader._string_convert (pandas\parser.c:10853)
  File "parser.pyx", line 1278, in pandas.parser._string_box_utf8 (pandas\parser.c:15657)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xda in position 6: invalid    continuation byte

这些文件的来源/创建都来自同一处。最佳的纠正方法是什么以继续导入?

2
添加这个参数对我有用:encoding_errors='ignore' - matthewpark319
1
忽略错误应该是你最后的无奈选择。同样地,随意猜测使用哪种编码可能会表面上消除错误,但在结果中产生完全的垃圾。如果你对文本编码还不熟悉,也许可以从 Stack Overflow character-encoding 标签信息页面 开始你的下一个冒险。 - tripleee
27个回答

1199

read_csv提供了一个encoding选项来处理不同格式的文件。我通常使用read_csv('file', encoding = "ISO-8859-1"),或者用encoding = "utf-8"来读取数据,并且通常使用utf-8作为to_csv的编码。

你还可以使用一些其他的选项,比如'latin''cp1252'(Windows),代替'ISO-8859-1'(可以查看Python文档,其中也列出了许多其他可能遇到的编码)。

更多相关信息,请参考Pandas文档Python CSV文件示例文档以及这里的大量相关问题。另外一个很好的背景资源是关于Unicode和字符集,每个开发者都必须知道的最基本内容

如果你需要检测编码(假设文件包含非ASCII字符),可以使用enca(参见man文档)或file -i(Linux)或file -I(OS X)(参见man文档)。


11
@Ben 这是一个很好的资源,每个开发者都应该了解的Unicode和字符集知识 - Stefan
1
ISO-8859-1在Python编码中具有独特的属性,即可以读取任何二进制数据而不会抛出错误。很多初学者经常会尝试不同的编码方式,但实际上并没有查看其结果数据,然后当他们选择错误的编码方式时,就会惊讶地发现自己得到了垃圾数据。 - tripleee
@tripleee,除非你认为像在Python的系统中实现ROT-13这样的东西是“编码”,否则没有“Python编码”的说法;ISO-8859-1是一个国际公认的标准(因此称为ISO),在无数的环境中得到了无数次的实现。16个ISO-8859编码中有10个可以处理任意二进制数据,历史上的一些DOS代码页、旧版Macintosh文本编码以及其他一些编码也可以。不过,ISO-8859-1确实具有(必要的)独特特性,即将这些字节按顺序映射到前256个Unicode码点。 - Karl Knechtel
当然,我是指Python支持的字符编码之间。 - tripleee

208

最简单的解决方案:

import pandas as pd
df = pd.read_csv('file_name.csv', engine='python')

备选方案:

Sublime Text:

  • Sublime文本编辑器 或者 VS Code 中打开csv文件。
  • 将文件保存为utf-8格式。
  • 在Sublime中,点击 文件 -> 以编码方式保存 -> UTF-8。

VS Code:

在VSCode的底部工具栏中,您会看到标签UTF-8。单击它,弹出一个窗口。单击“编码保存”,然后您可以选择该文件的新编码。

然后,您可以像往常一样读取您的文件:

import pandas as pd
data = pd.read_csv('file_name.csv', encoding='utf-8')

还有其他不同的编码类型:

encoding = "cp1252"
encoding = "ISO-8859-1"

43
Pandas允许指定编码,但不允许忽略错误或自动替换有问题的字节。因此,没有一种通用的方法适用于所有情况,而是根据实际使用情况选择不同的方式。
  1. 如果您知道文件的编码,并且文件中没有编码错误。 那么很好:只需指定编码即可:

    file_encoding = 'cp1252'        # set file_encoding to the file encoding (utf8, latin1, etc.)
    pd.read_csv(input_file_and_path, ..., encoding=file_encoding)
    
  2. 你不想被编码问题困扰,只想让该死的文件加载,不管一些文本字段是否包含垃圾。好的,你只需要使用Latin1编码,因为它接受任何可能的字节作为输入(并将其转换为相同代码的Unicode字符):

  3. pd.read_csv(input_file_and_path, ..., encoding='latin1')
    
  4. 你知道大部分文件都使用特定的编码方式进行写作,但也包含编码错误。一个现实世界的例子是UTF8文件,在非UTF8编辑器中进行编辑,其中包含一些不同编码方式的行。Pandas没有提供特殊的错误处理功能,但Python的open函数(假设Python3)具有此功能,并且read_csv接受文件对象。在这里使用的典型错误参数是'ignore',它只抑制有问题的字节,或者(在我看来更好的)'backslashreplace',它将有问题的字节替换为它们的Python反斜线转义序列:

  5. file_encoding = 'utf8'        # set file_encoding to the file encoding (utf8, latin1, etc.)
    input_fd = open(input_file_and_path, encoding=file_encoding, errors = 'backslashreplace')
    pd.read_csv(input_fd, ...)
    

33

这是一个更一般的脚本方法来回答所提出的问题。

import pandas as pd

encoding_list = ['ascii', 'big5', 'big5hkscs', 'cp037', 'cp273', 'cp424', 'cp437', 'cp500', 'cp720', 'cp737'
                 , 'cp775', 'cp850', 'cp852', 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862'
                 , 'cp863', 'cp864', 'cp865', 'cp866', 'cp869', 'cp874', 'cp875', 'cp932', 'cp949', 'cp950'
                 , 'cp1006', 'cp1026', 'cp1125', 'cp1140', 'cp1250', 'cp1251', 'cp1252', 'cp1253', 'cp1254'
                 , 'cp1255', 'cp1256', 'cp1257', 'cp1258', 'euc_jp', 'euc_jis_2004', 'euc_jisx0213', 'euc_kr'
                 , 'gb2312', 'gbk', 'gb18030', 'hz', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2'
                 , 'iso2022_jp_2004', 'iso2022_jp_3', 'iso2022_jp_ext', 'iso2022_kr', 'latin_1', 'iso8859_2'
                 , 'iso8859_3', 'iso8859_4', 'iso8859_5', 'iso8859_6', 'iso8859_7', 'iso8859_8', 'iso8859_9'
                 , 'iso8859_10', 'iso8859_11', 'iso8859_13', 'iso8859_14', 'iso8859_15', 'iso8859_16', 'johab'
                 , 'koi8_r', 'koi8_t', 'koi8_u', 'kz1048', 'mac_cyrillic', 'mac_greek', 'mac_iceland', 'mac_latin2'
                 , 'mac_roman', 'mac_turkish', 'ptcp154', 'shift_jis', 'shift_jis_2004', 'shift_jisx0213', 'utf_32'
                 , 'utf_32_be', 'utf_32_le', 'utf_16', 'utf_16_be', 'utf_16_le', 'utf_7', 'utf_8', 'utf_8_sig']

for encoding in encoding_list:
    worked = True
    try:
        df = pd.read_csv(path, encoding=encoding, nrows=5)
    except:
        worked = False
    if worked:
        print(encoding, ':\n', df.head())

首先需要获取Python版本(此处为3.7),并检索其所有可用的标准编码格式。具体信息请参见Python 3.7标准编码格式。这里提供了一个有用的Stack Overflow回答,其中包含各版本Python的标准编码格式列表:Helpful Stack Overflow回答

接下来,对数据的一个小块尝试每种编码格式,并只输出能够正常工作的编码格式。输出结果非常明显。此外,这个输出还解决了一些问题,如运行没有任何错误的“latin1”编码格式可能不会产生所需的结果。

针对问题CSV文件,可以尝试这种特定的方法,然后尝试在所有其他文件中使用找到的可用编码格式。


哈哈,干得好兄弟。 - Egbert Ke

26

请尝试添加

import pandas as pd
df = pd.read_csv('file.csv', encoding='unicode_escape')

这会有所帮助。对我有用。另外,请确保您正在使用正确的分隔符和列名称。

您可以从加载1000行开始,以便快速加载文件。


24
with open('filename.csv') as f:
   print(f)

执行此代码后,您将找到“filename.csv”的编码,然后按照以下方式执行代码

data=pd.read_csv('filename.csv', encoding="encoding as you found earlier"

你做到了


13

尝试更改编码方式。

在我的情况下,encoding = "utf-16"有效。

df = pd.read_csv("file.csv", encoding='utf-16')


12

您可以首先使用 chardetcchardetcharset-normalizer 尝试检测文件的编码:

from pathlib import Path
import chardet

filename = "file_name.csv"
detected = chardet.detect(Path(filename).read_bytes())
# detected is something like {'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

encoding = detected.get("encoding")
assert encoding, "Unable to detect encoding, is it a binary file?"

df = pd.read_csv(filename, encoding=encoding)


7
在我的情况下,一个文件具有USC-2 LE BOM编码,根据Notepad++的说法。 对于Python来说,它是encoding="utf_16_le"。 希望这能帮助某些人更快地找到答案。

6

尝试指定engine='python'。这对我有用,但我仍在努力弄清楚原因。

df = pd.read_csv(input_file_path,...engine='python')

这对我也起作用了。encoding = "ISO-8859-1" 也是如此。这绝对是一个编码问题。如果一个特殊字符被编码为 ANSI,比如省略号字符(即“...”),而你尝试以 UTF-8 读取它,你可能会得到一个错误。底线是你必须知道文件是用什么编码创建的。 - Sean McCarthy
“Encoded in ANSI”没有明确定义。在Windows上,ANSI术语是一个误称,并且不命名任何特定的编码;相反,它选择在系统设置中定义的编码。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接