【问题标题】:Inserting "missing" multiindex rows into a Pandas Dataframe将“缺失”的多索引行插入到 Pandas 数据框中
【发布时间】:2019-06-24 07:02:09
【问题描述】:

我有一个带有两级多索引的 pandas DataFrame。第二级是数字,应该对第一级索引的每个唯一值进行排序和顺序,但有间隙。如何插入“缺失”行?示例输入:

import pandas as pd
df = pd.DataFrame(list(range(5)),
                  index=pd.MultiIndex.from_tuples([('A',1), ('A',3),
                                                   ('B',2), ('B',3), ('B',6)]),
                  columns='value')
#     value
#A 1      0
#  3      1
#B 2      2
#  3      3
#  6      4

预期输出:

#     value
#A 1      0
#  2    NaN
#  3      1
#B 2      2
#  3      3
#  4    NaN
#  5    NaN
#  6      4

我怀疑我可以使用 resample,但我无法将数字转换为任何类似日期的内容。

【问题讨论】:

  • 通过for循环创建索引,然后重新索引?
  • @Wen-Ben 谢谢!那将是我最后的选择。我讨厌在 pandas 中使用循环。

标签: python pandas multi-index


【解决方案1】:

有志者事竟成。我对此并不感到自豪,但我认为它有效。

试试:

def f(x):
    levels = x.index.remove_unused_levels().levels
    x = x.reindex(pd.MultiIndex.from_product([levels[0], np.arange(levels[1][0], levels[1][-1]+1)]))
    return x

df.groupby(level=0, as_index=False, group_keys=False).apply(f)

输出:

     value
A 1    0.0
  2    NaN
  3    1.0
B 2    2.0
  3    3.0
  4    NaN
  5    NaN
  6    4.0

【讨论】:

    【解决方案2】:

    经过深思熟虑,我自己想出了一个解决方案。从它的糟糕程度来看,我面临的问题并不是一个很典型的问题。

    new_index = d.index.to_frame()\
                    .groupby(0)[1]\
                    .apply(lambda x:
                             pd.Series(1, index=range(x.min(), x.max() + 1))).index
    d.reindex(new_index)
    

    【讨论】:

      【解决方案3】:

      您可以简单地使用以下取决于缺少的索引:

      result.unstack(1).stack(0, dropna=False).fillna(0)
      

      当您取消堆叠时,pandas 会将 df 扩展为具有行和列,在上面的示例中,1 级索引将是列名。然后,再次通过堆叠,您将 df 返回到其原始形式,但是,这一次您需要确保使用 dropna=False,以便 NaN 值将用于缺失索引。最后,使用 .fillna(0) 是可选的,这取决于您要对 NaN 值做什么。

      【讨论】:

      • 这还将创建不在所需数据框中的(B, 1)。它也不会插入 new(B, 4)(B, 5)
      【解决方案4】:

      没有考虑口味,但我认为退回到列表理解会导致代码更具可读性:

      df.reindex(
          pd.MultiIndex.from_tuples([
              (level_0, level_1)
              for level_0 in df.reset_index(0).level_0.unique()
              for level_1 in range(
                  df.reset_index(1).loc[level_0, "level_1"].min(),
                  df.reset_index(1).loc[level_0, "level_1"].max()+1
              )
      ]))
      
      # Output:
      #value
      #A  1   0.0
      #   2   NaN
      #   3   1.0
      #B  2   2.0
      #   3   3.0
      #   4   NaN
      #   5   NaN
      #   6   4.0
      

      虽然这当然比走apply 路线要慢:

      list-comprehension: 2.57 ms ± 19 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      DYZ apply: 1.25 ms ± 8.75 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      Scott's apply: 2.19 ms ± 9.84 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-10
        • 2015-06-12
        • 1970-01-01
        • 1970-01-01
        • 2021-05-11
        • 2013-08-24
        • 2015-09-17
        • 1970-01-01
        相关资源
        最近更新 更多