【问题标题】:Flatten DataFrame nested list/array with extra index keys (for time series)使用额外的索引键展平 DataFrame 嵌套列表/数组(用于时间序列)
【发布时间】:2019-06-29 11:04:09
【问题描述】:

我有一个结构如下的 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             '...'   
etc.

这将允许我根据 [foo, a1, b1] 等元组绘制/分析时间序列

对我来说,这看起来与Flatten nested pandas dataframe 非常相似,但接受的答案令人沮丧:JSON/dict 数据并未真正处理以生成具有正确数据的 DataFrame。


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


第一种方法

使用以下,接近我想要的:

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

但是有两个问题:

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

第二种方法

基于Accessing nested JSON data as dataframes in Pandas

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

它给了我一个数据框,其中我的所有数组都被展平,列名正确,但我丢失了相应的键 (['id', 'colA', 'colB'])。 我觉得这是正确的方法,但我不知道如何保留索引列(以便我可以通过索引列过滤每个结果时间序列)。

可惜没有“json_melt”功能

第三种方法

基于这个问题Flatten nested pandas dataframe。 我可以保留我的索引列,但数组元素仍然在 JSON 中并且索引为 [0, 1, 2, ...]。我将无法处理可变长度(列索引的较高值有很多 NA


参考书目: Create a Pandas DataFrame from deeply nested JSON 但是解决方案是基于原始的 JSON 处理,而我想在现有的 DataFrame 上这样做

Accessing nested JSON data as dataframes in Pandas这和我想要的很接近。

Flatten nested pandas dataframe 结果看起来像是我的第一次尝试,但底层 JSON 数据并没有真正“矩阵化”到数据帧中。

A rather complex and not satisfaying approach

编辑:This question is the same 但在询问时,我无法通过搜索找到它。供日后参考?

【问题讨论】:

    标签: python json pandas normalization


    【解决方案1】:

    将字典理解与pop 用于提取原始列,concat 用于MulltiIndex

    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)
    

    然后删除第二级,所以可能join 与原始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=... param 的魔力。我的意思是,我知道pop 返回一个保留索引的新 DF。然后concat 部分发挥了作用(引用 concat doc:如果传递了 dict,则排序的键将用作键参数,除非传递,在这种情况下将选择值)。如果我不得不用我自己的话说出来:使用 [comprehension + keys=],或者使用 [.pop().items()] 提供给concat 的正确数据让魔法发生?
    • 呃,我手头有所有需要的英特尔(第一部分),但无法从文档中弄清楚...我得到了 reset_index 机制,但会搜索很长时间是时候找到它了。
    • 我再次阅读了 Pandas 文档(pandas.pydata.org/pandas-docs/stable/user_guide/merging.htmlpandas.pydata.org/pandas-docs/stable/reference/api/…),仍然没有找到对 keys= 参数行为的非常清楚的解释。无论如何,我可能错过了它。
    • @LoneWanderer 我认为最好解释一下this Q/A
    • 该死的stackoverflow.com/questions/22676081/…stackoverflow.com/questions/49671693/… 已经解决了这个问题......不敢相信我没有找到他们!我会把它们添加到书目中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    相关资源
    最近更新 更多