Разреженный фрейм данных Pandas больше на диске, чем плотная версия

Я обнаружил, что разреженные версии фрейма данных на самом деле намного больше при сохранении на диск, чем плотные версии. Что я делаю не так?

test = pd.DataFrame(ones((4,4000)))
test.ix[:,:] = nan
test.ix[0,0] = 47

test.to_hdf('test3', 'df')
test.to_sparse(fill_value=nan).to_hdf('test4', 'df')

test.to_pickle('test5')
test.to_sparse(fill_value=nan).to_pickle('test6')

....
ls -sh test*
200K test3   16M test4  164K test5  516K test6

Использование версии 0.12.0

В конечном итоге я хотел бы эффективно хранить массивы 10 ^ 7 на 60 с плотностью около 10%, а затем вставлять их в кадры данных Pandas и играть с ними.


Изменить: спасибо Джеффу за ответ на исходный вопрос. Дополнительный вопрос: похоже, это дает экономию только при травлении, а не при использовании других форматов, таких как HDF5. Маринование — мой лучший маршрут?

print shape(array_activity) #This is just 0s and 1s
(1020000, 60)

test = pd.DataFrame(array_activity)
test_sparse = test.to_sparse()
print test_sparse.density
0.0832333496732

test.to_hdf('1', 'df')
test_sparse.to_hdf('2', 'df')
test.to_pickle('3')
test_sparse.to_pickle('4')
!ls -sh 1 2 3 4
477M 1  544M 2  477M 3   83M 4

Это данные, которые в виде списка индексов в файле Matlab .mat составляют менее 12 МБ. Мне очень хотелось перевести его в формат HDF5/Pytables, чтобы я мог захватить только определенные индексы (другие файлы намного больше, и их загрузка в память занимает гораздо больше времени), а затем легко делать с ними вещи Pandasy. Может быть, я не иду об этом правильно?


person jeffalstott    schedule 06.02.2014    source источник
comment
добавьте фильтр сжатия, см. здесь: pandas.pydata.org/pandas- документы/dev/io.html#сжатие   -  person Jeff    schedule 07.02.2014
comment
С плотным фреймом данных и complevel=9 и complib='blosc' это снижает нас с 544M до 26M. Намного лучше, но все еще не поспевает за 12M. Попытка сжатия с разреженным кадром данных выдает TypeError: TypeError: cannot properly create the storer for: [_TABLE_MAP] [group->/test_sparse (Group) '',value-><class 'pandas.sparse.frame.SparseDataFrame'>,table->True,append->True,kwargs->{'encoding': None}]   -  person jeffalstott    schedule 07.02.2014
comment
хм .... это неправильный формат; он должен сохранить его с таблицей = False; но это тоже по умолчанию. дай мне взглянуть.   -  person Jeff    schedule 07.02.2014
comment
Вы можете опубликовать кадр, который вы сохранили (в плотном формате все в порядке), сжатый, пожалуйста! скажем, ссылка на дропбокс?   -  person Jeff    schedule 07.02.2014
comment
Вот: dropbox.com/s/d374qoxeua5n3gn/store_compressed.h5   -  person jeffalstott    schedule 07.02.2014


Ответы (1)


вы создаете фрейм, который имеет 4000 столбцов и только 4 строки; sparse обрабатывается построчно, поэтому размеры меняются местами.

In [2]: from numpy import *

In [3]: test = pd.DataFrame(ones((4000,4)))

In [4]: test.ix[:,:] = nan

In [5]: test.ix[0,0] = 47

In [6]: test.to_hdf('test3', 'df')

In [7]: test.to_sparse(fill_value=nan).to_hdf('test4', 'df')

In [8]: test.to_pickle('test5')

In [9]: test.to_sparse(fill_value=nan).to_pickle('test6')

In [11]: !ls -sh test3 test4 test5 test6
164K test3  148K test4  160K test5   36K test6

Следовать за. Предоставленный вами магазин был написан в формате table, и в результате была сохранена плотная версия (Sparse не поддерживается для формата таблицы, который очень гибок и доступен для запросов, см. документы.

Кроме того, вы можете поэкспериментировать с сохранением файла, используя 2 разных представления разреженного формата.

Итак, вот пример сеанса:

df = 
In [1]: df = pd.read_hdf('store_compressed.h5','test')

In [2]: type(df)
Out[2]: pandas.core.frame.DataFrame

In [3]: df.to_sparse(kind='block').to_hdf('test_block.h5','test',mode='w',complib='blosc',complevel=9)

In [4]: df.to_sparse(kind='integer').to_hdf('test_block.h5','test',mode='w',complib='blosc',complevel=9)

In [5]: df.to_sparse(kind='block').to_hdf('test_block.h5','test',mode='w',complib='blosc',complevel=9)

In [6]: df.to_sparse(kind='integer').to_hdf('test_integer.h5','test',mode='w',complib='blosc',complevel=9)

In [7]: df.to_hdf('test_dense_fixed.h5','test',mode='w',complib='blosc',complevel=9)

In [8]: df.to_hdf('test_dense_table.h5','test',mode='w',format='table',complib='blosc',complevel=9)

In [9]: !ls -ltr *.h5
-rwxrwxr-x 1 jreback users 57015522 Feb  6 18:19 store_compressed.h5
-rw-rw-r-- 1 jreback users 30335044 Feb  6 19:01 test_block.h5
-rw-rw-r-- 1 jreback users 28547220 Feb  6 19:02 test_integer.h5
-rw-rw-r-- 1 jreback users 44540381 Feb  6 19:02 test_dense_fixed.h5
-rw-rw-r-- 1 jreback users 57744418 Feb  6 19:03 test_dense_table.h5

IIRC - это ошибка в версии 0.12, поскольку to_hdf не передает все аргументы, поэтому вы, вероятно, захотите использовать:

with get_store('test.h5',mode='w',complib='blosc',complevel=9) as store:
    store.put('test',df)

Они хранятся в основном как коллекция SparseSeries, поэтому, если плотность низкая и несмежная, то она не будет минимальной по размеру. Разреженный набор Pandas лучше справляется с меньшим количеством смежных блоков, хотя YMMV. scipy также предоставляет несколько редких инструментов обработки.

Хотя, ИМХО, в любом случае это довольно тривиальные размеры для файлов HDF5, вы можете обрабатывать гигантское количество строк; и размеры файлов в 10 и 100 гигабайт могут быть легко обработаны (хотя рекомендуется).

Кроме того, вы можете рассмотреть возможность использования формата таблицы, если это действительно таблица поиска, которую вы можете запросить.

person Jeff    schedule 06.02.2014