正在 pandas 中加载包含二进制数据的 CSV 文件
Loading CSV file with binary data in pandas
我正在尝试解析一个 CSV 文件(来自外部数据源),其中一列使用不一致的字符编码。我不想让数据提供者使用一致的编码,而是想将该列作为二进制数据读取。但是,pandas.read_csv
似乎在解析之前将整个文件解码为字符串,所以这给了我错误(UnicodeDecodeError)。这是一个玩具示例 (python 3):
>>> from io import BytesIO
>>> import pandas as pd
>>> csv = b'Encoding,Data\nascii,abc\nwindows-1252,\xae\nutf-8,\xe2\x80\x9c1\xe2\x80\x9d\n'
>>> pd.read_csv(BytesIO(csv))
Traceback (most recent call last):
File "pandas/_libs/parsers.pyx", line 1130, in pandas._libs.parsers.TextReader._convert_tokens
File "pandas/_libs/parsers.pyx", line 1254, in pandas._libs.parsers.TextReader._convert_with_dtype
File "pandas/_libs/parsers.pyx", line 1269, in pandas._libs.parsers.TextReader._string_convert
File "pandas/_libs/parsers.pyx", line 1459, in pandas._libs.parsers._string_box_utf8
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 0: invalid start byte
我想要一个等同于此的结果:
>>> df = pd.DataFrame({'Encoding': ['ascii','windows-1252','utf-8'],
... 'Data': [b'abc',b'\xae',b'\xe2\x80\x9c1\xe2\x80\x9d']})
>>> df
Encoding Data
0 ascii b'abc'
1 windows-1252 b'\xae'
2 utf-8 b'\xe2\x80\x9c1\xe2\x80\x9d'
哪个可以(在这个玩具示例中)像这样进一步处理:
>>> df.apply(lambda row: str(row.Data,row.Encoding), axis=1)
0 abc
1 ®
2 “1”
dtype: object
我更喜欢仅使用 pandas 的解决方案,但如果绝对必要,我愿意查看其他解析库。
根据Serge Ballesta answering this post
"Pandas allows to specify encoding, but does not allow to ignore errors not to automatically replace the offending bytes. So there is no one size fits all method but different ways depending on the actual use case."
所以首先,尝试使用 Latin1
编码,因为它接受任何可能的字节作为输入,并且根据您的用例可能就足够了(我可以 运行 您的玩具示例使用这个):
data_frame = pd.read_csv(BytesIO(csv), encoding="latin1"))
如 Serge 的回答所述:"Pandas has no provision for a special error processing, but Python open
function has (assuming Python3), and read_csv
accepts a file like object." 对于您的情况,您可以考虑使用 'backslashreplace'
,它用 Python 的反斜杠转义序列替换有问题的字节:
file_encoding = 'utf8' # set file_encoding to the file encoding (utf8, latin1, etc.)
with open(path_to_csv, encoding=file_encoding, errors = 'backslashreplace') as my_csv:
dataframe = pd.read_csv(my_csv)
我正在尝试解析一个 CSV 文件(来自外部数据源),其中一列使用不一致的字符编码。我不想让数据提供者使用一致的编码,而是想将该列作为二进制数据读取。但是,pandas.read_csv
似乎在解析之前将整个文件解码为字符串,所以这给了我错误(UnicodeDecodeError)。这是一个玩具示例 (python 3):
>>> from io import BytesIO
>>> import pandas as pd
>>> csv = b'Encoding,Data\nascii,abc\nwindows-1252,\xae\nutf-8,\xe2\x80\x9c1\xe2\x80\x9d\n'
>>> pd.read_csv(BytesIO(csv))
Traceback (most recent call last):
File "pandas/_libs/parsers.pyx", line 1130, in pandas._libs.parsers.TextReader._convert_tokens
File "pandas/_libs/parsers.pyx", line 1254, in pandas._libs.parsers.TextReader._convert_with_dtype
File "pandas/_libs/parsers.pyx", line 1269, in pandas._libs.parsers.TextReader._string_convert
File "pandas/_libs/parsers.pyx", line 1459, in pandas._libs.parsers._string_box_utf8
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 0: invalid start byte
我想要一个等同于此的结果:
>>> df = pd.DataFrame({'Encoding': ['ascii','windows-1252','utf-8'],
... 'Data': [b'abc',b'\xae',b'\xe2\x80\x9c1\xe2\x80\x9d']})
>>> df
Encoding Data
0 ascii b'abc'
1 windows-1252 b'\xae'
2 utf-8 b'\xe2\x80\x9c1\xe2\x80\x9d'
哪个可以(在这个玩具示例中)像这样进一步处理:
>>> df.apply(lambda row: str(row.Data,row.Encoding), axis=1)
0 abc
1 ®
2 “1”
dtype: object
我更喜欢仅使用 pandas 的解决方案,但如果绝对必要,我愿意查看其他解析库。
根据Serge Ballesta answering this post
"Pandas allows to specify encoding, but does not allow to ignore errors not to automatically replace the offending bytes. So there is no one size fits all method but different ways depending on the actual use case."
所以首先,尝试使用
Latin1
编码,因为它接受任何可能的字节作为输入,并且根据您的用例可能就足够了(我可以 运行 您的玩具示例使用这个):data_frame = pd.read_csv(BytesIO(csv), encoding="latin1"))
如 Serge 的回答所述:"Pandas has no provision for a special error processing, but Python
open
function has (assuming Python3), andread_csv
accepts a file like object." 对于您的情况,您可以考虑使用'backslashreplace'
,它用 Python 的反斜杠转义序列替换有问题的字节:file_encoding = 'utf8' # set file_encoding to the file encoding (utf8, latin1, etc.) with open(path_to_csv, encoding=file_encoding, errors = 'backslashreplace') as my_csv: dataframe = pd.read_csv(my_csv)