Сохранение в файле массива или 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 во многих отраслях и дисциплинах, чтобы продемонстрировать множество функций и использовать ноутбуки. Он может расширить ваши горизонты, не пытаясь разработать способ маркировки простых фрагментов текста для ваших данных.