在 Pandas DataFrame 中删除列级别的方法链解决方案

dme*_*meu 3 python method-chaining multi-index pandas

在重塑和查询我在 pandas 中的数据时,我使用了很多方法链DataFrames。有时会为 in 索引(行)和列创建额外的和不必要的级别。如果是这样,例如在索引(行轴)上,可以使用以下方法轻松解决DataFrame.reset_index()

df.query('some query')
   .apply(cool_func)
   .reset_index('unwanted_index_level',drop=True) # <====
   .apply(another_cool_func)
Run Code Online (Sandbox Code Playgroud)

reset_index函数允许继续链方法并继续使用DataFrame.

尽管如此,我从未找到 column_axis 的等效解决方案。有吗?

Jul*_*rec 6

您可以仅stack列(将其移动到索引)并reset_index使用 drop=True调用,或者您可以reset_columns()使用该列reset_index()作为起点编写一个方法(参见 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)
Run Code Online (Sandbox Code Playgroud)

替代方案:Monkey 补丁解决方案

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
Run Code Online (Sandbox Code Playgroud)