[英]How can I insert into a specific location of a MultiIndex DataFrame?
假设我有一个 pandas DataFrame 在结构上看起来类似于以下内容。 但是在实践中它可能会大得多,并且 1 级索引的数量以及 2 级索引(每个 1 级索引)的数量会有所不同,因此解决方案不应对此做出假设:
index = pandas.MultiIndex.from_tuples([
("a", "s"),
("a", "u"),
("a", "v"),
("b", "s"),
("b", "u")])
result = pandas.DataFrame([
[1, 2],
[3, 4],
[5, 6],
[7, 8],
[9, 10]], index=index, columns=["x", "y"])
看起来像这样:
x y
a s 1 2
u 3 4
v 5 6
b s 7 8
u 9 10
现在假设我想为每个“a”和“b”级别创建一个“总计”行。 因此,鉴于以上作为输入,我希望我的代码产生如下内容:
x y
a s 1 2
u 3 4
v 5 6
t 9 12
b s 7 8
u 9 10
b t 16 18
这是我到目前为止的代码:
# Calculate totals
for level, _ in result.groupby(level=0):
# work out the global total for that desk:
x_sum = result.loc[level]["x"].sum()
y_sum = result.loc[level]["y"].sum()
result = result.append(pandas.DataFrame([[x_sum, y_sum]], columns=result.columns, index=pandas.MultiIndex.from_tuples([(level, "t")])))
但这会导致“总计”列被附加到末尾:
x y
a s 1 2
u 3 4
v 5 6
b s 7 8
u 9 10
a t 9 12
b t 16 18
使用result.sort_index()
进行排序也不符合我的要求:
x y
a s 1 2
t 9 12
u 3 4
v 5 6
b s 7 8
t 16 18
u 9 10
我究竟做错了什么?
这真的很烦人,但sorted Multiindex
原因是性能更好。 此外,如果没有排序MultiIndex
可能是一些UnsortedIndexError,如果需要由MultiIndex
选择。
但如果确实需要更改标签的位置,可以使用reindex
。
df = result.groupby(level=0).sum()
df.index = [df.index, ['t'] * len(df.index)]
df1 = pd.concat([result, df]).sort_index().reindex(['s','u','t'], level=1)
df1 = pd.concat([result, df]).sort_index()
print (df1)
x y
a s 1 2
t 4 6
u 3 4
b s 5 6
t 12 14
u 7 8
df1 = df1.reindex(['s','u','t'], level=1)
print (df1)
x y
a s 1 2
u 3 4
t 4 6
b s 5 6
u 7 8
t 12 14
更动态的解决方案
print (result.index.get_level_values(1).unique().tolist())
['s', 'u']
df1 = df1.reindex(result.index.get_level_values(1).unique().tolist() + ['t'], level=1)
print (df1)
x y
a s 1 2
u 3 4
t 4 6
b s 5 6
u 7 8
t 12 14
使用GroupBy.apply
在自定义函数中进行放大设置的另一个解决方案:
def f(x):
x.loc[(x.name, 't'),:] = x.sum()
return x
df = result.groupby(level=0, group_keys=False).apply(f)
print (df)
x y
a s 1.0 2.0
u 3.0 4.0
t 4.0 6.0
b s 5.0 6.0
u 7.0 8.0
t 12.0 14.0
result.reindex(pandas.MultiIndex.from_tuples([
("a", "s"),
("a", "u"),
("a", "t"),
("b", "s"),
("b", "u"),
("b", "t")
]))
给我
x y
a s 1 2
u 3 4
t 4 6
b s 5 6
u 7 8
t 12 14
更好的解决方案是将级别转换为分类类型,以便 MultiIndex 将是is_monotonic_increasing
。 这保留了顺序,并且 MultiIndex 的性能会更好,因为它已排序。
输入:
x y
a s 1 2
u 3 4
v 5 6
b s 7 8
u 9 10
a t 9 12
b t 16 18
将级别转换为分类以保留顺序。
result.index = result.index.set_levels(pd.CategoricalIndex(result.index.levels[1], categories=['s', 'u', 'v', 't'], ordered=True), level=1)
result.sort_index()
Output:
x y
a s 1 2
u 3 4
v 5 6
t 9 12
b s 7 8
u 9 10
t 16 18
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.