`pandas to_json`和`read_json`

时间:2015-08-26 23:56:18

标签: python json serialization pandas celery

设置

这个问题的基础是我正在使用celeryrabbitmq创建一个分布式HDFStore消息传递应用程序,它将pandas DataFrame传递给分布式进程(和然后写信给HDFStore)。由于jsoncelery接受的task serialization protocols之一,因此to_json()的{​​{1}}和read_json()功能非常适合完成此操作。

所以我的申请:

  • 点击和API并下拉pandas
  • 使用pandas.DataFrame
  • 序列化DataFrame
  • 将序列化值传递给to_json() worker
  • 使用celery方法
  • 在另一侧重新创建DataFrame

问题

我发现当我创建HDFStore时,他们是>比我刚刚进行celery.group循环并且没有序列化/反序列化对象(使用json)大50倍。所以我从中取出for并用一个非常简单的函数重新创建它,重新创建了这个现象:

celery

因此,如果您运行以下功能:

import numpy
import pandas
import random


def test_store_size(n_dfs, f_path):
    wj_store = pandas.HDFStore(f_path + 'from_json.h5', mode = 'w')
    nj_store = pandas.HDFStore(f_path + 'from_dfrm.h5', mode = 'w')

    ticks = []

    for i in numpy.arange(n_dfs):

        tag = _rnd_letters(5)
        print "working on " + str(i)

        index = pandas.DatetimeIndex(
                start = '01/01/2000', 
                periods = 1000, 
                freq = 'b'
        )

        df = pandas.DataFrame(
                numpy.random.rand(len(index), 3), 
                columns = ['a', 'b', 'c'], 
                index = index
        )

        nj_store[tag] = df

        stream = df.to_json(
                orient = 'index', 
                date_format = 'iso',
        )

        #stream = df.to_json(orient = 'values')
        wj_df = pandas.read_json(
                stream, 
                typ = 'frame', 
                orient = 'index', 
                dtype = _dtype_cols(df)
        )

        #wj_df = pandas.read_json(stream, convert_dates = False, orient = 'values')
        wj_store[tag] = wj_df

    wj_store.close()
    nj_store.close()

def _rnd_letters(n_letters):
    """Make random tags for the DataFrames"""
    s = 'abcdefghijklmnopqrstuvwxyz'
    return reduce(lambda x, y: x + y, [random.choice(s) for i in numpy.arange(n_letters)])

def _dtype_cols(df):
    """map the types for dytpes"""
    cols = df.columns.tolist()
    return dict([(col, numpy.float) for col in cols])

以下是In [1]: test_store_size(n_dfs = 10, f_path = '/Users/benjamingross/Desktop/tq-') s:

之间的差异

size-diff

所以21.4 MB比365 KB大59倍!我正在处理1,000个HDFStore s,所以看起来我硬盘上的空间很小(400MB),结果是24 GB,这现在是一个“大数据”问题(不应该是)。

使用DataFrameto_json进行序列化以“行为”(即序列化前后的大小相同)的任何帮助都将非常感激。

我尝试过什么

我已经尝试了read_json中的所有不同参数,包括几乎可以to_json / read_json,但我需要序列化orient = values和{{ 1}},当re-created in very creative ways 仍然最终为原始大小的60倍时。

1 个答案:

答案 0 :(得分:2)

如果您回顾一下程序的输出,您可能会收到如下消息:

In [7]: wj_df.to_hdf('test.h5', 'key')
PerformanceWarning: 
your performance may suffer as PyTables will pickle object types that it cannot
map directly to c-types [inferred_type->unicode,key->axis0] [items->None]

这并不是特别明显,但你的列名被回读为unicode而不是python字符串 - PyTables在python2中处理得不好,所以它又回到了酸洗。一个相对简单的解决方法是将列转换为字符串,就像这样。

wj_df.columns = wj_df.columns.astype(str)

GitHub上存在以下问题。

https://github.com/pydata/pandas/issues/5743