将JSON列表映射到数据框的熊猫惯用方式

时间:2019-03-04 10:47:40

标签: python json pandas

我有一个从json输入派生的数据集,它的ID喜欢映射到熊猫数据框。可以说与表的各个行相对应的json看起来像这样:

popo = {'foo': 3.14, 'bar': [1, 2, 3]}

也就是说,与表中所需列之一相对应的键中的一个本身就是一个固定长度的列表。

使用pandas.DataFrame.from_dict或pandas.io.json.json_normalize加载此类dict列表,将导致数据帧包含两列,即foo和bar。在这两种情况下,bar都是object类型,这些对象是python列表。

df = pd.DataFrame.from_dict([popo] * 10, orient='index')

在一个完美的世界中,df ['bar']的id像要取消引用到形状[n,3]的数组一样,所以我可以继续写df ['bar']。sum(axis = 1)高效简洁。

但是,不仅我的加载代码没有给出此结果,令我不高兴的是,熊猫似乎不支持1d数组作为数据帧上的序列/列,因此随后也无法手动将其转换为类似格式。

我想念什么吗?感觉这不是一个非常特殊的用例,因此肯定有一种惯用的方式来处理以这种方式构造的数据吗?

编辑:包含python列表的类型对象的列令人讨厌的另一个原因是,羽毛等二进制格式无法处理它。因此,将这种数据结构转换为可以有效序列化的数据结构,可以视为释放在惯用大熊猫中工作的典型好处的另一项要求。

2 个答案:

答案 0 :(得分:1)

要回答我自己的问题,这是我到目前为止找到的最令人满意的答案;通过将所有列表(或可迭代对象)强制转换为枚举dict来预处理我的json派生数据结构:

def list_to_dict(popo):
    if isinstance(popo, dict):
        return {k: list_to_dict(v) for k, v in popo.items()}
    try:
        return {str(i): list_to_dict(v) for i, v in enumerate(popo)}
    except:
        return popo

现在我们有:

list_to_dict(popo) == {'foo': 3.14, 'bar': {'0': 1, '1': 2, '2': 3}}

至少可以让我写这样的东西:

df = pandas.io.json.json_normalize([list_to_dict(popo)] * 10)
df[[f'bar.{i}' for i in range(3)]].sum(axis=1)

不是一个忠实的拥护者,因为这种预处理不是免费提供的,而且访问将不会具有与解决单个连续数组相同的效率...但是也许不适合解决这个问题。

答案 1 :(得分:0)

嗯,这不会让您到达想要去的地方,但是我很乐于尝试,所以我想我会分享的,因为为什么呢?

import pandas as pd

popo = {'foo': 3.14, 'bar': [1, 2, 3]}
df = pd.DataFrame.from_dict([popo]*10)
df

输出:

        bar     foo
0   [1, 2, 3]   3.14
1   [1, 2, 3]   3.14
2   [1, 2, 3]   3.14
3   [1, 2, 3]   3.14
4   [1, 2, 3]   3.14
5   [1, 2, 3]   3.14
6   [1, 2, 3]   3.14
7   [1, 2, 3]   3.14
8   [1, 2, 3]   3.14
9   [1, 2, 3]   3.14

让我们定义一个函数:

def obj_sum(df, column):
   new_col = []
   for i in df[column].tolist():
           new_col.append(sum(i))
   df.drop(column, axis = 1, inplace = True)
   df[column] = new_col
   return df

最后,让我们看看它的作用:

obj_sum(df,'bar')

输出:

    foo     bar
0   3.14    6
1   3.14    6
2   3.14    6
3   3.14    6
4   3.14    6
5   3.14    6
6   3.14    6
7   3.14    6
8   3.14    6
9   3.14    6

好吧,至少我尝试过...