2015-03-18 2 views
9

Я помню из своих дней MatLab, используя структурированные массивы, в которых вы могли хранить разные данные как атрибут основной структуры. Что-то вроде:Сохранить дополнительные атрибуты в Pandas Dataframe

a = {} 
a.A = magic(10) 
a.B = magic(50); etc. 

где a.A и a.B полностью отделены друг от друга позволяет хранить различные типы в пределах и работать на них, как хотелось бы. Панда позволяет нам делать что-то подобное, но не совсем то же самое.

Я использую Pandas и хочу хранить атрибуты DataFrame, не помещая его в рамки данных. Это может быть сделано с помощью:

import pandas as pd 

a = pd.DataFrame(data=pd.np.random.randint(0,100,(10,5)),columns=list('ABCED') 

# now store an attribute of <a> 
a.local_tz = 'US/Eastern' 

Теперь локальная временная зона хранится в, но я не могу сохранить этот атрибут, когда я сохраняю dataframe (т.е. после повторной загрузки нет a.local_tz). Есть ли способ сохранить эти атрибуты?

В настоящее время я просто создаю новые столбцы в dataframe, чтобы хранить информацию, такую ​​как часовой пояс, широта, длина и т. Д., Но это кажется немного пустым. Кроме того, когда я делаю анализ данных, я сталкиваюсь с проблемами исключения этих других столбцов.

################## НАЧАТЬ РЕДАКТИРОВАНИЕ ##################

Использование unutbu годов совет, теперь я храню данные в формате h5. Как уже упоминалось, загрузка метаданных в качестве атрибутов фреймворка является рискованной. Однако, поскольку я являюсь создателем этих файлов (и алгоритмов обработки), я могу выбрать, что хранится как метаданные, а что нет. При обработке данных, которые войдут в файлы h5, я хочу сохранить метаданные в словаре, который инициализируется как атрибут моих классов. Я сделал простой класс ввода-вывода для импорта данных h5 и сделал метаданные атрибутами класса. Теперь я могу работать с моими файлами данных без риска потерять метаданные.

class IO(): 
    def __init__(self): 
     self.dtfrmt = 'dummy_str' 

    def h5load(self,filename,update=False): 
     '''h5load loads the stored HDF5 file. Both the dataframe (actual data) and 
     the associated metadata are stored in the H5file 

     NOTE: This does not load "any" H5 
     file, it loads H5 files specifically created to hold dataframe data and 
     metadata. 

     When multi-indexed dataframes are stored in the H5 format the date 
     values (previously initialized with timezone information) lose their 
     timezone localization. Therefore, <h5load> re-localizes the 'DATE' 
     index as UTC. 

     Parameters 
     ---------- 
     filename : string/path 
      path and filename of H5 file to be loaded. H5 file must have been 
      created using <h5store> below. 

     udatedf : boolean True/False 
      default: False 
      If the selected dataframe is to be updated then it is imported 
      slightly different. If update==True, the <metadata> attribute is 
      returned as a dictionary and <data> is returned as a dataframe 
      (i.e., as a stand-alone dictionary with no attributes, and NOT an 
      instance of the IO() class). Otherwise, if False, <metadata> is 
      returned as an attribute of the class instance. 

     Output 
     ------ 
     data : Pandas dataframe with attributes 
      The dataframe contains only the data as collected by the instrument. 
      Any metadata (e.g. timezone, scaling factor, basically anything that 
      is constant throughout the file) is stored as an attribute (e.g. lat 
      is stored as <data.lat>).''' 

     with pd.HDFStore(filename,'r') as store: 
      self.data = store['mydata'] 
      self.metadata = store.get_storer('mydata').attrs.metadata # metadata gets stored as attributes, so no need to make <metadata> an attribute of <self> 

      # put metadata into <data> dataframe as attributes 
      for r in self.metadata: 
       setattr(self,r,self.metadata[r]) 

     # unscale data 
     self.data, self.metadata = unscale(self.data,self.metadata,stringcols=['routine','date']) 

     # when pandas stores multi-index dataframes as H5 files the timezone 
     # initialization is lost. Remake index with timezone initialized: only 
     # for multi-indexed dataframes 
     if isinstance(self.data.index,pd.core.index.MultiIndex): 
      # list index-level names, and identify 'DATE' level 
      namen = self.data.index.names 
      date_lev = namen.index('DATE') 

      # extract index as list and remake tuples with timezone initialized 
      new_index = pd.MultiIndex.tolist(self.data.index) 
      for r in xrange(len(new_index)): 
       tmp = list(new_index[r]) 
       tmp[date_lev] = utc.localize(tmp[date_lev]) 

       new_index[r] = tuple(tmp) 

      # reset multi-index 
      self.data.index = pd.MultiIndex.from_tuples(new_index, names=namen) 


     if update: 
      return self.metadata, self.data 
     else: 
      return self 





    def h5store(self,data, filename, **kwargs): 
     '''h5store stores the dataframe as an HDF5 file. Both the dataframe 
     (actual data) and the associated metadata are stored in the H5file 

     Parameters 
     ---------- 
     data : Pandas dataframe NOT a class instance 
      Must be a dataframe, not a class instance (i.e. cannot be an instance 
      named <data> that has an attribute named <data> (e.g. the Pandas 
      data frame is stored in data.data)). If the dataframe is under 
      data.data then the input variable must be data.data. 

     filename : string/path 
      path and filename of H5 file to be loaded. H5 file must have been 
      created using <h5store> below. 

     **kwargs : dictionary 
      dictionary containing metadata information. 


     Output 
     ------ 
     None: only saves data to file''' 

     with pd.HDFStore(filename,'w') as store: 
      store.put('mydata',data) 
      store.get_storer('mydata').attrs.metadata = kwargs 

H5 файлы затем загружаются через данные = IO(). H5load ('filename.h5') dataframe хранится под data.data я сохранить словарь метаданных под data.metadata и создали индивидуальные атрибуты метаданных (например, data.lat, созданные из data.metadata ['lat']).

Модифицировать метки времени указаны в pytz.utc(). Однако, когда многоиндексированный фрейм данных сохраняется в h5, локализация временного пространства теряется (используя Pandas 15.2), поэтому я исправляю это в IO(). H5load.

+1

Хотя атрибуты могут быть добавлены к ФР они не будут скопированы, даже если вы сделали 'df.copy()', так что вы должны были бы чтобы сохранить это, используя другой метод – EdChum

ответ

20

There is an open issue относительно хранения пользовательских метаданных в NDFrames. Но из-за множества способов функции pandas могут возвращать DataFrames, атрибут _metadata не сохраняется (пока) во всех ситуациях.

На данный момент вам просто нужно сохранить метаданные в вспомогательной переменной.

Существует множество опций для хранения файлов DataFrames + метаданных в файлах, в зависимости от того, какой формат вы хотите использовать - pickle, JSON, HDF5 - все возможности.

Вот как вы можете хранить и загружать DataFrame с помощью метаданных с использованием HDF5. Рецепт для хранения метаданных поступает от Pandas Cookbook.

import numpy as np 
import pandas as pd 

def h5store(filename, df, **kwargs): 
    store = pd.HDFStore(filename) 
    store.put('mydata', df) 
    store.get_storer('mydata').attrs.metadata = kwargs 
    store.close() 

def h5load(store): 
    data = store['mydata'] 
    metadata = store.get_storer('mydata').attrs.metadata 
    return data, metadata 

a = pd.DataFrame(
    data=pd.np.random.randint(0, 100, (10, 5)), columns=list('ABCED')) 

filename = '/tmp/data.h5' 
metadata = dict(local_tz='US/Eastern') 
h5store(filename, a, **metadata) 
with pd.HDFStore(filename) as store: 
    data, metadata = h5load(store) 

print(data) 
#  A B C E D 
# 0 9 20 92 43 25 
# 1 2 64 54 0 63 
# 2 22 42 3 83 81 
# 3 3 71 17 64 53 
# 4 52 10 41 22 43 
# 5 48 85 96 72 88 
# 6 10 47 2 10 78 
# 7 30 80 3 59 16 
# 8 13 52 98 79 65 
# 9 6 93 55 40 3 

print(metadata) 

дает

{'local_tz': 'US/Eastern'} 
+0

Отлично! Фактически, я могу поместить атрибуты обратно в фреймворк данных, когда загружаю H5-файл через: для r в метаданных: setattr (data, r, metadata [r]) – tnknepp

+0

Это, кажется, делает это довольно гибким и именно то, что я хочу. – tnknepp

+0

Да, но будьте осторожны, если вы используете 'setattr', так как если вы вызываете что-то вроде' data.groupby (...). Agg (...) ', возвращаемый DataFrame может потерять метаданные. – unutbu

5

Подход, который я использую, заключается в добавлении дополнительных уровней MultiIndex для хранения дополнительной информации, которую я хочу (я использую столбцы, но любой из них будет работать). Все эти столбцы имеют одинаковые значения для этих дополнительных параметров. Это также полезно, поскольку я могу объединить несколько кадров данных или разделить отдельные столбцы, и эти значения сохраняются.

>>> col=pd.MultiIndex.from_product([['US/Eastern'], ['A', 'B', 'C', 'E', 'D']], names=['local_tz', 'name']) 
>>> a = pd.DataFrame(data=pd.np.random.randint(0,100,(10,5)),columns=col) 
>>> print(a) 
local_tz US/Eastern     
name    A B C E D 
0    38 93 63 24 55 
1    21 25 84 98 62 
2     4 60 78 0 5 
3    26 50 82 89 23 
4    32 70 80 90 1 
5     6 17 8 60 59 
6    95 98 69 19 76 
7    71 90 45 45 40 
8    94 16 44 60 16 
9    53 8 30 4 72 
+0

Спасибо BlackCat. Это будет работать, хотя я стараюсь избегать многоиндексации (возможно, на мой собственный ущерб). – tnknepp

Смежные вопросы