【问题标题】:Merge Many json strings with python pandas inputs将许多 json 字符串与 python pandas 输入合并
【发布时间】:2015-03-20 14:46:50
【问题描述】:

总结

我创建了由pandas 对象(如DataFrames 和Panels 等)组成的数据对象。我希望将这些对象序列化为json,速度是首要考虑因素。

使用pandas.Panel 的示例

比如说我有一个这样的面板:

In [54]: panel = pandas.Panel( 
             numpy.random.randn(5, 100, 10), 
             items = ['a', 'b', 'c', 'd', 'e'], 
             major_axis = pandas.DatetimeIndex(start = '01/01/2000', 
                                               freq = 'b', 
                                               periods = 100
             ), 
             minor_axis = ['z', 'y', 'x', 'v', 'u', 't', 's', 'r', 'q', 'o']
          )
In [64]: panel
Out[64]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 5 (items) x 100 (major_axis) x 10 (minor_axis)
Items axis: a to e
Major_axis axis: 2000-01-03 00:00:00 to 2000-05-19 00:00:00
Minor_axis axis: z to o

我想把这个panel 变成扁平的json

注意:我正在对更复杂的对象执行此操作,但循环键和为每个键生成 json 数据的整体逻辑是相同的

我可以像这样写一个又快又脏的panel_to_json()函数:

def panel_to_json(panel):

    d = {'__type__' : 'panel'}
    for item in panel.items:
        tmp = panel.loc[item ,: , :].to_json()
        d[item] = eval(tmp)
    return json.dumps(d)

In [58]: tmp = panel_to_json(panel)
In [59]: tmp[:100]
Out[59]: '{"a": {"q": {"948931200000": -0.5586319118, "951955200000": 0.6820748888, "949363200000": -0.0153867'

这让我得到了正确的结果,问题是eval 的使用非常成本很高。例如,如果我删除 eval 并在此处处理由 panel_no_eval_to_json 函数产生的少量 \\

def panel_no_eval_to_json(panel):
    d = {'__type__' : 'panel'}
    for item in panel.items:
        d[item] = panel.loc[item ,: , :].to_json()
    return json.dumps(d)

In [60]: tmp = panel_no_eval_to_json(panel)

In [61]: tmp[:100]
Out[61]: '{"a": "{\\"z\\":{\\"946857600000\\":1.0233515965,\\"946944000000\\":-1.1333560575,\\"947030400000\\":-0.0072'

速度差异很大,查看他们的%timeit 值!!:

In [62]: %timeit panel_no_eval_to_json(panel)
100 loops, best of 3: 3.55 ms per loop

In [63]: %timeit panel_to_json(panel)
10 loops, best of 3: 41.1 ms per loop

最终目标

所以我的最终目标是遍历Panel(或我的对象,具有不同的键/属性,其中许多是PanelDataFrames),并合并json通过调用 to_json() 创建的流到聚合的 json 流(这实际上是我的数据对象的扁平化数据表示),就像使用上面的 panel_to_json 函数执行的一样(witheval)。

我的主要目标是:

  1. 利用现有的pandas to_json 功能
  2. 利用加速和现有库(我可以编写自己的 json_stream_merger,但显然这已经完成了,对吧?)

