我需要应用一个函数,该函数将多索引列的子列(又名系列)作为参数。我想出了一个可行的解决方案,但我很好奇是否有一种更Pythonic/正确的 pandas 方法来做到这一点。
假设我们有一个函数,它接受两个系列作为参数并对这些系列执行一些用户定义的操作并返回单个系列。
import pandas as pd
def user_defined_function(series1, series2):
return 12 * (series1 * series2 / 3)
让我们创建一个包含多索引列的数据框。
data = [[1, 2, 3, 4],
[5, 6, 7, 8],
[10, 11, 12, 13],
[14, 15, 16, 17]]
columns = (('A', 'sub_col_1'),
('A', 'sub_col_2'),
('B', 'sub_col_1'),
('B', 'sub_col_2'))
df = pd.DataFrame(data, columns=columns)
print(df)
A B
sub_col_1 sub_col_2 sub_col_1 sub_col_2
0 1 2 3 4
1 5 6 7 8
2 10 11 12 13
3 14 15 16 17
我想将我的 user_define_function()
应用于 A 和 B 的子列。
现在,如果您尝试使用传统方式应用,pandas 将单独遍历每一列,将单个系列返回给函数。所以你不能只这样做。
df.apply(lambda x: user_defined_function(x['sub_col_1'], x['sub_col_2']))
您最终会收到一个关键错误,因为 pandas 传递的是一系列而不是通常索引的“子数据帧”。
这就是我想出的解决方案。
level1_labels = set(df.columns.get_level_values(0))
processed_df = pd.DataFrame()
for label in level1_labels:
data_to_apply_function_to = df[label]
processed_series = user_defined_function(data_to_apply_function_to['sub_col_1'],
data_to_apply_function_to['sub_col_2'])
processed_df[label] = processed_series
print(processed_df)
A B
0 8.0 48.0
1 120.0 224.0
2 440.0 624.0
3 840.0 1088.0
这会返回我想要的结果。然而,我很好奇是否有一种更干净、更Pythonic、正确的方法来做到这一点。
最佳答案
您可以在列轴上groupby
。您的函数需要一个Series
,因此如果我们想按标签进行选择,我们需要squeeze
。
(df.groupby(level=0, axis=1)
.apply(lambda gp: user_defined_function(gp.xs('sub_col_1', level=1, axis=1).squeeze(),
gp.xs('sub_col_2', level=1, axis=1).squeeze()))
)
# A B
#0 8.0 48.0
#1 120.0 224.0
#2 440.0 624.0
#3 840.0 1088.0
更容易出错,不过如果你知道所有组都有两个系列处于相同位置就可以了
(df.groupby(level=0, axis=1)
.apply(lambda gp: user_defined_function(gp.iloc[:, 0], gp.iloc[:, 1]))
)
关于python - Pandas 将函数应用于以列(系列)作为参数的多索引列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61396850/