Flatten DataFrame nested list/array with extra index keys (for time series)
我有一个结构如下的DataFrame。 (这是JSON规范化的结果)
1 2 3 4 5 6 7 | 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'] 是我想用作唯一索引的列的示例
我想转换这些数据以便将它们用作时间序列。
我想要的输出将是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 '...' etc. |
这将允许我基于
等元组来绘制/分析时间序列
在我看来,这与Flatten嵌套的pandas数据帧非常相似,但是公认的答案令人沮丧:JSON / dict数据并未真正处理以生成具有正确数据的DataFrame。
有人对如何实现这一目标有任何建议吗?
第一种方法
使用以下内容,该内容与我想要的内容很接近:
1 2 | tmpdf = pd.DataFrame(mydf['colArray'].tolist()) json_normalize(tmpdf[0]) |
但是有2个问题:
第二种方法
基于将嵌套的JSON数据作为pandas中的数据帧进行访问
1 | pd.concat(pd.DataFrame.from_dict(tmp_array) for array in mydf['colArray']) |
它为我提供了一个数据框,其中所有数组都经过展平,正确的列名,但是我丢失了对应的键(
我认为这是正确的方法,但是我无法弄清楚如何保留索引列(以便我可以通过索引列来过滤每个结果时间序列)。
太糟糕了,没有" json_melt"功能
第三种方法
基于此问题,拼合嵌套的pandas数据框。
我可以保留索引列,但数组元素仍为JSON,索引为[0,1,2,...]。我在处理可变长度时会遇到麻烦(对于较大的列index
,它需要很多NA
参考书目:
从深度嵌套的JSON创建Pandas DataFrame,但是该解决方案基于原始JSON处理,而我想在现有的DataFrame
上执行此操作
将嵌套的JSON数据作为Pandas中的数据帧进行访问。这与我想要的非常接近。
平面嵌套的pandas数据框结果看起来像我的第一次尝试,但是底层JSON数据并没有真正"矩阵化"到数据框中。
一种相当复杂且不令人满意的方法
编辑:这个问题是相同的,但是在发问时,我无法通过搜索找到它。供将来参考?
使用字典理解,将
1 | df = pd.concat({k: pd.DataFrame(array) for k, array in mydf.pop('colArray').items()}) |
替代方法是使用参数
1 | df = pd.concat([pd.DataFrame(array) for array in mydf.pop('colArray')], keys=mydf.index) |
然后删除第二个级别,因此可能会删除带有原始
1 | df = df.reset_index(level=1, drop=True).join(mydf).reset_index(drop=True) |
样品:
1 2 3 4 5 6 7 | 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}] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |