假设我们有一个DataFrame
,其中包含多个列标题。
level_0 A B C
level_1 P P P
level_2 x y x y x y
0 -1.027155 0.667489 0.314387 -0.428607 1.277167 -1.328771
1 0.223407 -1.713410 0.480903 -3.517518 -1.412756 0.718804
我想从命名级别中选择一列列。
required_columns = ['A', 'B']
required_level = 'level_0'
方法1 :(不赞成使用df.loc)
print df.select(lambda x: x[0] in required_columns, axis=1)
这个问题是我必须用0指定级别。如果我使用级别的名称,则会失败。
方法2:
print df.xs('A', level=required_level, axis=1)
这个问题是我只能指定一个值。如果我使用['A','B'],它就会失败。
方法3:
print df.ix[:, df.columns.get_level_values(required_level).isin(required_columns)]
这样可行,但不像前两种方法那样简洁! :)
问题:
如何让方法1或2工作?或者,有更多的pythonic方式吗?
MWE:
import pandas as pd
import numpy as np
header = pd.MultiIndex.from_product([['A', 'B', 'C'],
['P'],
['x', 'y']],
names=['level_0',
'level_1',
'level_2'])
df = pd.DataFrame(
np.random.randn(2, 6),
columns=header
)
required_columns = ['A', 'B']
required_level = 'level_0'
print df
print df.select(lambda x: x[0] in required_columns, axis=1)
print df.xs('A', level=required_level, axis=1)
print df.ix[:, df.columns.get_level_values(required_level).isin(required_columns)]
相关问题:
答案 0 :(得分:6)
您可以使用reindex
:
df.reindex(columns=required_columns, level=required_level)
结果输出:
level_0 A B
level_1 P P
level_2 x y x y
0 -1.265558 0.681565 -0.553084 -1.340652
1 1.705043 -0.512333 -0.785326 0.968391
答案 1 :(得分:3)
您是否考虑过使用IndexSlice
?它通常要求首先对列进行排序(在原始数据帧中,它们已经排序)。
df.sort_index(axis=1, inplace=True)
>>> df.loc[:, pd.IndexSlice[required_columns, :, :]]
# Output:
# level_0 A B
# level_1 P P
# level_2 x y x y
# 0 0.079368 -1.083421 0.129979 -0.558004
# 1 -0.157843 -1.176632 -0.219833 0.935364
<强>更新强>
您选择的方法实际上取决于您首先选择数据的原因以及是否需要通过选择修改原始数据。
首先,为了使示例更具挑战性,让我们使用MultiIndex数据帧,该数据帧在不同级别具有相同的值且未排序。
required_columns = ['A', 'B'] # Per original question.
required_level = 'level_0' # Per original question.
np.random.seed(0)
idx = pd.MultiIndex.from_product([list('BAC'), list('AB')], names=['level_0', 'level_1'])
df = pd.DataFrame(np.random.randn(2, len(idx)), columns=idx)
>>> df
# Output:
# level_0 B A C
# level_1 A B A B A B
# 0 1.764052 0.400157 0.978738 2.240893 1.867558 -0.977278
# 1 0.950088 -0.151357 -0.103219 0.410599 0.144044 1.454274
返回数据副本
如果您只需要直接查看数据或在管道中进行后续计算,那么@root提到的reindex
方法和文档中讨论的here是一个不错的选择。< / p>
df2 = df.reindex(columns=required_columns, level=required_level)
>>> df2
# Output:
# level_0 A B
# level_1 A B A B
# 0 0.978738 2.240893 1.764052 0.400157
# 1 -0.103219 0.410599 0.950088 -0.151357
然而,如果您尝试修改此数据框,则更改不会反映在您的原始数据中。
df2.iloc[0, 0] = np.nan
>>> df # Check values in original dataframe. None are `NaN`.
# Output:
# level_0 B A C
# level_1 A B A B A B
# 0 1.764052 0.400157 0.978738 2.240893 1.867558 -0.977278
# 1 0.950088 -0.151357 -0.103219 0.410599 0.144044 1.454274
修改数据
另一种方法是使用loc
的布尔索引。您可以使用条件列表推导来选择所需的列以及get_level_values
:
cols = [col in required_columns for col in df.columns.get_level_values(required_level)]
>>> df.loc[:, cols]
# Output:
# level_0 B A
# level_1 A B A B
# 0 1.764052 0.400157 0.978738 2.240893
# 1 0.950088 -0.151357 -0.103219 0.410599
如果您要对索引而不是列进行切片,那么显然需要在上面的代码段中将df.columns.get_level_values
更改为df.index.get_level_values
。
您还可以使用loc
修改原始数据:
df2 = df.copy()
df2.loc[:, cols] = 1
>>> df2
# Output:
# level_0 B A C
# level_1 A B A B A B
# 0 1 1 1 1 1.867558 -0.977278
# 1 1 1 1 1 0.144044 1.454274
<强>结论强>
虽然select
是返回多索引数据视图的好选项,但使用loc
进行布尔索引可以查看或修改数据。
我将使用上述loc
方法,而不是方法1 或方法2 。
截至pandas 0.20.0,已弃用ix
方法。我不建议方法3 。