Сохранение в файле массива или DataFrame вместе с другой информацией
Статистическое программное обеспечение Stata позволяет сохранять короткие текстовые фрагменты в наборе данных. Это достигается либо с использованием notes
и/или characteristics
.
Это функция, которая имеет большое значение для меня, поскольку она позволяет мне сохранять разнообразную информацию, начиная от напоминаний и списков дел до информации о том, как я генерировал данные, или даже в том, какой метод оценки для конкретной переменной был.
Теперь я пытаюсь придумать аналогичную функциональность в Python 3.6. До сих пор я смотрел онлайн и консультировался с несколькими сообщениями, которые, однако, не совсем соответствуют тому, что я хочу делать.
Несколько справочных сообщений включают:
Для небольшого массива NumPy
я пришел к выводу, что комбинация функции numpy.savez()
и dictionary
может адекватно хранить всю соответствующую информацию в одном файле.
Например:
a = np.array([[2,4],[6,8],[10,12]])
d = {"first": 1, "second": "two", "third": 3}
np.savez(whatever_name.npz, a=a, d=d)
data = np.load(whatever_name.npz)
arr = data['a']
dic = data['d'].tolist()
Однако остается вопрос:
Есть ли лучшие способы потенциально включить другие части информации в файл, содержащий массив NumPy
или (большой) Pandas
DataFrame
?
Мне особенно интересно узнать о каких-либо плюсах и минусах любых предложений, которые вы можете иметь с примерами. Чем меньше зависимостей, тем лучше.
Ответы
Ответ 1
Есть много вариантов. Я буду обсуждать только HDF5, потому что у меня есть опыт использования этого формата.
Преимущества: Portable (может быть прочитан за пределами Python), встроенное сжатие, недоступность памяти, поддержка метаданных.
Недостатки: Опора на один низкоуровневый API C, возможность повреждения данных как одного файла, удаление данных не уменьшает размер автоматически.
По моему опыту, для повышения производительности и мобильности, не используйте pyTables
/HDFStore
для хранения числовых данных. Вместо этого вы можете использовать интуитивно понятный интерфейс, предоставляемый h5py
.
Хранить массив
import h5py, numpy as np
arr = np.random.randint(0, 10, (1000, 1000))
f = h5py.File('file.h5', 'w', libver='latest') # use 'latest' for performance
dset = f.create_dataset('array', shape=(1000, 1000), data=arr, chunks=(100, 100)
compression='gzip', compression_opts=9)
Сжатие и поршень
Существует множество вариантов сжатия, например, blosc
и lzf
являются хорошим выбором для производительности сжатия и декомпрессии. Примечание. gzip
является родным; другие фильтры сжатия могут не поставляться по умолчанию при установке HDF5.
Chunking - это еще один вариант, который при согласовании с тем, как вы читаете данные из памяти, может значительно повысить производительность.
Добавить некоторые атрибуты
dset.attrs['Description'] = 'Some text snippet'
dset.attrs['RowIndexArray'] = np.arange(1000)
Сохранить словарь
for k, v in d.items():
f.create_dataset('dictgroup/'+str(k), data=v)
Доступ из памяти
dictionary = f['dictgroup']
res = dictionary['my_key']
Нет никакой замены для чтения документации h5py
, которая предоставляет большую часть C API, но вы должны видеть из вышеизложенного, существует значительная гибкость.
Ответ 2
Я согласен с JPP в том, что хранение hdf5 является хорошим вариантом. Разница между его решением и моим мином - это использование ячеек памяти Pandas вместо массивов numpy. Я предпочитаю структуру данных, так как это позволяет использовать смешанные типы, многоуровневое индексирование (даже индексирование даты и времени, что очень важно для моей работы) и маркировка столбцов, что помогает мне помнить, как организованы разные наборы данных. Кроме того, Pandas обеспечивает множество встроенных функциональных возможностей (как numpy). Еще одно преимущество использования Pandas заключается в создании встроенного hdf-создателя (например, pandas.DataFrame.to_hdf), который я нахожу удобным
При хранении данных в h5 у вас есть возможность хранить словарь метаданных, что может быть вашими заметками для себя или фактическими метаданными, которые не нужно хранить в фрейме данных (я также использую это для установки флагов, например, {'is_agl': True, 'scale_factor': 100, 'already_corrected': False и т.д. В этом отношении нет никакой разницы между использованием массива numpy и фрейма данных. Для полного решения см. мой первоначальный вопрос и решение здесь.
Ответ 3
Практический способ может заключаться в встраивании метаданных непосредственно в массив Numpy. Преимущество состоит в том, что, как вы хотите, нет никакой дополнительной зависимости, и это очень простое использование в коде. Однако это не полностью отвечает на ваш вопрос, потому что вам по-прежнему нужен механизм для сохранения данных, и я бы рекомендовал использовать решение jpp с использованием HDF5.
Чтобы включить метаданные в ndarray
, в документации есть пример. Вы в основном должны подклассы в ndarray
и добавить поле info
или metadata
или любой другой.
Это даст (код из приведенной выше ссылки)
import numpy as np
class ArrayWithInfo(np.ndarray):
def __new__(cls, input_array, info=None):
# Input array is an already formed ndarray instance
# We first cast to be our class type
obj = np.asarray(input_array).view(cls)
# add the new attribute to the created instance
obj.info = info
# Finally, we must return the newly created object:
return obj
def __array_finalize__(self, obj):
# see InfoArray.__array_finalize__ for comments
if obj is None: return
self.info = getattr(obj, 'info', None)
Чтобы сохранить данные через numpy
, вам необходимо перегрузить функцию write
или использовать другое решение.
Ответ 4
Ответ jpp довольно всеобъемлющий, просто хотел упомянуть, что паркет pandas v22 очень удобен и быстр, и почти без каких-либо недостатков vs csv (допустим, возможно, перерыв на кофе).
читать паркет
написать паркет
В момент написания вам также понадобится
pip install pyarrow
Что касается добавления информации, у вас есть метаданные, которые привязаны к данным
import pyarrow as pa
import pyarrow.parquet as pq
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.normal(size=(1000, 10)))
tab = pa.Table.from_pandas(df)
tab = tab.replace_schema_metadata({'here' : 'it is'})
pq.write_table(tab, 'where_is_it.parq')
pq.read_table('where_is_it.parq')
Ответ 5
Это интересный вопрос, хотя я считаю очень открытым.
Текстовые фрагменты
Для текстовых фрагментов, которые имеют буквальные заметки (как в, а не в коде, а не данные), я действительно не знаю, каков ваш вариант использования, но я не понимаю, почему я отклоняюсь от использования обычного with open() as f:...
Небольшие коллекции различных данных
Конечно, ваш npz
работает. На самом деле то, что вы делаете, очень похоже на создание словаря со всем, что вы хотите сохранить и проследить этот словарь.
См. Здесь для обсуждения различий между pickle и npz (но в основном, npz оптимизирован для массивов numpy).
Лично я бы сказал, что если вы не храните массивы Numpy, я бы использовал pickle и даже реализовал бы быстрый класс MyNotes
который в основном является словарем для сохранения материала в нем, с некоторыми дополнительными функциями, которые могут вам понадобиться.
Сбор больших объектов
Для действительно больших np.arrays или dataframes, которые я использовал до формата HDF5. Хорошо, что он уже встроен в панды, и вы можете напрямую df.to_hdf5()
. Это необходимо под pytables
-installation должно быть довольно безболезненным с пипсом или conda-, но напрямую с помощью pytables может быть гораздо больнее.
Опять же, эта идея очень похожа: вы создаете HDFStore, который является довольно большим словарем, в котором вы можете хранить (почти любые) объекты. Преимущество состоит в том, что формат использует пространство более разумно, используя повторение аналогичных значений. Когда я использовал его для хранения некоторых ~ 2 Гбайт данных, он смог уменьшить его почти на полный порядок (~ 250 МБ).
Последний игрок: feather
Feather
- это проект, созданный Уэсом Маккинни и Хэдли Викхем поверх структуры Apache Arrow, для сохранения данных в двоичном формате, который является агностиком языка (и поэтому вы можете читать R и Python). Тем не менее, он все еще находится в разработке, и в прошлый раз, когда я проверил, они не поощряли его использовать для долгосрочного хранения (поскольку спецификация может измениться в будущих версиях), а не просто использовать его для связи между R и Python.
Оба они только что запустили Ursalabs, буквально всего несколько недель назад, которые будут продолжать развивать эту и подобные инициативы.
Ответ 6
Вы указали в качестве причин этого вопроса:
... он позволяет мне сохранять разнообразную информацию, начиная от напоминаний и списков дел, до информации о том, как я создал данные, или даже о том, какой метод оценки для конкретной переменной был.
Могу ли я предложить другую парадигму, чем предложенная Stata? Заметки и характеристики кажутся очень ограниченными и ограничиваются только текстом. Вместо этого вы должны использовать Jupyter Notebook для своих проектов исследований и анализа данных. Он предоставляет такую богатую среду для документирования вашего рабочего процесса и сбора деталей, мыслей и идей, когда вы проводите анализ и исследования. Его можно легко разделить, и он готов к презентации.
Вот галерея интересных Jupyter Notebooks во многих отраслях и дисциплинах, чтобы продемонстрировать множество функций и использовать ноутбуки. Он может расширить ваши горизонты, не пытаясь разработать способ маркировки простых фрагментов текста для ваших данных.