将DataFrame嵌套的列表/数组展平,带有额外的索引键(用于时间序列)

24 浏览
0 Comments

将DataFrame嵌套的列表/数组展平,带有额外的索引键(用于时间序列)

我有一个结构化如下的DataFrame(它是JSON标准化的结果):

mydf
id    colA    colB    ...    colArray
foo   a1      b1             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
bar   a2      b2             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
fooz  a3      b3             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]
barz  a4      b4             [{'date': '...', 'data1': '...', 'data2': 0.1 ...}, ...]

  • date是时间戳
  • colArray中的每个数组长度不同,但具有相同的数组元素结构
  • ['id', 'colA', 'colB']是我想要用作唯一索引的列示例

我想将这些数据转换为时间序列以便使用它们。

我希望得到的输出如下所示:

id    colA    colB    ...    date               data1    data2 ... data n
foo   a1      b1             '1st timestamp'   'flex'   0.1
foo   a1      b1             '...'   
...
foo   a1      b1             'last_timestamp'   
bar   a2      b2             '1st timestamp'   'zorg'
bar   a2      b2             '...'   
...   
bar   a2      b2             'last_timestamp'   
fooz  a3      b3             '...'   
fooz  a3      b3             '...'   
...
fooz  a3      b3             '...'   
等等。

这将使我能够基于类似于[foo, a1, b1]的元组绘制/分析时间序列。

对我来说,这看起来很像展平嵌套的pandas数据框,但是被接受的答案令人沮丧:JSON /字典数据没有真正被处理以生成具有正确数据的DataFrame。


有人对如何实现这一点有什么建议吗?


第一种方法

使用以下代码,它接近我想要的结果:

tmpdf = pd.DataFrame(mydf['colArray'].tolist())
json_normalize(tmpdf[0])

但是有两个问题:

  1. 我丢失了我想要用作唯一标识符的['id', 'colA', 'colB']元组。
  2. 我需要对我的tmpdf的每一行执行此操作。

第二种方法

基于在Pandas中访问嵌套的JSON数据作为数据框

pd.concat(pd.DataFrame.from_dict(tmp_array) for array in mydf['colArray'])

它给我一个展平了的包含所有数组的数据框,正确的列名,但是我丢失了对应的键(['id', 'colA', 'colB'])。

我觉得这是正确的方法,但是我无法想出如何保留索引列(以便我可以通过索引列过滤每个生成的时间序列)。

可惜没有"json_melt"函数

第三种方法

基于这个问题展平嵌套的pandas数据框

我可以保留我的索引列,但是数组元素仍然是JSON并以[0、1、2、...]编入索引。我将在处理变量长度时遇到问题(在较高的列索引值处有很多NA)。


参考文献:

从深层嵌套的JSON创建Pandas DataFrame但是解决方案是基于原始JSON处理,而我想在现有的DataFrame上进行操作。

在Pandas中访问嵌套的JSON数据作为数据框这非常接近我想要的。

展平嵌套的pandas数据框结果看起来像我的第一次尝试,但是基础JSON数据没有真正地被"矩阵化"到数据框中。

一种相对复杂且不令人满意的方法

编辑:这个问题是相同的但在提问时,我无法通过搜索找到它。以供将来参考?

0
0 Comments

问题的出现是因为要将DataFrame中的嵌套列表或数组展开,并使用额外的索引键(用于时间序列)。解决方法是使用字典解析和DataFrame的pop函数来提取原始列,并使用concat函数创建MultiIndex。然后,通过删除第二层级,可以将其与原始DataFrame进行连接。

首先,使用字典解析和pop函数提取原始列并创建MultiIndex:

df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})

另一种方法是使用keys参数:

df = pd.concat([pd.DataFrame(array) for array in mydf.pop('colArray')], keys=mydf.index)

然后,通过重置索引的第二级别,可以将其与原始DataFrame进行连接:

df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)

以上代码的示例输入和输出如下所示:

mydf = pd.DataFrame({'id': ['foo', 'bar', 'fooz', 'barz'], 'colA': ['a1', 'a2', 'a3', 'a4'], 'colB': ['b1', 'b2', 'b3', 'b4'], 'colArray': [[{'date': 's', 'data1': 't', 'data2': 0.1}, {'date': 'd', 'data1': 'r', 'data2': 0.8}], [{'date': 'd', 'data1': 'y', 'data2': 0.1}], [{'date': 'g', 'data1': 'u', 'data2': 0.1}], [{'date': 'h', 'data1': 'i', 'data2': 0.1}]]})
print(mydf)
     id colA colB                                           colArray
0   foo   a1   b1  [{'date': 's', 'data1': 't', 'data2': 0.1}, {'...
1   bar   a2   b2        [{'date': 'd', 'data1': 'y', 'data2': 0.1}]
2  fooz   a3   b3        [{'date': 'g', 'data1': 'u', 'data2': 0.1}]
3  barz   a4   b4        [{'date': 'h', 'data1': 'i', 'data2': 0.1}]
df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()})
print(df)
    data1  data2 date
0 0     t    0.1    s
  1     r    0.8    d
1 0     y    0.1    d
2 0     u    0.1    g
3 0     i    0.1    h
df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True)
print(df)
  data1  data2 date    id colA colB
0     t    0.1    s   foo   a1   b1
1     r    0.8    d   foo   a1   b1
2     y    0.1    d   bar   a2   b2
3     u    0.1    g  fooz   a3   b3
4     i    0.1    h  barz   a4   b4

以上是解决问题的代码和步骤。原始问题中的提问者表示,他对concat函数的keys参数的行为不够清楚。提问者在Pandas文档中查找了相关信息,但仍然没有找到keys参数的解释。提问者表示,他会在问题的参考文献中添加一些相关的Stack Overflow链接。

以上是对问题出现原因和解决方法的整理。

0