如何根据基于数据框的两个或多个条件在 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
问题是:如何创建一个新索引,以便在每个具有B2
和B3
条目的A
中,如果B3 < B2
则B4 = 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.IndexSlice
、get_level_values
、boolean 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
值,其中B2
或B3
是nan
。要解决这个问题:
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
【讨论】:
它可以工作,谢谢,但是stack
和unstack
让我失去了我原来的 A 和 B 顺序。在这个例子中,恰好索引是按升序创建的命令。你知道如何维护秩序吗?【参考方案2】:
groupby(level=...)
可以通过根据多索引的A
级别拆分数据帧来提供帮助。从那里,搜索B2
和B3
是否都存在就足够了,如果存在则计算新行。
有必要根据索引进行排序,以便将新行放在正确的位置。代码可能是:
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 数据框中添加新行的主要内容,如果未能解决你的问题,请参考以下文章