熊猫read_csv在 gzip 文件上失败,UnicodeDecode错误:'utf-8'编解码器无法解码位置 1 中的字节0x8b:无效的起始字节



我正在尝试处理一系列.gz(gzipped(文件。我发誓,当我第一次开始调试代码的其他部分时,他们早些时候读得很成功,但我不能保证这一点。我切换到一个未压缩的测试文件,这样我就可以看到是什么导致了一些类型转换失败。一旦我调试好了,并尝试处理真正的gzip文件,我就开始出现错误。我很乐意就问题可能是什么和/或如何进一步调查提出任何想法。

我把它分解为以下代码:

#!/usr/bin/env python3
import numpy as np
import pandas as pd
filename = './small_test.csv.gz'
names = ['string_var','int_var','float_var','date_var']
types = {'string_var': 'string','int_var':'int64','float_var':'float64','date_var':'string'}
with open(filename) as csvfile:
print(filename)
#    df = pd.read_csv(csvfile,names=names,header=0,dtype=types)
#    df = pd.read_csv(csvfile,compression='gzip')
df = pd.read_csv(csvfile)
print(df.info(verbose=True))

我试着只指定文件并默认所有内容,指定文件和压缩,并做我真正需要做的事情,即指定名称和类型。我还在我的完整数据集上尝试了所有这些组合。它们都以相同的方式失败,并出现以下错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

我在stackoverflow上发现了其他问题,表明这是一个编码问题。我有read_csv用来推断的正确的.gz扩展名,我还明确指定了它。堆栈跟踪(下面(显示它正在进入gzip例程。file-I命令正确地将压缩文件标识为gzip:small_test.csv.gz: application/x-gzip; charset=binary并且文本文件为ASCII:small_test.csv: text/plain; charset=us-ascii,所以这似乎不是问题。

基于以上内容,我还尝试了编码="scii"和编码="s-asci"。他们以同样的方式失败了。

还有一个没有.gz扩展名,所以它被gzip了,它试图以未压缩的方式读取,但这不是我的问题。如果我解压缩文件,它工作得很好。如果我重新压缩它,它就会失败。gzcat和gzip在所有文件上都能正常工作,所以我不认为这是腐败问题。

如果有用的话,下面是测试文件:

"string_var","int_var","float_var","date_var"
a,1,1.0,"2020-01-01 21:20:19"
b,2,2.0,"2019-10-31 00:00:00"
c,3,3.0,"1969-06-22 12:00:00"

最后,这是整个堆栈跟踪:

Traceback (most recent call last):
File "./test_read_csv.py", line 14, in <module>
df = pd.read_csv(csvfile,compression='gzip',encoding='us-ascii')
File "/usr/local/lib/python3.7/site-packages/pandas/io/parsers.py", line 676, in parser_f
return _read(filepath_or_buffer, kwds)
File "/usr/local/lib/python3.7/site-packages/pandas/io/parsers.py", line 448, in _read
parser = TextFileReader(fp_or_buf, **kwds)
File "/usr/local/lib/python3.7/site-packages/pandas/io/parsers.py", line 880, in __init__
self._make_engine(self.engine)
File "/usr/local/lib/python3.7/site-packages/pandas/io/parsers.py", line 1114, in _make_engine
self._engine = CParserWrapper(self.f, **self.options)
File "/usr/local/lib/python3.7/site-packages/pandas/io/parsers.py", line 1891, in __init__
self._reader = parsers.TextReader(src, **kwds)
File "pandas/_libs/parsers.pyx", line 529, in pandas._libs.parsers.TextReader.__cinit__
File "pandas/_libs/parsers.pyx", line 719, in pandas._libs.parsers.TextReader._get_header
File "pandas/_libs/parsers.pyx", line 915, in pandas._libs.parsers.TextReader._tokenize_rows
File "pandas/_libs/parsers.pyx", line 2062, in pandas._libs.parsers.raise_parser_error
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/_compression.py", line 68, in readinto
data = self.read(len(byte_view))
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/gzip.py", line 463, in read
if not self._read_gzip_header():
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/gzip.py", line 406, in _read_gzip_header
magic = self._fp.read(2)
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/gzip.py", line 91, in read
self.file.read(size-self._length+read)
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/codecs.py", line 322, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

在我的同事的大量帮助下,我们深入研究了Pandas代码,发现了这一点。这里是简短的版本:如果你想打开一个gzip文件并将其传递给read_csv(),你必须用二进制文件打开它并指定压缩:

with open(filename, 'rb') as csvfile:
df = pd.read_csv(csvfile,compression='gzip')

read_csv()打开同样有效:read_csv(filename) #filename is a string ending in .gz

主要的问题是我没有打开二进制文件。由于我没有,csvfile的默认编码是UTF-8。因此,以下是场景:

with open(filename) as csvfile: # Not binary

  • read_csv(csvfile):Pandas使用了一个文本解析器,但由于文件被gzip化而失败
  • read_csv(csvfile, compression='gzip'):这是我工作最多的地方。它确实进入了gzip(这就是令人困惑的地方(,然后调用了read_header,但由于文件句柄设置为UTF-8,它再次使用文本读取器,但失败了

with open(filename, 'rb') as csvfile:

  • read_csv(csvfile):这仍然失败。这一次它失败了,因为压缩的默认值是"推断",但如果你仔细阅读文档,"推断"只有在"类似路径"的情况下才有效。它根据它没有的文件扩展名进行推断,因为它被传递了一个文件句柄,而不是路径的字符串表示。当它没有以二进制形式打开时,这与上面的read_csv(csvfile)情况相同。

  • read_csv(csvfile, compression='gzip'):这是有效的。该文件是二进制的,因此不使用UTF读取器,并且它被明确告知它是gzip的,因此它调用gzip库

我找到了解决该问题的正确编码。编码是";ISO-8859-1";,用CCD_ 15代替CCD_。

df = pd.read_csv(csv_file_or_csv.gz_file, encoding = "ISO-8859-1")

最新更新