我希望能够使用具有多索引列结构的 DataFrame 中的顶级列索引器一次设置多个列。
我正在使用 DataFrame 执行数据处理,该 DataFrame 具有许多采用二级多索引结构的列。我这样做是为了可以对相关变量进行分组并轻松访问它们。下面的部分给出了这个 DataFrame 的总体概述:
import pandas as pd
import numpy as np
df = pd.DataFrame(index=range(10), columns = pd.MultiIndex.from_arrays([["Input"]*3+["Output"]*3+["Meta"],[*"XYZ"]*2+["ID"]]))
df["Input"] = np.random.rand(10,3)
df["Output"] = np.random.rand(10,3)
df["Meta"] = ["a"]*4 + ["b"]*6
print(df)
和输出:
Input Output Meta
X Y Z X Y Z ID
0 0.360439 0.604642 0.255683 0.662775 0.627135 0.920299 a
1 0.462851 0.695910 0.705533 0.969508 0.568267 0.878743 a
2 0.926175 0.792516 0.191144 0.194397 0.152643 0.837344 a
3 0.928863 0.385174 0.452903 0.267481 0.924337 0.264785 a
4 0.244422 0.961650 0.557120 0.441052 0.596733 0.676364 b
5 0.462019 0.226703 0.725212 0.526478 0.660846 0.938667 b
6 0.069525 0.658742 0.288887 0.892227 0.907018 0.784265 b
7 0.338952 0.859036 0.854475 0.562198 0.857035 0.984735 b
8 0.560532 0.117619 0.227673 0.048954 0.987209 0.066062 b
9 0.265070 0.960674 0.984968 0.348832 0.757715 0.175176 b
正如您从前面的代码示例中看到的,我使用
df["Input"]
一次设置多个列。一段非常方便的语法,因为它为我提供了更高级别的抽象。如果稍后我向 Input
或 Output
添加另一个维度(例如 Magnitude
),这可能会很方便。我不需要在那里更新我的逻辑。
如果(顶级)列已经定义,则此方法可以正常工作。但是,如果我想使用顶级列索引器添加更多列,我会收到 ValueError。
df["Diff"] = df["Input"] - df["Input"].shift(1)
6 df["Meta"] = ["a"]*4 + ["b"]*6
7
----> 8 df["Diff"] = df["Input"] - df["Input"].shift(1)
9 print(df)
ValueError: Cannot set a DataFrame with multiple columns to the single column Diff
我了解表达式返回一个 DataFrame,并且我了解此语法通常用于仅设置一列。但是,当列已经定义时,此语法有效。此外,表达式生成的数据帧将具有与其关联的
X
、Y
和 Z
列。所以设置子级列索引应该不成问题。知道为什么会出现这个问题吗?或者我只是错过了什么?语法似乎不一致,直观上这应该也可行。
我可以通过使用列表理解语法对 df 进行索引来提出解决方法,如下所示:
df[[("Diff", c) for c in df["Input"].columns]] = df["Input"] - df["Input"].shift(1)
但在我看来,这种语法不必要地冗长,并且容易出现更新错误,特别是与我期望能够使用的直观语法相比。也许这就是像 pandas 这样的数据科学包的混乱本质。
这个怎么样?不太无缝,但更接近您想要的。
diff = df["Input"] - df["Input"].shift(1)
diff.columns = pd.MultiIndex.from_product([["Diff"], diff.columns])
df = pd.concat([df, diff], axis=1)