在 pandas DataFrame 中删除列级别的方法链接解决方案
Method chaining solution to drop column level in pandas DataFrame
在重塑和查询 pandas DataFrames
中的数据时,我使用了很多方法链接。有时会为索引(行)和列创建额外的和不必要的级别。如果是这样,例如在索引(行轴)上,这很容易通过使用 DataFrame.reset_index()
:
来解决
df.query('some query')
.apply(cool_func)
.reset_index('unwanted_index_level',drop=True) # <====
.apply(another_cool_func)
reset_index
函数允许继续链式方法并继续使用 DataFrame
。
然而,我从未找到 column_axis 的等效解决方案。到底有没有?
您可以只 stack
列(将其移动到索引)并使用 drop=True 调用 reset_index
,或者您可以使用 [=15] 编写 reset_columns()
方法=] 一个作为起点(参见 frame.py#L2940)
df.query('some query')
.apply(cool_func)
.stack(level='unwanted_col_level_name')
.reset_index('unwanted_col_level_name',drop=True)
.apply(another_cool_func)
备选方案:猴子补丁解决方案
def drop_column_levels(self, level=None, inplace=False):
"""
For DataFrame with multi-level columns, drops one or more levels.
For a standard index, or if dropping all levels of the MultiIndex, will revert
back to using a classic RangeIndexer for column names.
Parameters
----------
level : int, str, tuple, or list, default None
Only remove the given levels from the index. Removes all levels by
default
inplace : boolean, default False
Modify the DataFrame in place (do not create a new object)
Returns
-------
resetted : DataFrame
"""
if inplace:
new_obj = self
else:
new_obj = self.copy()
new_columns = pd.core.common._default_index(len(new_obj.columns))
if isinstance(self.index, pd.MultiIndex):
if level is not None:
if not isinstance(level, (tuple, list)):
level = [level]
level = [self.index._get_level_number(lev) for lev in level]
if len(level) < len(self.columns.levels):
new_columns = self.columns.droplevel(level)
new_obj.columns = new_columns
if not inplace:
return new_obj
# Monkey patch the DataFrame class
pd.DataFrame.drop_column_levels = drop_column_levels
允许继续点链的一个选项是为 pd.DataFrame
class 定义一种新方法,以降低列索引级别。这称为猴子修补,它会降低代码的可移植性。
def reset_column_index(self, inplace=False):
if inplace:
self.columns = ['_'.join(tup) for tup in self.columns]
else:
c = self.copy()
c.columns = ['_'.join(tup) for tup in c.columns]
return c
pd.DataFrame.reset_column_index = reset_column_index
df.query('some query')
.apply(cool_func)
.reset_column_index()
.apply(another_cool_func)
使用此方法会将多索引列展平为单个索引,并用下划线合并名称。
# foo bar
# A B A B
# 0 17 2 0 3
# 1 4 12 40 11
变成
# foo_A foo_B bar_A bar_B
# 0 17 2 0 3
# 1 4 12 40 11
我自己找到了另一个解决方案,它使用 DataFrame
的 .T
字段,相当于 DataFrame.transpose()
.
df.query('some query')
.apply(cool_func)
.T.reset_index('unwanted_col_level_name',drop=True).T
.apply(another_cool_func)
在重塑和查询 pandas DataFrames
中的数据时,我使用了很多方法链接。有时会为索引(行)和列创建额外的和不必要的级别。如果是这样,例如在索引(行轴)上,这很容易通过使用 DataFrame.reset_index()
:
df.query('some query')
.apply(cool_func)
.reset_index('unwanted_index_level',drop=True) # <====
.apply(another_cool_func)
reset_index
函数允许继续链式方法并继续使用 DataFrame
。
然而,我从未找到 column_axis 的等效解决方案。到底有没有?
您可以只 stack
列(将其移动到索引)并使用 drop=True 调用 reset_index
,或者您可以使用 [=15] 编写 reset_columns()
方法=] 一个作为起点(参见 frame.py#L2940)
df.query('some query')
.apply(cool_func)
.stack(level='unwanted_col_level_name')
.reset_index('unwanted_col_level_name',drop=True)
.apply(another_cool_func)
备选方案:猴子补丁解决方案
def drop_column_levels(self, level=None, inplace=False):
"""
For DataFrame with multi-level columns, drops one or more levels.
For a standard index, or if dropping all levels of the MultiIndex, will revert
back to using a classic RangeIndexer for column names.
Parameters
----------
level : int, str, tuple, or list, default None
Only remove the given levels from the index. Removes all levels by
default
inplace : boolean, default False
Modify the DataFrame in place (do not create a new object)
Returns
-------
resetted : DataFrame
"""
if inplace:
new_obj = self
else:
new_obj = self.copy()
new_columns = pd.core.common._default_index(len(new_obj.columns))
if isinstance(self.index, pd.MultiIndex):
if level is not None:
if not isinstance(level, (tuple, list)):
level = [level]
level = [self.index._get_level_number(lev) for lev in level]
if len(level) < len(self.columns.levels):
new_columns = self.columns.droplevel(level)
new_obj.columns = new_columns
if not inplace:
return new_obj
# Monkey patch the DataFrame class
pd.DataFrame.drop_column_levels = drop_column_levels
允许继续点链的一个选项是为 pd.DataFrame
class 定义一种新方法,以降低列索引级别。这称为猴子修补,它会降低代码的可移植性。
def reset_column_index(self, inplace=False):
if inplace:
self.columns = ['_'.join(tup) for tup in self.columns]
else:
c = self.copy()
c.columns = ['_'.join(tup) for tup in c.columns]
return c
pd.DataFrame.reset_column_index = reset_column_index
df.query('some query')
.apply(cool_func)
.reset_column_index()
.apply(another_cool_func)
使用此方法会将多索引列展平为单个索引,并用下划线合并名称。
# foo bar
# A B A B
# 0 17 2 0 3
# 1 4 12 40 11
变成
# foo_A foo_B bar_A bar_B
# 0 17 2 0 3
# 1 4 12 40 11
我自己找到了另一个解决方案,它使用 DataFrame
的 .T
字段,相当于 DataFrame.transpose()
.
df.query('some query')
.apply(cool_func)
.T.reset_index('unwanted_col_level_name',drop=True).T
.apply(another_cool_func)