【问题讨论】:

    标签: python json serialization pandas concat


    【解决方案1】:

    最后,最快的方法是写一个简单的字符串concat-er。以下是两个最佳解决方案,(一个由@Skorp 提供))以及它们各自的%timeit 图形形式的时间

    方法一、字符串合并

    def panel_to_json_string(panel):
        def __merge_stream(key, stream):
            return '"' + key + '"' + ': ' + stream + ', '
    
        try:
            stream = '{ "__type__": "panel", '
            for item in panel.items:
                stream += __merge_stream(item, panel.loc[item, :, :].to_json()) 
    
            # take out extra last comma
            stream = stream[:-2] 
    
            # add the final paren
            stream += '}'
        except:
            logging.exception('Panel Encoding did not work')
    return stream
    

    方法 2. 加载-转储

    def panel_to_json_loads(panel):
        try:
            d = {'__type__' : 'panel'}
    
            for item in panel.items:
                d[item] = json.loads(panel.loc[item ,: , :].to_json())
            return json.dumps(d)
        except:
            logging.exception('Panel Encoding did not work')
    

    问题设置

    import timeit
    import pandas
    import numpy
    
    setup = ("import strat_check.io as sio; import pandas; import numpy;" 
         "panel = pandas.Panel(numpy.random.randn(5, {0}, 4), "
         "items = ['a', 'b', 'c', 'd', 'e'], " 
         "major_axis = pandas.DatetimeIndex(start = '01/01/1990',"
                                            "freq = 's', "
                                            "periods = {0}), "
                                            "minor_axis = numpy.arange(4))")
    
    vals = [10, 100, 1000, 10000, 100000]
    
    d = {'string-merge': [], 
         'loads-dumps': []
         }
    
    for n in vals:
        number = 10
    
    d['string-merge'].append(
        timeit.timeit(stmt = 'panel_to_json_string(panel)', 
                      setup = setup.format(n), 
                      number = number)
    )
    
    d['loads-dumps'].append(
        timeit.timeit(stmt = 'sio.panel_to_json_loads(panel)', 
                      setup = setup.format(n), 
                      number = number)
    )
    

    【讨论】:

      【解决方案2】:

      如果您需要做的就是摆脱“\\”,您可以使用
      .str.strip("\\") #or

      `.str.replace("\\","") `
      

      您应该阅读字符串方法、向量化字符串方法和正则表达式。这是熊猫特定的信息链接:

      http://pandas.pydata.org/pandas-docs/stable/text.html#text-string-methods

      【讨论】:

      • 感谢您的回答@Skorp。从我的目标和目的来看,您可以看到我正在尝试“将通过调用 to_json() 创建的 json 流合并到一个聚合的 json 流中”我打算简单地使用 replace("\\", "") 并没有完成我的任务正在寻找,但我认为这从我的目标和目标中很清楚。感谢您的回复!
      • 你考虑过合并数据帧然后“to_json”那个帧吗?你可以使用 pd.merge(masterdf, panel[item], how="outer")。只是一个想法,我没有使用面板,所以不确定 json 表示是否准确。您也可以尝试 pd.concat([masterdf, panel[item]], axis = 1, keys =[list(masterdf.columns, item) ,然后将其转换为 json
      • pd.concat([masterdf, panel[item]], axis = 1, keys =[list(masterdf.columns.values), item])
      • 仅供参考@Skorp,json_string.replace("\\", "") 不会产生有效的json 字符串,仅供参考。如果您删除此答案,然后将最终的loads(df.to_json()) 作为您的答案,我会给您一个支持,因为它是该问题的第二快解决方案。
      【解决方案3】:

      您是否考虑过合并数据帧然后“to_json”该帧?你可以使用 pd.merge(masterdf, panel[item], how="outer")。只是一个想法,我没有使用面板,所以不确定 json 表示是否准确。您也可以尝试在循环中使用它。您还应该考虑使用 iteritems() 方法。

      masterdf = pd.concat([masterdf, panel[item]], axis = 1, keys =[list(masterdf.columns.values), item]) and then make that into a json.  
      

      你甚至可以做一些更性感的事情,比如:

      pd.concat([lamda x: x for panel.items], axis = 1, keys = list(panel.keys())).to_json
      

      【讨论】:

      • 请参阅 NOTE 部分“我正在对更复杂的对象执行此操作,但循环键和为每个键生成 json 数据的整体逻辑是相同的, " 所以(key, frame) / (key, series)` / (key, frame) 是我正在使用的结构的一部分(因此不能只是pandas.concat 一切
      • 你试过用 json.loads(tmp) 代替 eval 吗?
      猜你喜欢
      • 1970-01-01
      • 2018-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-22
      • 1970-01-01
      • 2020-04-12
      相关资源
      最近更新 更多