2015-06-11 20 views
7

Đây là một khung dữ liệu mẫu:Lưu gấu trúc DataFrame sử dụng h5py cho interoperabilty với các độc giả hdf5 khác

import pandas as pd 

NaN = float('nan') 
ID = [1, 2, 3, 4, 5, 6, 7] 
A = [NaN, NaN, NaN, 0.1, 0.1, 0.1, 0.1] 
B = [0.2, NaN, 0.2, 0.2, 0.2, NaN, NaN] 
C = [NaN, 0.5, 0.5, NaN, 0.5, 0.5, NaN] 
columns = {'A':A, 'B':B, 'C':C} 
df = pd.DataFrame(columns, index=ID) 
df.index.name = 'ID' 
print(df) 

     A B C 
ID    
1 NaN 0.2 NaN 
2 NaN NaN 0.5 
3 NaN 0.2 0.5 
4 0.1 0.2 NaN 
5 0.1 0.2 0.5 
6 0.1 NaN 0.5 
7 0.1 NaN NaN 

Tôi biết rằng gấu trúc có pytables dựa HDFStore, đó là một cách dễ dàng để serialize/deserialize một dữ liệu một cách hiệu quả khung. Nhưng những bộ dữ liệu này không phải là rất dễ dàng để tải trực tiếp bằng cách sử dụng một đầu đọc h5py hoặc matlab. Làm thế nào tôi có thể lưu một khung dữ liệu bằng cách sử dụng h5py, để tôi có thể dễ dàng tải nó trở lại bằng cách sử dụng một đầu đọc hdf5?

Trả lời

6

Các gấu trúcĐịnh dạnglà chuẩn HDF5, chỉ với quy ước về cách diễn giải siêu dữ liệu. Tài liệu là here

In [54]: df.to_hdf('test.h5','df',mode='w',format='table',data_columns=True) 

In [55]: h = h5py.File('test.h5') 

In [56]: h['df']['table'] 
Out[56]: <HDF5 dataset "table": shape (7,), type "|V32"> 

