Чтение ARFF из ZIP с помощью zipfile и scipy.io.arff

Я хочу обрабатывать довольно большие файлы ARFF в scikit-learn. Файлы находятся в zip архиве и я не хочу распаковывать архив в папку перед обработкой. Следовательно, я использую модуль zipfile Python 3.6:

from zipfile import ZipFile
from scipy.io.arff import loadarff

archive = ZipFile( 'archive.zip', 'r' )
datafile = archive.open( 'datafile.arff' )
data = loadarff( datafile )
# …
datafile.close()
archive.close()

Однако это приводит к следующей ошибке:

Traceback (most recent call last):
  File "./m.py", line 6, in <module>
    data = loadarff( datafile )
  File "/usr/lib64/python3.6/site-packages/scipy/io/arff/arffread.py", line 541, in loadarff
    return _loadarff(ofile)
  File "/usr/lib64/python3.6/site-packages/scipy/io/arff/arffread.py", line 550, in _loadarff
    rel, attr = read_header(ofile)
  File "/usr/lib64/python3.6/site-packages/scipy/io/arff/arffread.py", line 323, in read_header
    while r_comment.match(i):
TypeError: cannot use a string pattern on a bytes-like object

Согласно документации loadarff, loadarff требуется файлоподобный объект. Согласно документации по zip-файлу, open возвращает файл ZipExtFile.

Следовательно, мой вопрос заключается в том, как использовать то, что ZipFile.open возвращает в качестве ввода ARFF для loadarff.

Примечание. Если я разархивирую вручную и загружу ARFF напрямую с помощью data = loadarff( 'datafile.arff' ), все будет в порядке.


person Bernhard Bodenstorfer    schedule 19.03.2019    source источник
comment
loadarff требует файлоподобный объект. Таким образом, вы должны читать файл в памяти, такой как объект. Можете ли вы попробовать это? in_mem_fo = StringIO(archive.read('datafile.arff'))   -  person Nihal Sangeeth    schedule 19.03.2019
comment
Это дает ошибку: файл m.py, строка 7, в ‹module› in_mem_fo = StringIO(archive.read('datafile.arff')) TypeError: initial_value должно быть str или None, а не bytes   -  person Bernhard Bodenstorfer    schedule 19.03.2019
comment
Но ваша идея позвольте мне найти решение: in_mem_fo = StringIO(archive.read('datafile.arff').decode("utf-8")) или in_mem_fo = StringIO(archive.read('datafile.arff').decode("ascii"))   -  person Bernhard Bodenstorfer    schedule 19.03.2019
comment
Большой. Я добавил ответ, который может быть лучшим решением.   -  person Nihal Sangeeth    schedule 19.03.2019


Ответы (1)


from io import BytesIO, TextIOWrapper
from zipfile import ZipFile
from scipy.io.arff import loadarff

zfile = ZipFile('archive.zip', 'r')
in_mem_fo = TextIOWrapper(BytesIO(zfile.read('datafile.arff')), encoding='utf-8')
data = loadarff(in_mem_fo)

Считайте zfile в объект BytesIO в памяти. Используйте TextIOWrapper с encoding='utf-8'. Используйте этот буферизованный в памяти текстовый объект в loadarff.

Редактировать: Turnsout zfile.open() возвращает файлоподобный объект, поэтому вышеизложенное можно выполнить с помощью:

zfile = ZipFile('archive.zip', 'r')
in_mem_fo = TextIOWrapper(zfile.open('datafile.arff'), encoding='ascii')
data = loadarff(in_mem_fo)

Спасибо @Bernhard

person Nihal Sangeeth    schedule 19.03.2019
comment
Спасибо, еще раз, ваш ответ вдохновил меня на другое решение, которое я нахожу еще более элегантным, потому что оно не позволяет сначала помещать все в память: textfile = TextIOWrapper(datafile, encoding='ascii'), а затем data = loadarff( textfile ). Я предлагаю вам добавить что-то подобное в свое решение в качестве редактирования, и я принимаю это, чтобы другие могли его использовать. - person Bernhard Bodenstorfer; 19.03.2019