熊猫映射json列表到数据框的惯用方法

2024-06-01 09:39:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个从json输入派生的数据集,我想将它映射到一个数据帧。假设对应于表中各行的json如下所示:

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

也就是说,在表中与所需列之一对应的键中,有一个本身就是一个固定长度的列表。你知道吗

加载此类dict的列表,使用pandas.DataFrame.from目录,或熊猫.io.json.json\u normalize,结果是一个包含两列foo和bar的数据帧。在这两种情况下,bar都是object类型的,这些对象是python列表。你知道吗

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

在一个完美的世界中,id喜欢df['bar']去引用一个数组[n,3],这样我就可以继续高效简洁地编写df['bar'].sum(axis=1)之类的东西。你知道吗

但我的加载代码不仅没有给出这个结果,令我不快的是,pandas似乎只支持1d数组作为数据帧上的序列/列,因此我也无法随后手动转换为类似的格式。你知道吗

我错过什么了吗?感觉这不是一个非常奇特的用例,所以肯定有一种惯用的方法来处理以这种方式构造的数据?你知道吗

EDIT:包含python列表的object类型的列令人讨厌的另一个原因是像feather这样的二进制格式无法处理它。因此,将这个数据结构转换成一个可以有效序列化的数据结构可以被认为是另一个要求,以释放在习惯用法中工作的典型好处。你知道吗


Tags: 数据fromjson类型dataframepandasdf列表
2条回答

好吧,这不会让你达到你想去的地方,但我很高兴尝试,所以我想我会分享这个,因为为什么不呢?你知道吗

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

好吧,至少我试过。。。你知道吗

回答我自己的问题,这是迄今为止我找到的最令人满意的答案;通过将所有列表(或iterables)强制转换为枚举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)

不是一个巨大的球迷,因为这种预处理不是免费的,而且访问将不会有同样的效率,作为解决一个单一的连续数组。。。但也许我不得不接受。你知道吗

相关问题 更多 >