In [64]: h['df']['table'][:] 
Out[64]: 
array([(1, nan, 0.2, nan), (2, nan, nan, 0.5), (3, nan, 0.2, 0.5), 
     (4, 0.1, 0.2, nan), (5, 0.1, 0.2, 0.5), (6, 0.1, nan, 0.5), 
     (7, 0.1, nan, nan)], 
     dtype=[('index', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 


In [57]: h['df']['table'].attrs.items() 
Out[57]: 
[(u'CLASS', 'TABLE'), 
(u'VERSION', '2.7'), 
(u'TITLE', ''), 
(u'FIELD_0_NAME', 'index'), 
(u'FIELD_1_NAME', 'A'), 
(u'FIELD_2_NAME', 'B'), 
(u'FIELD_3_NAME', 'C'), 
(u'FIELD_0_FILL', 0), 
(u'FIELD_1_FILL', 0.0), 
(u'FIELD_2_FILL', 0.0), 
(u'FIELD_3_FILL', 0.0), 
(u'index_kind', 'integer'), 
(u'A_kind', "(lp1\nS'A'\na."), 
(u'A_meta', 'N.'), 
(u'A_dtype', 'float64'), 
(u'B_kind', "(lp1\nS'B'\na."), 
(u'B_meta', 'N.'), 
(u'B_dtype', 'float64'), 
(u'C_kind', "(lp1\nS'C'\na."), 
(u'C_meta', 'N.'), 
(u'C_dtype', 'float64'), 
(u'NROWS', 7)] 

In [58]: h.close() 

Dữ liệu sẽ hoàn toàn có thể đọc được trong bất kỳ đầu đọc HDF5 nào. Một số siêu dữ liệu được ngâm, vì vậy phải cẩn thận.

+1

Tôi đã sử dụng các đối số mặc định của định dạng 'cố định' mà không thiết lập data_columns, trong đó có một bộ dữ liệu hdf5 tìm khác nhau và trừu tượng hơn khi sử dụng format = 'table', data_columns = True. Đối với tài liệu gấu trúc về khả năng tương thích bên ngoài với HDFStore, tôi đọc lại nó và sẽ không bao giờ thấy câu trả lời của bạn từ mô tả đó. Cảm ơn câu trả lời rõ ràng và hữu ích của bạn! – Phil

+0

nếu bạn muốn thêm một số bình luận thêm vào ví dụ tài liệu đó sẽ là awseome! xin gửi yêu cầu kéo – Jeff

+0

Tôi muốn thêm vào ví dụ về tài liệu, nhưng tôi đang gặp sự cố. Xem http://stackoverflow.com/questions/30807270 để biết câu hỏi tiếp theo. – Phil

7

Đây là cách tiếp cận của tôi để giải quyết vấn đề này. Tôi hy vọng một người khác có giải pháp tốt hơn hoặc cách tiếp cận của tôi là hữu ích cho người khác.

Đầu tiên, hãy xác định hàm để tạo mảng cấu trúc có khối u (không phải mảng bản ghi) từ khung dữ liệu gấu trúc.

import numpy as np 
def df_to_sarray(df): 
    """ 
    Convert a pandas DataFrame object to a numpy structured array. 
    This is functionally equivalent to but more efficient than 
    np.array(df.to_array()) 

    :param df: the data frame to convert 
    :return: a numpy structured array representation of df 
    """ 

    v = df.values 
    cols = df.columns 
    types = [(cols[i].encode(), df[k].dtype.type) for (i, k) in enumerate(cols)] 
    dtype = np.dtype(types) 
    z = np.zeros(v.shape[0], dtype) 
    for (i, k) in enumerate(z.dtype.names): 
     z[k] = v[:, i] 
    return z 

để tạo khung dữ liệu mới bao gồm chỉ mục như một phần dữ liệu của nó. Chuyển đổi khung dữ liệu đó thành một mảng cấu trúc.

sa = df_to_sarray(df.reset_index()) 
sa 

array([(1L, nan, 0.2, nan), (2L, nan, nan, 0.5), (3L, nan, 0.2, 0.5), 
     (4L, 0.1, 0.2, nan), (5L, 0.1, 0.2, 0.5), (6L, 0.1, nan, 0.5), 
     (7L, 0.1, nan, nan)], 
     dtype=[('ID', '<i8'), ('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 

Lưu mảng có cấu trúc đó vào tệp hdf5.

import h5py 
with h5py.File('mydata.h5', 'w') as hf: 
      hf['df'] = sa 

Nạp h5 dataset

with h5py.File('mydata.h5') as hf: 
      sa2 = hf['df'][:] 

Giải nén cột ID và xóa nó khỏi SA2

ID = sa2['ID'] 
sa2 = nprec.drop_fields(sa2, 'ID') 

khung dữ liệu Make với chỉ số ID sử dụng SA2

df2 = pd.DataFrame(sa2, index=ID) 
df2.index.name = 'ID' 

print(df2) 

     A B C 
ID    
1 NaN 0.2 NaN 
2 NaN NaN 0.5 
3 NaN 0.2 0.5 
4 0.1 0.2 NaN 
5 0.1 0.2 0.5 
6 0.1 NaN 0.5 
7 0.1 NaN NaN 
+1

Câu trả lời khá hay và chính xác những gì tôi đang tìm kiếm.Khi tôi sử dụng tiêu chuẩn 'pandas' để tạo tệp hdf5, nó tạo tệp hdf5 với nhiều bảng, điều này không thực sự thuận tiện, vì vậy tôi thích làm điều đó với' h5py' hơn nhưng để xử lý dữ liệu gấu trúc. Nếu chỉ có tôi có thể đặt nhiều hơn 1 upvote cho câu trả lời của bạn tôi muốn làm điều đó, cảm ơn! ;) – silgon

+0

Cảm ơn sự khích lệ và thăng hoa! Câu trả lời của tôi là cấp thấp hơn và được tùy biến hơn Jeff, có câu trả lời tôi chấp nhận vì nó không yêu cầu mã tùy chỉnh và phù hợp với trường hợp sử dụng của tôi tốt hơn phương pháp tùy chỉnh này. Tuy nhiên, tôi rất vui vì mã này hữu ích cho bạn. – Phil

1

Trong trường hợp nó hữu ích cho bất kỳ ai, tôi lấy this post từ GuillaumePhil và thay đổi một chút cho nhu cầu của tôi với sự giúp đỡ của ankostis. Chúng tôi đọc DataFrame gấu trúc từ tệp CSV.

Chủ yếu là tôi đã điều chỉnh nó cho Strings, bởi vì bạn không thể lưu trữ một đối tượng trong tệp HDF5 (tôi tin). Trước hết, hãy kiểm tra xem các loại cột nào là numpy objects. Sau đó kiểm tra xem đó là chiều dài dài nhất của cột đó và sửa cột đó thành một Chuỗi có độ dài đó. Phần còn lại khá giống với bài viết khác.

def df_to_sarray(df): 
    """ 
    Convert a pandas DataFrame object to a numpy structured array. 
    Also, for every column of a str type, convert it into 
    a 'bytes' str literal of length = max(len(col)). 

    :param df: the data frame to convert 
    :return: a numpy structured array representation of df 
    """ 

    def make_col_type(col_type, col): 
     try: 
      if 'numpy.object_' in str(col_type.type): 
       maxlens = col.dropna().str.len() 
       if maxlens.any(): 
        maxlen = maxlens.max().astype(int) 
        col_type = ('S%s' % maxlen, 1) 
       else: 
        col_type = 'f2' 
      return col.name, col_type 
     except: 
      print(col.name, col_type, col_type.type, type(col)) 
      raise 

    v = df.values    
    types = df.dtypes 
    numpy_struct_types = [make_col_type(types[col], df.loc[:, col]) for col in df.columns] 
    dtype = np.dtype(numpy_struct_types) 
    z = np.zeros(v.shape[0], dtype) 
    for (i, k) in enumerate(z.dtype.names): 
     # This is in case you have problems with the encoding, remove the if branch if not 
     try: 
      if dtype[i].str.startswith('|S'): 
       z[k] = df[k].str.encode('latin').astype('S') 
      else: 
       z[k] = v[:, i] 
     except: 
      print(k, v[:, i]) 
      raise 

    return z, dtype 

Vì vậy, các quy trình làm việc sẽ là:

import h5py 
import pandas as pd 

# Read a CSV file 
# Here we assume col_dtypes is a dictionary that contains the dtypes of the columns 
df = pd.read_table('./data.csv', sep='\t', dtype=col_dtypes) 
# Transform the DataFrame into a structured numpy array and get the dtype 
sa, saType = df_to_sarray(df) 

# Open/create the HDF5 file 
f = h5py.File('test.hdf5', 'a') 
# Save the structured array 
f.create_dataset('someData', data=sa, dtype=saType) 
# Retrieve it and check it is ok when you transform it into a pandas DataFrame 
sa2 = f['someData'][:] 
df2 = pd.DataFrame(sa2) 
print(df2.head()) 
f.close() 

Ngoài ra, bằng cách này bạn có thể nhìn thấy nó từ HDFView ngay cả khi sử dụng gzip nén ví dụ.

+0

Giải pháp tốt. Nó hoạt động với tôi trên Python3. –

Các vấn đề liên quan