如何根据基于数据框的两个或多个条件在 MultiIndex 数据框中添加新行

Posted

技术标签:

【中文标题】如何根据基于数据框的两个或多个条件在 MultiIndex 数据框中添加新行【英文标题】:How to add new row in a MultiIndex dataframe based on two or more conditions based on the dataframe 【发布时间】:2019-09-27 08:28:01 【问题描述】:

我正在尝试根据多个条件将新行添加到我的 MultiIndex 数据框中。

以下代码是我如何设置我想要操作的初始数据帧(不是真实的,但足以说明我遇到的问题......):

def mklbl(prefix, n):
    return ["%s%s" % (prefix, i) for i in range(n)]

----


    miindex = pd.MultiIndex.from_product([mklbl('A', 3),
                                           mklbl('B', 4),
                                           ], names=['A','B'])

    micolumns = pd.MultiIndex.from_tuples([('a', 'foo'), ('a', 'bar'),
                                           ('b', 'foo'), ('b', 'bah')],
                                           names=['lvl0', 'lvl1'])


    df = pd.DataFrame(np.random.randint(100, size=len(miindex) * len(micolumns))
                        .reshape((len(miindex), len(micolumns))),
                         index=miindex,
                         columns=micolumns).sort_index().sort_index(axis=1)                         

    df = df.drop([('A2','B2'),('A2','B3')])

这里是起始df

lvl0    a       b    
lvl1  bar foo bah foo
A  B                 
A0 B0  38  16   1  31
   B1  49  12  97  73
   B2  76  26  17  34
   B3   8  55   6  80
A1 B0  40  94  57   0
   B1  21  23  45  78
   B2  36  31  89  18
   B3  46  31  57  94
A2 B0  46  98  62  97
   B1  89  26  93  95

问题是:如何创建一个新索引,以便在每个具有B2B3 条目的A 中,如果B3 < B2B4 = B3 / B2 否则B4 = 0

我希望结果会是这样的:


lvl0    a       b    
lvl1  bar foo bah foo
A  B                 
A0 B0  38       16   1          31
   B1  49       12  97          73
   B2  76       26  17          34
   B3   8       55   6          80
   B4  0.105     0  0.352        0
A1 B0  40       94  57           0
   B1  21       23  45          78
   B2  36       31  89          18
   B3  46       31  57          94
   B4   0        0  0.640        0
A2 B0  46       98  62          97
   B1  89       26  93          95

这对我来说很难做到。我一整天都尝试使用pd.IndexSliceget_level_valuesboolean indexer 自己做这件事,但无济于事。真是令人沮丧。

感谢您提供的任何帮助。

【问题讨论】:

什么是mklbl函数? 我在上面的帖子中添加了mklbl 函数。很抱歉错过了这个。 【参考方案1】:

一种方法可能是转换数据,以便您可以对列而不是行执行这些操作:

df = df.T.stack('A')

那么你可以使用numpy.where来满足你的条件:

df['B4'] = np.where(df.B3 < df.B2, df.B3 / df.B2, 0)

上一行将留下0 值,其中B2B3nan。要解决这个问题:

df['B4'] = np.where(df.B3.isnull() | df.B2.isnull(), np.nan, df.B4)

现在你可以变回来了:

df = df.stack('B').unstack(['lvl0', 'lvl1'])

一组:

df = df.T.stack('A')
df['B4'] = np.where(df.B3 < df.B2, df.B3 / df.B2, 0)
df['B4'] = np.where(df.B3.isnull() | df.B2.isnull(), np.nan, df.B4)
df = df.stack('B').unstack(['lvl0', 'lvl1'])

使用以下数据框:

lvl0    a       b
lvl1  bar foo bah foo
A  B
A0 B0  59  41  50  82
   B1  77   7  15  77
   B2  91  57  44  98
   B3  74  54  52  88
A1 B0  35  47  68   4
   B1  93  93  20  93
   B2  68  76  67  29
   B3   9  50  25   3
A2 B0   7  59  69  74
   B1  19  34  40  32

这会产生:

lvl0           a                     b
lvl1         bar        foo        bah        foo
A  B
A0 B0  59.000000  41.000000  50.000000  82.000000
   B1  77.000000   7.000000  15.000000  77.000000
   B2  91.000000  57.000000  44.000000  98.000000
   B3  74.000000  54.000000  52.000000  88.000000
   B4   0.813187   0.947368   0.000000   0.897959
A1 B0  35.000000  47.000000  68.000000   4.000000
   B1  93.000000  93.000000  20.000000  93.000000
   B2  68.000000  76.000000  67.000000  29.000000
   B3   9.000000  50.000000  25.000000   3.000000
   B4   0.132353   0.657895   0.373134   0.103448
A2 B0   7.000000  59.000000  69.000000  74.000000
   B1  19.000000  34.000000  40.000000  32.000000

【讨论】:

它可以工作,谢谢,但是stackunstack 让我失去了我原来的 A 和 B 顺序。在这个例子中,恰好索引是按升序创建的命令。你知道如何维护秩序吗?【参考方案2】:

groupby(level=...) 可以通过根据多索引的A 级别拆分数据帧来提供帮助。从那里,搜索B2B3 是否都存在就足够了,如果存在则计算新行。

有必要根据索引进行排序,以便将新行放在正确的位置。代码可能是:

for A, g in df.index.to_frame().groupby(level='A'):
    if ((A, 'B2') in g.index) and ((A, 'B3') in g.index):
        df.loc[(A, 'B4'), :] = np.where(
            df.loc[(A, 'B3')]<df.loc[(A, 'B2')],
            df.loc[(A, 'B3')] / df.loc[(A, 'B2')],
            0)

df.sort_index(inplace=True)

【讨论】:

以上是关于如何根据基于数据框的两个或多个条件在 MultiIndex 数据框中添加新行的主要内容,如果未能解决你的问题,请参考以下文章

如何在熊猫数据框的行之间应用多个条件创建目标数据框

使用 np.where 基于多列的 pandas 多个条件

如何根据python中的多个条件对excel文件进​​行重复数据删除?

基于日期时间列名称的数据框的条件平均值

根据条件保留熊猫数据框的上 n 行

根据多个列的条件连接两个表