【问题标题】:Unfold a nested dictionary with lists into a pandas DataFrame将带有列表的嵌套字典展开为 pandas DataFrame
【发布时间】:2018-05-30 02:54:42
【问题描述】:

我有一个嵌套字典,其中子字典使用列表:

nested_dict = {'string1': {69: [1231, 232], 67:[682, 12], 65: [1, 1]}, 
    `string2` :{28672: [82, 23], 22736:[82, 93, 1102, 102], 19423: [64, 23]}, ... }

子词典列表中至少有两个元素,但可能还有更多。

我想把这个字典“展开”成一个 pandas DataFrame,一列用于第一个字典键(例如'string1','string2',..),一列用于子目录键,一列列表中的第一个项目,下一个项目的一列,依此类推。

下面是输出的样子:

col1       col2    col3     col4    col5    col6
string1    69      1231     232
string1    67      682      12
string1    65      1        1
string2    28672   82       23
string2    22736   82       93      1102    102
string2    19423   64       23

当然,我尝试使用pd.DataFrame.from_dict

new_df = pd.DataFrame.from_dict({(i,j): nested_dict[i][j] 
                           for i in nested_dict.keys() 
                           for j in nested_dict[i].keys()
                           ... 

现在我被困住了。并且存在很多问题:

  1. 如何解析字符串(即nested_dict[i].values()),使每个元素都是一个新的 pandas DataFrame 列?

  2. 上面实际上不会为每个字段创建一列

  3. 以上内容不会用元素填充列,例如string1 应该在子目录键值对的每一行中。 (对于col5col6,我可以用零填充NA)

  4. 我不确定如何正确命名这些列。

【问题讨论】:

    标签: python pandas dictionary


    【解决方案1】:

    这是一种使用递归生成器展开嵌套字典的方法。它不会假设您恰好有两个级别,而是继续展开每个 dict,直到它遇到 list

    nested_dict = {
        'string1': {69: [1231, 232], 67:[682, 12], 65: [1, 1]}, 
        'string2' :{28672: [82, 23], 22736:[82, 93, 1102, 102], 19423: [64, 23]},
        'string3': [101, 102]}
    
    def unroll(data):
        if isinstance(data, dict):
            for key, value in data.items():
                # Recursively unroll the next level and prepend the key to each row.
                for row in unroll(value):
                    yield [key] + row
        if isinstance(data, list):
            # This is the bottom of the structure (defines exactly one row).
            yield data
    
    df = pd.DataFrame(list(unroll(nested_dict)))
    

    因为unroll 生成列表而不是字典,所以列将以数字命名(在本例中为从 0 到 5)。所以你需要使用rename来获取你想要的列标签:

    df.rename(columns=lambda i: 'col{}'.format(i+1))
    

    这将返回以下结果(请注意,附加的 string3 条目也已展开)。

          col1   col2  col3   col4    col5   col6
    0  string1     69  1231  232.0     NaN    NaN
    1  string1     67   682   12.0     NaN    NaN
    2  string1     65     1    1.0     NaN    NaN
    3  string2  28672    82   23.0     NaN    NaN
    4  string2  22736    82   93.0  1102.0  102.0
    5  string2  19423    64   23.0     NaN    NaN
    6  string3    101   102    NaN     NaN    NaN
    

    【讨论】:

      【解决方案2】:

      这应该会为您提供您正在寻找的结果,尽管它可能不是最优雅的解决方案。可能有更好的(更多 pandas 方式)来做到这一点。

      我解析了您的嵌套字典并构建了一个字典列表(每行一个)。

      # some sample input
      nested_dict = {
          'string1': {69: [1231, 232], 67:[682, 12], 65: [1, 1]}, 
          'string2' :{28672: [82, 23], 22736:[82, 93, 1102, 102], 19423: [64, 23]},
          'string3' :{28673: [83, 24], 22737:[83, 94, 1103, 103], 19424: [65, 24]}
      }
      
      # new list is what we will use to hold each row
      new_list = []
      for k1 in nested_dict:
          curr_dict = nested_dict[k1]
          for k2 in curr_dict:
              new_dict = {'col1': k1, 'col2': k2}
              new_dict.update({'col%d'%(i+3): curr_dict[k2][i] for i in range(len(curr_dict[k2]))})
              new_list.append(new_dict)
      
      # create a DataFrame from new list
      df = pd.DataFrame(new_list)
      

      输出:

            col1   col2  col3  col4    col5   col6
      0  string2  28672    82    23     NaN    NaN
      1  string2  22736    82    93  1102.0  102.0
      2  string2  19423    64    23     NaN    NaN
      3  string3  19424    65    24     NaN    NaN
      4  string3  28673    83    24     NaN    NaN
      5  string3  22737    83    94  1103.0  103.0
      6  string1     65     1     1     NaN    NaN
      7  string1     67   682    12     NaN    NaN
      8  string1     69  1231   232     NaN    NaN
      

      假设输入将总是包含足够的数据来创建col1col2

      我遍历nested_dict。假设nested_dict的每个元素也是一个字典。我们也遍历该字典(curr_dict)。键 k1k2 用于填充 col1col2。对于其余的键,我们遍历列表内容并为每个元素添加一列。

      【讨论】:

        猜你喜欢
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 2020-02-18
        • 2019-06-27
        • 2018-10-26
        • 1970-01-01
        • 1970-01-01
        • 2019-05-27
        相关资源
        最近更新 更多