pandas读取json在MultiIndex上不起作用

12 投票
4 回答
9517 浏览
提问于 2025-04-18 00:42

我正在尝试通过 pd.read_json 来读取一个用 df.to_json() 创建的数据框(dataframe),但是遇到了 ValueError 错误。我觉得这可能和数据框的索引是多重索引(MultiIndex)有关,但我不太确定该怎么处理。

我原来的数据框有55000行,叫做 psi,我通过以下方式创建了 test.json

psi.head().to_json('test.json')

如果你想使用,可以查看 这里,这是 print psi.head().to_string() 的输出。

当我在这小部分数据(5行)上操作时,出现了 ValueError 错误。

! wget --no-check-certificate https://gist.githubusercontent.com/olgabot/9897953/raw/c270d8cf1b736676783cc1372b4f8106810a14c5/test.json
import pandas as pd
pd.read_json('test.json')

这是完整的错误信息:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-1de2f0e65268> in <module>()
      1 get_ipython().system(u' wget https://gist.githubusercontent.com/olgabot/9897953/raw/c270d8cf1b736676783cc1372b4f8106810a14c5/test.json'>)
      2 import pandas as pd
----> 3 pd.read_json('test.json')

/home/obot/virtualenvs/envy/lib/python2.7/site-packages/pandas/io/json.pyc in read_json(path_or_buf, orient, typ, dtype, convert_axes, convert_dates, keep_default_dates, numpy, precise_float, date_unit)
    196         obj = FrameParser(json, orient, dtype, convert_axes, convert_dates,
    197                           keep_default_dates, numpy, precise_float,
--> 198                           date_unit).parse()
    199 
    200     if typ == 'series' or obj is None:

/home/obot/virtualenvs/envy/lib/python2.7/site-packages/pandas/io/json.pyc in parse(self)
    264 
    265         else:
--> 266             self._parse_no_numpy()
    267 
    268         if self.obj is None:

/home/obot/virtualenvs/envy/lib/python2.7/site-packages/pandas/io/json.pyc in _parse_no_numpy(self)
    481         if orient == "columns":
    482             self.obj = DataFrame(
--> 483                 loads(json, precise_float=self.precise_float), dtype=None)
    484         elif orient == "split":
    485             decoded = dict((str(k), v)

ValueError: No ':' found when decoding object value

> /home/obot/virtualenvs/envy/lib/python2.7/site-packages/pandas/io/json.py(483)_parse_no_numpy()
    482             self.obj = DataFrame(
--> 483                 loads(json, precise_float=self.precise_float), dtype=None)
    484         elif orient == "split":

但是当我在整个数据框(55000行)上操作时,我得到了一个 无效指针错误,并且IPython内核崩溃了。有什么想法吗?

编辑:我添加了最初是如何生成这个json的内容。

4 个回答

0

这是我为处理多重索引的 pandas 数据框而做的一个简单粗糙的解决办法,这个方法似乎也适用于索引或列中包含日期时间的情况……不过并没有经过优化!

这里是把数据框编码成 JSON 的代码——我把数据框、索引和列都放进一个字典里,然后生成 JSON。

import json
import pandas as pd

def to_json_multiindex(df):
    dfi = df.index.to_frame()
    dfc = df.columns.to_frame()

    d = dict(
        df = df.to_json(),
        di = dfi.to_json(),
        dc = dfc.to_json()   
    )

    return json.dumps(d)

同时,这里是解码器,它可以读取这个 JSON 字典,并重新创建数据框。

def read_json_multiindex(j):
    d = json.loads(j)

    di=pd.read_json(d['di'])
    if di.shape[1]>1:
        di = pd.MultiIndex.from_frame(di)
    else:
        _name = di.columns[0]
        di = di.index
        di.name = _name
        
        
    dc=pd.read_json(d['dc'])
    if dc.shape[1]>1:
        dc = pd.MultiIndex.from_frame(dc)
    else:
        _name = dc.columns[0]
        dc = dc.index
        dc.name = _name        
    
    df = pd.read_json(d['df']).values
    
    return pd.DataFrame(
        data=df,
        index=di,
        columns=dc,
    )

还有一个测试,针对多重索引的列和索引……看起来可以保持数据框的结构。有几个问题:1)可能效率不高,2)在多重索引中似乎对日期时间不太有效(但在不是多重索引时可以正常工作)。

    df = pd.DataFrame(
        data = [[0,1,2],[2,3,4],[5,6,7]],
        index = pd.MultiIndex.from_tuples(
           (('aa','bb'),('aa','cc'),('bb','cc')
        ),
        names=['AA','BB']),
        columns = pd.MultiIndex.from_tuples(
           (('XX','YY'),('XX','ZZ'),('YY','ZZ')
        ),
        names=['YY','ZZ'])
    )
    
    j = to_json_multiindex(df)
    d = read_json_multiindex(j)
0

如果你想返回一个多重索引的结构:

 # save MultiIndex indexes names 
 indexes_names = df.index.names

 df.reset_index().to_json('dump.json')

 # return back MultiIndex structure:
 loaded_df = pd.read_json('dump.json').set_index(indexes_names)
3

或者你可以直接用一种叫做'table'的方式来写json文件。

df.to_json(path_or_buf='test.json', orient='table')

读取多重索引的json文件

pd.read_json('test.json', orient='table')

10

这个功能现在还没有实现,具体情况可以查看这个链接:https://github.com/pydata/pandas/issues/4889

你可以先重置索引,比如这样:

df.reset_index().to_json(...)

这样就可以正常工作了。

撰写回答